diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp index ce80a05b9b53d6fe7390286a4dec9bf3b7174ad1..3befc1ef002de272d24932a7998af410d0a5bb40 100644 --- a/Geo/CellComplex.cpp +++ b/Geo/CellComplex.cpp @@ -7,8 +7,6 @@ #include "CellComplex.h" -#if defined(HAVE_KBIPACK) - CellComplex::CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> subdomain ){ _domain = domain; @@ -65,6 +63,10 @@ void CellComplex::insertCells(bool subdomain){ } +void CellComplex::insertCell(Cell* cell){ + _cells[cell->getDim()].insert(cell); +} + int Simplex::kappa(Cell* tau) const{ for(int i=0; i < tau->getNumVertices(); i++){ if( !(this->hasVertex(tau->getVertex(i))) ) return 0; @@ -184,9 +186,9 @@ std::vector< std::set<Cell*, Less_Cell>::iterator > CellComplex::cbdIt(Cell* tau } -void CellComplex::removeCell(Cell* cell){ +void CellComplex::removeCell(Cell* cell, bool deleteCell){ _cells[cell->getDim()].erase(cell); - delete cell; + if(deleteCell) delete cell; } void CellComplex::removeCellIt(std::set<Cell*, Less_Cell>::iterator cell){ Cell* c = *cell; @@ -197,7 +199,7 @@ void CellComplex::removeCellIt(std::set<Cell*, Less_Cell>::iterator cell){ void CellComplex::removeCellQset(Cell*& cell, std::set<Cell*, Less_Cell>& Qset){ Qset.erase(cell); - delete cell; + delete cell; } void CellComplex::enqueueCellsIt(std::vector< std::set<Cell*, Less_Cell>::iterator >& cells, @@ -272,7 +274,7 @@ int CellComplex::coreductionMrozek(Cell* generator){ } -int CellComplex::coreduction(int dim){ +int CellComplex::coreduction(int dim, bool deleteCells){ if(dim < 0 || dim > 2) return 0; @@ -287,8 +289,8 @@ int CellComplex::coreduction(int dim){ bd_c = bd(cell); if(bd_c.size() == 1 && inSameDomain(cell, bd_c.at(0)) ){ - removeCell(cell); - removeCell(bd_c.at(0)); + removeCell(cell, deleteCells); + removeCell(bd_c.at(0), deleteCells); count++; coreduced = true; } @@ -300,8 +302,39 @@ int CellComplex::coreduction(int dim){ } +int CellComplex::coreduction(int dim, std::set<Cell*, Less_Cell>& removedCells){ + + if(dim < 0 || dim > 2) return 0; + + std::vector<Cell*> bd_c; + int count = 0; + + bool coreduced = true; + while (coreduced){ + coreduced = false; + for(citer cit = firstCell(dim+1); cit != lastCell(dim+1); cit++){ + Cell* cell = *cit; + + bd_c = bd(cell); + if(bd_c.size() == 1 && inSameDomain(cell, bd_c.at(0)) ){ + removedCells.insert(cell); + removedCells.insert(bd_c.at(0)); + removeCell(cell, false); + removeCell(bd_c.at(0), false); + count++; + coreduced = true; + } + + } + } + + return count; + +} -int CellComplex::reduction(int dim){ + + +int CellComplex::reduction(int dim, bool deleteCells){ if(dim < 1 || dim > 3) return 0; std::vector<Cell*> cbd_c; @@ -314,8 +347,8 @@ int CellComplex::reduction(int dim){ Cell* cell = *cit; cbd_c = cbd(cell); if(cbd_c.size() == 1 && inSameDomain(cell, cbd_c.at(0)) ){ - removeCell(cell); - removeCell(cbd_c.at(0)); + removeCell(cell, deleteCells); + removeCell(cbd_c.at(0), deleteCells); count++; reduced = true; } @@ -334,36 +367,79 @@ void CellComplex::reduceComplex(){ printf("Cell complex after reduction: %d volumes, %d faces, %d edges and %d vertices.\n", getSize(3), getSize(2), getSize(1), getSize(0)); } + +void CellComplex::coreduceComplex(int generatorDim, std::set<Cell*, Less_Cell>& removedCells){ + + std::set<Cell*, Less_Cell> generatorCells[4]; + + printf("Cell complex before coreduction: %d volumes, %d faces, %d edges and %d vertices.\n", + getSize(3), getSize(2), getSize(1), getSize(0)); + + int i = generatorDim; + while (getSize(i) != 0){ + citer cit = firstCell(i); + Cell* cell = *cit; + while(!cell->inSubdomain() && cit != lastCell(i)){ + cell = *cit; + cit++; + } + generatorCells[i].insert(cell); + removedCells.insert(cell); + removeCell(cell, false); + coreduction(0, removedCells); + coreduction(1, removedCells); + coreduction(2, removedCells); + } + + + for(citer cit = generatorCells[i].begin(); cit != generatorCells[i].end(); cit++){ + Cell* cell = *cit; + if(!cell->inSubdomain()) _cells[i].insert(cell); + if(!cell->inSubdomain()) removedCells.insert(cell); + } + printf("Cell complex after coreduction: %d volumes, %d faces, %d edges and %d vertices.\n", + getSize(3), getSize(2), getSize(1), getSize(0)); + + return; + +} void CellComplex::coreduceComplex(){ - std::set<Cell*, Less_Cell> removedCells[4]; + std::set<Cell*, Less_Cell> generatorCells[4]; printf("Cell complex before coreduction: %d volumes, %d faces, %d edges and %d vertices.\n", getSize(3), getSize(2), getSize(1), getSize(0)); - for(int i = 0; i < 3; i++){ + for(int i = 0; i < 4; i++){ while (getSize(i) != 0){ citer cit = firstCell(i); Cell* cell = *cit; - removedCells[i].insert(cell); - _cells[i].erase(cell); - //removeCell(cell); - //complex.coreductionMrozek(kaka); + while(!cell->inSubdomain() && cit != lastCell(i)){ + cell = *cit; + cit++; + } + generatorCells[i].insert(cell); + removeCell(cell, false); coreduction(0); coreduction(1); coreduction(2); } } - for(int i = 0; i < 3; i++){ - for(citer cit = removedCells[i].begin(); cit != removedCells[i].end(); cit++){ + for(int i = 0; i < 4; i++){ + for(citer cit = generatorCells[i].begin(); cit != generatorCells[i].end(); cit++){ Cell* cell = *cit; - _cells[i].insert(cell); + if(!cell->inSubdomain()) _cells[i].insert(cell); } } printf("Cell complex after coreduction: %d volumes, %d faces, %d edges and %d vertices.\n", getSize(3), getSize(2), getSize(1), getSize(0)); + + return; } + +#if defined(HAVE_KBIPACK) + std::vector<gmp_matrix*> CellComplex::constructHMatrices(){ // h_dim: C_dim -> C_(dim-1) @@ -418,7 +494,7 @@ std::vector<gmp_matrix*> CellComplex::constructHMatrices(){ } return HMatrix; } - +#endif void CellComplex::getDomainVertices(std::set<MVertex*, Less_MVertex>& domainVertices, bool subdomain){ @@ -541,6 +617,8 @@ void CellComplex::printComplex(int dim, bool subcomplex){ } } +#if defined(HAVE_KBIPACK) + void ChainComplex::KerCod(int dim){ if(dim < 1 || dim > 3 || _HMatrix[dim] == NULL) return; @@ -580,11 +658,16 @@ void ChainComplex::KerCod(int dim){ return; } -/* -//j:B->Z + +//j:B_(k+1)->Z_k void ChainComplex::Inclusion(int dim){ - if(dim < 1 || dim > 3 || _kerH[dim] == NULL || _codH[dim] == NULL) return; + if(dim < 1 || dim > 2 || _kerH[dim] == NULL || _codH[dim+1] == NULL) return; + + gmp_matrix* Zbasis = copy_gmp_matrix(_kerH[dim], 1, 1, + gmp_matrix_rows(_kerH[dim]), gmp_matrix_cols(_kerH[dim])); + gmp_matrix* Bbasis = copy_gmp_matrix(_codH[dim+1], 1, 1, + gmp_matrix_rows(_codH[dim+1]), gmp_matrix_cols(_codH[dim+1])); int rows = gmp_matrix_rows(Zbasis); int cols = gmp_matrix_cols(Zbasis); @@ -594,18 +677,13 @@ void ChainComplex::Inclusion(int dim){ cols = gmp_matrix_cols(Bbasis); if(rows < cols) return; - gmp_matrix* Zbasis = copy_gmp_matrix(_ker[dim], 1, 1, - gmp_matrix_rows(_kerH[dim]), gmp_matrix_cols(_kerH[dim])); - gmp_matrix* Bbasis = copy_gmp_matrix(_cod[dim], 1, 1, - gmp_matrix_rows(_codH[dim]), gmp_matrix_cols(_codH[dim])); - // A*inv(V) = U*S - normalForm = create_gmp_Smith_normal_form(Zbasis, NOT_INVERTED, INVERTED); + gmp_normal_form* normalForm = create_gmp_Smith_normal_form(Zbasis, INVERTED, INVERTED); mpz_t elem; mpz_init(elem); - for(int i = 1; i < cols; i++){ + for(int i = 1; i <= cols; i++){ gmp_matrix_get_elem(elem, i, i, normalForm->canonical); if(mpz_cmp_si(elem,0) == 0){ destroy_gmp_normal_form(normalForm); @@ -615,10 +693,146 @@ void ChainComplex::Inclusion(int dim){ gmp_matrix_left_mult(normalForm->left, Bbasis); + + + gmp_matrix* LB = copy_gmp_matrix(Bbasis, 1, 1, gmp_matrix_cols(Zbasis), gmp_matrix_cols(Bbasis)); + destroy_gmp_matrix(Bbasis); + + rows = gmp_matrix_rows(LB); + cols = gmp_matrix_cols(LB); + + mpz_t divisor; + mpz_init(divisor); + mpz_t remainder; + mpz_init(remainder); + mpz_t result; + mpz_init(result); + + for(int i = 1; i <= rows; i++){ + gmp_matrix_get_elem(divisor, i, i, normalForm->canonical); + for(int j = 1; j <= cols; j++){ + gmp_matrix_get_elem(elem, i, j, LB); + mpz_cdiv_qr(result, remainder, elem, divisor); + if(mpz_cmp_si(remainder, 0) == 0){ + gmp_matrix_set_elem(result, i, j, LB); + } + else return; + } + } + + gmp_matrix_left_mult(normalForm->right, LB); + + _JMatrix[dim] = LB; + + mpz_clear(elem); + mpz_clear(divisor); + mpz_clear(result); + destroy_gmp_normal_form(normalForm); + + return; + +} +void ChainComplex::Quotient(int dim){ + + if(dim < 1 || dim > 3 || _JMatrix[dim] == NULL) return; + + gmp_matrix* JMatrix = copy_gmp_matrix(_JMatrix[dim], 1, 1, + gmp_matrix_rows(_JMatrix[dim]), gmp_matrix_cols(_JMatrix[dim])); + int rows = gmp_matrix_rows(JMatrix); + int cols = gmp_matrix_cols(JMatrix); + + gmp_normal_form* normalForm = create_gmp_Smith_normal_form(JMatrix, NOT_INVERTED, NOT_INVERTED); + + mpz_t elem; + mpz_init(elem); + for(int i = 1; i <= cols; i++){ + gmp_matrix_get_elem(elem, i, i, normalForm->canonical); + if(mpz_cmp_si(elem,0) == 0){ + destroy_gmp_normal_form(normalForm); + return; + } + if(mpz_cmp_si(elem,1) > 0){ + _torsion[dim].push_back(mpz_get_si(elem)); + } + } + + int rank = cols - _torsion[dim].size(); + if(rows - rank > 0){ + gmp_matrix* Hbasis = copy_gmp_matrix(normalForm->left, 1, rank+1, rows, rows); + _QMatrix[dim] = Hbasis; + } + + mpz_clear(elem); + destroy_gmp_normal_form(normalForm); + return; +} + +void ChainComplex::computeHomology(){ + + for(int i=0; i < 4; i++){ + + KerCod(i+1); + + // 1) no edges, but zero cells + if(i == 0 && gmp_matrix_cols(getHMatrix(0)) > 0 && getHMatrix(1) == NULL) { + _Hbasis[i] = create_gmp_matrix_identity(gmp_matrix_cols(getHMatrix(0))); + } + + // 2) this dimension is empty + else if(getHMatrix(i) == NULL && getHMatrix(i+1) == NULL){ + _Hbasis[i] = NULL; + } + // 3) No higher dimension cells -> none of the cycles are boundaries + else if(getHMatrix(i+1) == NULL){ + _Hbasis[i] = copy_gmp_matrix(getKerHMatrix(i), 1, 1, + gmp_matrix_rows(getKerHMatrix(i)), gmp_matrix_cols(getKerHMatrix(i))); + } + + // 5) General case: + // 1) Find the bases of boundaries B and cycles Z + // 2) find j: B -> Z and + // 3) find quotient Z/j(B) + else { + + // 4) No lower dimension cells -> all chains are cycles + if(getHMatrix(i) == NULL){ + _kerH[i] = create_gmp_matrix_identity(gmp_matrix_rows(getHMatrix(i+1))); + } + + Inclusion(i); + Quotient(i); + + if(getCodHMatrix(i+1) == NULL){ + _Hbasis[i] = getKerHMatrix(i); + } + else if(getJMatrix(i) == NULL || getQMatrix(i) == NULL){ + _Hbasis[i] = NULL; + } + else{ + _Hbasis[i] = copy_gmp_matrix(getKerHMatrix(i), 1, 1, + gmp_matrix_rows(getKerHMatrix(i)), gmp_matrix_cols(getKerHMatrix(i))); + gmp_matrix_right_mult(_Hbasis[i], getQMatrix(i)); + } + } + + destroy_gmp_matrix(_kerH[i]); + destroy_gmp_matrix(_codH[i]); + destroy_gmp_matrix(_JMatrix[i]); + destroy_gmp_matrix(_QMatrix[i]); + + _kerH[i] = NULL; + _codH[i] = NULL; + _JMatrix[i] = NULL; + _QMatrix[i] = NULL; + + } + + + return; } -*/ + void ChainComplex::matrixTest(){ diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h index 5f73d241d72811ffdca7ae9cbbb2907a490bba0b..dbcfc66cf42026a2564130f55f203c45601c8f77 100644 --- a/Geo/CellComplex.h +++ b/Geo/CellComplex.h @@ -28,6 +28,8 @@ extern "C" { #include "gmp_normal_form.h" // perhaps make c++ headers instead? } +#endif + // Abstract class representing a cell of a cell complex. class Cell { @@ -364,9 +366,12 @@ class CellComplex virtual void insertCells(bool subdomain); public: - CellComplex( std::set<Cell*, Less_Cell>* cells ) { - for(int i = 0; i < 4; i++){ - //_cells[i] = cells[i]; + CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> subdomain, std::set<Cell*, Less_Cell> cells ) { + _domain = domain; + _subdomain = subdomain; + for(citer cit = cells.begin(); cit != cells.end(); cit++){ + Cell* cell = *cit; + _cells[cell->getDim()].insert(cell); } } CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> subdomain ); @@ -396,24 +401,32 @@ class CellComplex virtual std::vector< std::set<Cell*, Less_Cell>::iterator > cbdIt(Cell* tau); // remove a cell from this cell complex - virtual void removeCell(Cell* cell); + virtual void removeCell(Cell* cell, bool deleteCell=true); virtual void removeCellIt(std::set<Cell*, Less_Cell>::iterator cell); + virtual void insertCell(Cell* cell); + // check whether two cells both belong to subdomain or if neither one does virtual bool inSameDomain(Cell* c1, Cell* c2) const { return ( (!c1->inSubdomain() && !c2->inSubdomain()) || (c1->inSubdomain() && c2->inSubdomain()) ); } // coreduction of this cell complex // removes corection pairs of cells of dimension dim and dim+1 - virtual int coreduction(int dim); + virtual int coreduction(int dim, bool deleteCells=true); + // stores removed cells + virtual int coreduction(int dim, std::set<Cell*, Less_Cell>& removedCells); // reduction of this cell complex // removes reduction pairs of cell of dimension dim and dim-1 - virtual int reduction(int dim); + virtual int reduction(int dim, bool deleteCells=true); // useful functions for (co)reduction of cell complex virtual void reduceComplex(); virtual void coreduceComplex(); + // stores cells removed after removal of generatos of dimension generatorDim + virtual void coreduceComplex(int generatorDim, std::set<Cell*, Less_Cell>& removedCells); + + // queued coreduction presented in Mrozek's paper // slower, but produces cleaner result virtual int coreductionMrozek(Cell* generator); @@ -429,15 +442,19 @@ class CellComplex // get the boundary operator matrix dim->dim-1 //virtual gmp_matrix* getHMatrix(int dim) { return _HMatrix[dim]; } + +#if defined(HAVE_KBIPACK) // construct boundary operator matrices of this cell complex // used to construct a chain complex virtual std::vector<gmp_matrix*> constructHMatrices(); +#endif }; +#if defined(HAVE_KBIPACK) // A class representing a chain complex of a cell complex. // This should only be constructed for a reduced cell complex because of -// dense matrix reprentations and great computational complexity in its methods. +// dense matrix representations and great computational complexity in its methods. class ChainComplex{ private: // boundary operator matrices for this chain complex @@ -450,7 +467,10 @@ class ChainComplex{ gmp_matrix* _JMatrix[4]; gmp_matrix* _QMatrix[4]; - std::vector<int> _torsion[4]; + std::vector<long int> _torsion[4]; + + // bases for homology groups + gmp_matrix* _Hbasis[4]; public: @@ -463,6 +483,7 @@ class ChainComplex{ _codH[i] = NULL; _JMatrix[i] = NULL; _QMatrix[i] = NULL; + _Hbasis[i] = NULL; } } @@ -473,25 +494,30 @@ class ChainComplex{ _codH[i] = NULL; _JMatrix[i] = NULL; _QMatrix[i] = NULL; + _Hbasis[i] = NULL; } } virtual ~ChainComplex(){} // get the boundary operator matrix dim->dim-1 - virtual gmp_matrix* getHMatrix(int dim) { return _HMatrix[dim]; } - virtual gmp_matrix* getKerHMatrix(int dim) { return _kerH[dim]; } - virtual gmp_matrix* getCodHMatrix(int dim) { return _codH[dim]; } - virtual gmp_matrix* getJMatrix(int dim) { return _JMatrix[dim]; } - virtual gmp_matrix* getQMatrix(int dim) { return _QMatrix[dim]; } + virtual gmp_matrix* getHMatrix(int dim) { if(dim > -1 || dim < 4) return _HMatrix[dim]; else return NULL;} + virtual gmp_matrix* getKerHMatrix(int dim) { if(dim > -1 || dim < 4) return _kerH[dim]; else return NULL;} + virtual gmp_matrix* getCodHMatrix(int dim) { if(dim > -1 || dim < 4) return _codH[dim]; else return NULL;} + virtual gmp_matrix* getJMatrix(int dim) { if(dim > -1 || dim < 4) return _JMatrix[dim]; else return NULL;} + virtual gmp_matrix* getQMatrix(int dim) { if(dim > -1 || dim < 4) return _QMatrix[dim]; else return NULL;} + virtual gmp_matrix* getHbasis(int dim) { if(dim > -1 || dim < 4) return _Hbasis[dim]; else return NULL;} // Compute basis for kernel and codomain of boundary operator matrix of dimension dim (ie. ker(h_dim) and cod(h_dim) ) virtual void KerCod(int dim); // Compute matrix representation J for inclusion relation from dim-cells who are boundary of dim+1-cells // to cycles of dim-cells (ie. j: cod(h_(dim+1)) -> ker(h_dim) ) - virtual void Inclusion(int dim){} + virtual void Inclusion(int dim); // Compute quotient problem for given inclusion relation j to find representatives of homology groups // and possible torsion coeffcients - virtual void Quotient(int dim){} + virtual void Quotient(int dim); + + // Compute bases for the homology groups of this chain complex + virtual void computeHomology(); virtual int printMatrix(gmp_matrix* matrix){ printf("%d rows and %d columns\n", gmp_matrix_rows(matrix), gmp_matrix_cols(matrix)); diff --git a/contrib/kbipack/gmp_matrix.c b/contrib/kbipack/gmp_matrix.c index 2d07724b0804ac8f598a68b0ca9fc37842758892..c6dcb11fac8ecec18015404d31fddd310f20c005 100755 --- a/contrib/kbipack/gmp_matrix.c +++ b/contrib/kbipack/gmp_matrix.c @@ -22,7 +22,7 @@ P.O.Box 692, FIN-33101 Tampere, Finland saku.suuriniemi@tut.fi - $Id: gmp_matrix.c,v 1.2 2009-04-03 11:06:12 matti Exp $ + $Id: gmp_matrix.c,v 1.3 2009-04-14 10:02:22 matti Exp $ */ @@ -281,6 +281,24 @@ gmp_matrix_get_elem(mpz_t elem, size_t row, size_t col, return EXIT_SUCCESS; } +/* (matrix(row, col)) <- elem */ +int +gmp_matrix_set_elem(mpz_t elem, size_t row, size_t col, + const gmp_matrix * m) +{ +#ifdef DEBUG + + if(m == NULL) + { + return EXIT_FAILURE; + } + +#endif + + mpz_set(m -> storage[(col-1)*(m -> rows)+row-1], elem); + return EXIT_SUCCESS; +} + int gmp_matrix_swap_rows(size_t row1, size_t row2, gmp_matrix * m) { diff --git a/contrib/kbipack/gmp_matrix.h b/contrib/kbipack/gmp_matrix.h index 784a87c20609f436bacda294851d6887107914b3..5d0e7c57dc853238729492548f1da24eb634b837 100755 --- a/contrib/kbipack/gmp_matrix.h +++ b/contrib/kbipack/gmp_matrix.h @@ -22,7 +22,7 @@ P.O.Box 692, FIN-33101 Tampere, Finland saku.suuriniemi@tut.fi - $Id: gmp_matrix.h,v 1.2 2009-04-03 11:06:13 matti Exp $ + $Id: gmp_matrix.h,v 1.3 2009-04-14 10:02:22 matti Exp $ */ #ifndef __GMP_MATRIX_H__ @@ -72,6 +72,11 @@ int gmp_matrix_get_elem(mpz_t elem, size_t row, size_t col, const gmp_matrix *); +/* (matrix(row, col)) <- elem */ +int +gmp_matrix_set_elem(mpz_t elem, size_t row, size_t col, + const gmp_matrix *); + int gmp_matrix_swap_rows(size_t row1, size_t row2, gmp_matrix *);