diff --git a/Geo/Cell.cpp b/Geo/Cell.cpp
index f59cc141332e9154eba9df04d172ffa75fbd0eba..c19622eb2463c7641e2ba1f109e612eaac27e6df 100755
--- a/Geo/Cell.cpp
+++ b/Geo/Cell.cpp
@@ -57,8 +57,8 @@ bool Cell::findBoundaryCells(std::vector<Cell*>& bdCells)
       if(type == TYPE_TET) newtype = MSH_TRI_3;
       else if(type == TYPE_HEX) newtype = MSH_QUA_4;
       else if(type == TYPE_PRI) {
-        if(vertices.size() == 3) newtype = MSH_TRI_3;
-        else if(vertices.size() == 4) newtype = MSH_QUA_4;
+	if(vertices.size() == 3) newtype = MSH_TRI_3;
+	else if(vertices.size() == 4) newtype = MSH_QUA_4;
       }
     }
     else if(_dim == 2) newtype = MSH_LIN_2;
@@ -68,7 +68,7 @@ bool Cell::findBoundaryCells(std::vector<Cell*>& bdCells)
       return false;
     }
     MElement* element = factory.create(newtype, vertices, 0, 
-                                       _image->getPartition());
+				       _image->getPartition());
     Cell* cell = new Cell(element);
     bdCells.push_back(cell);
   }
@@ -101,7 +101,7 @@ void Cell::getFacetVertices(const int num, std::vector<MVertex*> &v) const
   return;
 }
 
-int Cell::getFacetOri(Cell* cell) 
+int Cell::findBoundaryCellOrientation(Cell* cell) 
 {
   if(_image == NULL){ 
     printf("ERROR: No image mesh element for cell. \n");
@@ -141,7 +141,7 @@ int Cell::getFacetOri(Cell* cell)
 bool Cell::hasVertex(int vertex) const 
 {
   std::vector<int>::const_iterator it = std::find(_vs.begin(), _vs.end(), 
-                                                  vertex);
+						  vertex);
   if (it != _vs.end()) return true;
   else return false;
 }
@@ -166,7 +166,7 @@ void Cell::restoreCell(){
 }
 
 void Cell::addBoundaryCell(int orientation, Cell* cell, 
-                           bool orig, bool other) 
+			   bool orig, bool other) 
 {
   if(orig) _obd.insert( std::make_pair(cell, orientation ) );
   biter it = _bd.find(cell);
@@ -184,7 +184,7 @@ void Cell::addBoundaryCell(int orientation, Cell* cell,
 }
 
 void Cell::addCoboundaryCell(int orientation, Cell* cell, 
-                             bool orig, bool other) 
+			     bool orig, bool other) 
 {
   if(orig) _ocbd.insert( std::make_pair(cell, orientation ) );
   biter it = _cbd.find(cell);
diff --git a/Geo/Cell.h b/Geo/Cell.h
index 46b516af3b0cafbcdbe3ab70880692b691ea9fd2..0d0dd3e6caf3312c295e3852176ea06a334d8a9f 100644
--- a/Geo/Cell.h
+++ b/Geo/Cell.h
@@ -59,15 +59,17 @@ class Cell
   std::map<Cell*, int, Less_Cell > _obd;
   std::map<Cell*, int, Less_Cell > _ocbd;
   
+  // sorted vertices of this cell (used for ordering of the cells)
+  std::vector<int> _vs;
+
+  
+  
   // the mesh element that is the image of this cell
   MElement* _image;
   // whether to delete the mesh element when done
-  // (created for homology computation only)
+  // (set to true if created for homology computation only)
   bool _delimage;
   
-  // sorted vertices of this cell (used for ordering of the cells)
-  std::vector<int> _vs;
-
   // get vertex 
   MVertex* getVertex(int vertex) const { 
     if(_image == NULL) printf("ERROR: No image mesh element for cell. \n");
@@ -99,10 +101,11 @@ class Cell
   void setDeleteImage(bool delimage) { _delimage = delimage; }
   bool getDeleteImage() const { return _delimage; }
 
-  // find the cells on the boundary of this cell 
+  // find the cells on the boundary of this cell
   bool findBoundaryCells(std::vector<Cell*>& bdCells);
   // get boundary cell orientation
-  int getFacetOri(Cell* cell);
+  int findBoundaryCellOrientation(Cell* cell);
+  
 
   int getDim() const { return _dim; };
   int getIndex() const { return _index; };
@@ -123,6 +126,8 @@ class Cell
   
   // (co)boundary cell iterator
   typedef std::map<Cell*, int, Less_Cell>::iterator biter;
+  // iterators to (first/last (co)boundary cells of this cell
+  // (orig: to original (co)boundary cells of this cell)
   biter firstBoundary(bool orig=false){ 
     return orig ? _obd.begin() : _bd.begin(); }
   biter lastBoundary(bool orig=false){ 
@@ -135,7 +140,7 @@ class Cell
   int getBoundarySize() { return _bd.size(); }
   int getCoboundarySize() { return _cbd.size(); }
    
-  // get the cell boundary
+  // get the (orig: original) cell boundary
   void getBoundary(std::map<Cell*, int, Less_Cell >& boundary, 
 		   bool orig=false){
     orig ? boundary = _obd : boundary =  _bd; }
@@ -143,17 +148,19 @@ class Cell
 		     bool orig=false){
     orig ? coboundary = _ocbd : coboundary = _cbd; }
   
-  // add (co)boundary cell
+  // add (co)boundary cell (orig: as original)
+  // (other: reciprocally also add this cell from the other cell's (co)boundary)
   void addBoundaryCell(int orientation, Cell* cell, 
 		       bool orig, bool other); 
   void addCoboundaryCell(int orientation, Cell* cell, 
 			 bool orig, bool other);
   
-  // remove (co)boundary cell
+  // remove (co)boundary cell 
+  // (other: reciprocally also revove this cell from the other cell's (co)boundary)
   void removeBoundaryCell(Cell* cell, bool other);
   void removeCoboundaryCell(Cell* cell, bool other);
   
-  // true if has given cell on (original) (co)boundary
+  // true if has given cell on (orig: original) (co)boundary
   bool hasBoundary(Cell* cell, bool orig=false);
   bool hasCoboundary(Cell* cell, bool orig=false);
   
@@ -184,7 +191,7 @@ class Cell
     }
     for(int i=0; i < this->getNumSortedVertices();i++){
       if(this->getSortedVertex(i) != c2.getSortedVertex(i)){
-        return false;
+	return false;
       }
     }
     return true;
@@ -212,6 +219,7 @@ class CombinedCell : public Cell{
   int getNum() const { return _num; }
 
   bool operator==(const Cell& c2) const {
+    if(this->isCombined() != c2.isCombined()) return false;
     if(this->getNum() != c2.getNum()) return false;
     else return true;
   }
diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp
index 4a87e357193fd655be500ee0ff0bc6cf78cbac6e..26162fee1f55ddda8c94d3d70f90a764fc4ad5e0 100644
--- a/Geo/CellComplex.cpp
+++ b/Geo/CellComplex.cpp
@@ -10,7 +10,7 @@
 #if defined(HAVE_KBIPACK)
 
 CellComplex::CellComplex( std::vector<MElement*>& domainElements, 
-                          std::vector<MElement*>& subdomainElements)
+			  std::vector<MElement*>& subdomainElements)
 {
   _dim = 0;
   _simplicial = true;
@@ -41,7 +41,7 @@ void CellComplex::panic_exit(){
 }
 
 bool CellComplex::insert_cells(std::vector<MElement*>& elements,
-                               bool subdomain)
+			       bool subdomain)
 {
   // add highest dimensional cells
   for(unsigned int i=0; i < elements.size(); i++){
@@ -49,7 +49,7 @@ bool CellComplex::insert_cells(std::vector<MElement*>& elements,
     
     int type = element->getType();   
     if(_simplicial && !(type == TYPE_PNT || type == TYPE_LIN 
-                     || type == TYPE_TRI || type == TYPE_TET) ){
+		     || type == TYPE_TRI || type == TYPE_TET) ){
       _simplicial = false;
     }
     //FIXME: no getFaceInfo methods for these MElements
@@ -70,19 +70,19 @@ bool CellComplex::insert_cells(std::vector<MElement*>& elements,
       std::vector<Cell*> bdCells;
       if(!cell->findBoundaryCells(bdCells)) return false;
       for(unsigned int i = 0; i < bdCells.size(); i++){
-        Cell* newCell = bdCells.at(i);
-        newCell->setInSubdomain(subdomain);
-        newCell->setDeleteImage(true);
-        std::pair<citer, bool> insertInfo = 
-          _cells[newCell->getDim()].insert(newCell);
-        if(!insertInfo.second){ // the cell was already in the cell complex
-          delete newCell; 
-          newCell = *(insertInfo.first); 
-        }
-        if(!subdomain) {
-          int ori = cell->getFacetOri(newCell);
-          cell->addBoundaryCell( ori, newCell, true, true);
-        }
+	Cell* newCell = bdCells.at(i);
+	newCell->setInSubdomain(subdomain);
+	newCell->setDeleteImage(true);
+	std::pair<citer, bool> insertInfo = 
+	  _cells[newCell->getDim()].insert(newCell);
+	if(!insertInfo.second){ // the cell was already in the cell complex
+	  delete newCell; 
+	  newCell = *(insertInfo.first); 
+	}
+	if(!subdomain) {
+	  int ori = cell->findBoundaryCellOrientation(newCell);
+	  cell->addBoundaryCell( ori, newCell, true, true);
+	}
       }
     }
   }
@@ -138,14 +138,14 @@ void CellComplex::removeCell(Cell* cell, bool other)
 }
 
 void CellComplex::removeCellQset(Cell* cell, 
-                                 std::set<Cell*, Less_Cell>& Qset)
+				 std::set<Cell*, Less_Cell>& Qset)
 {
   Qset.erase(cell);
 }
 
 void CellComplex::enqueueCells(std::map<Cell*, int, Less_Cell>& cells, 
-                               std::queue<Cell*>& Q,
-                               std::set<Cell*, Less_Cell>& Qset)
+			       std::queue<Cell*>& Q,
+			       std::set<Cell*, Less_Cell>& Qset)
 {
   for(std::map<Cell*, int, Less_Cell>::iterator cit = cells.begin();
       cit != cells.end(); cit++){
@@ -185,7 +185,7 @@ int CellComplex::coreduction(Cell* startCell, int omitted)
       enqueueCells(cbd_c, Q, Qset);
       removeCell(bd_s.begin()->first);
       if(bd_s.begin()->first->getDim() == 0 && omitted > 0){
-        _store.at(omitted-1).insert(bd_s.begin()->first);
+	_store.at(omitted-1).insert(bd_s.begin()->first);
       }
       coreductions++;
     }
@@ -212,15 +212,15 @@ int CellComplex::reduction(int dim, int omitted)
     while(cit != lastCell(dim-1)){
       Cell* cell = *cit;
       if( cell->getCoboundarySize() == 1 
-          && inSameDomain(cell, cell->firstCoboundary()->first)){
-        ++cit;
-        if(dim == getDim() && omitted > 0){
-          _store.at(omitted-1).insert(cell->firstCoboundary()->first);    
-        }
-        removeCell(cell->firstCoboundary()->first);
-        removeCell(cell);
-        count++;
-        reduced = true;
+	  && inSameDomain(cell, cell->firstCoboundary()->first)){
+	++cit;
+	if(dim == getDim() && omitted > 0){
+	  _store.at(omitted-1).insert(cell->firstCoboundary()->first);    
+	}
+	removeCell(cell->firstCoboundary()->first);
+	removeCell(cell);
+	count++;
+	reduced = true;
       }
     
       if(getSize(dim) == 0 || getSize(dim-1) == 0) break;
@@ -247,9 +247,9 @@ int CellComplex::coreduction(int dim, int omitted)
       if( cell->getBoundarySize() == 1
           && inSameDomain(cell, cell->firstBoundary()->first)){
         ++cit;
-        if(dim-1 == 0 && omitted > 0){
-          _store.at(omitted-1).insert(cell->firstBoundary()->first);
-        }
+	if(dim-1 == 0 && omitted > 0){
+	  _store.at(omitted-1).insert(cell->firstBoundary()->first);
+	}
         removeCell(cell->firstBoundary()->first);
         removeCell(cell);
         count++;
@@ -266,7 +266,7 @@ int CellComplex::coreduction(int dim, int omitted)
 int CellComplex::reduceComplex(bool omit)
 {  
   printf("Cell Complex: \n %d volumes, %d faces, %d edges and %d vertices. \n",
-         getSize(3), getSize(2), getSize(1), getSize(0));
+	 getSize(3), getSize(2), getSize(1), getSize(0));
 
   int count = 0;
   for(int i = 3; i > 0; i--) count = count + reduction(i);
@@ -301,7 +301,7 @@ int CellComplex::reduceComplex(bool omit)
   combine(1);
   
   printf(" %d volumes, %d faces, %d edges and %d vertices. \n",
-         getSize(3), getSize(2), getSize(1), getSize(0));
+	 getSize(3), getSize(2), getSize(1), getSize(0));
   
   return 0;
 }
@@ -321,7 +321,7 @@ void CellComplex::removeSubdomain()
 int CellComplex::coreduceComplex(bool omit)
 {
   printf("Cell Complex: \n %d volumes, %d faces, %d edges and %d vertices. \n",
-         getSize(3), getSize(2), getSize(1), getSize(0));
+	 getSize(3), getSize(2), getSize(1), getSize(0));
   
   int count = 0;
   removeSubdomain();
@@ -354,7 +354,7 @@ int CellComplex::coreduceComplex(bool omit)
   }
 
   printf(" %d volumes, %d faces, %d edges and %d vertices. \n",
-         getSize(3), getSize(2), getSize(1), getSize(0));
+	 getSize(3), getSize(2), getSize(1), getSize(0));
   
   cocombine(0);
   coreduction(1);
@@ -365,7 +365,7 @@ int CellComplex::coreduceComplex(bool omit)
   coherent();
 
   printf(" %d volumes, %d faces, %d edges and %d vertices. \n",
-         getSize(3), getSize(2), getSize(1), getSize(0));
+	 getSize(3), getSize(2), getSize(1), getSize(0));
 
   return omitted;
 }
@@ -390,7 +390,7 @@ int CellComplex::cocombine(int dim)
       Cell* s = Q.front();
       Q.pop();
       if(s->getBoundarySize() == 2){
-        Cell::biter it = s->firstBoundary();
+	Cell::biter it = s->firstBoundary();
         int or1 = (*it).second;
         Cell* c1 = (*it).first;
         it++;
@@ -399,7 +399,7 @@ int CellComplex::cocombine(int dim)
 
         if(!(*c1 == *c2) && abs(or1) == abs(or2)
            && inSameDomain(s, c1) && inSameDomain(s, c2)){
-          removeCell(s);
+	  removeCell(s);
           
           c1->getCoboundary(cbd_c);
           enqueueCells(cbd_c, Q, Qset);
@@ -407,7 +407,7 @@ int CellComplex::cocombine(int dim)
           enqueueCells(cbd_c, Q, Qset);
           
           CombinedCell* newCell = new CombinedCell(c1, c2, 
-                                                   (or1 != or2), true );
+						   (or1 != or2), true );
           removeCell(c1);
           removeCell(c2);
           insertCell(newCell);
@@ -448,7 +448,7 @@ int CellComplex::combine(int dim)
       Q.pop(); 
 
       if(s->getCoboundarySize() == 2){
-        Cell::biter it = s->firstCoboundary();
+	Cell::biter it = s->firstCoboundary();
         int or1 = (*it).second;
         Cell* c1 = (*it).first;
         it++;
@@ -468,7 +468,7 @@ int CellComplex::combine(int dim)
           removeCell(c1);
           removeCell(c2);
           insertCell(newCell);
-          
+	  
           cit = firstCell(dim);
           count++;
         }
@@ -492,7 +492,7 @@ bool CellComplex::coherent()
       std::map<Cell*, int, Less_Cell> boundary;
       cell->getBoundary(boundary);
       for(Cell::biter it = boundary.begin();
-          it != boundary.end(); it++){
+	  it != boundary.end(); it++){
         Cell* bdCell = (*it).first;
         int ori = (*it).second;
         citer cit = _cells[bdCell->getDim()].find(bdCell);
@@ -503,7 +503,7 @@ bool CellComplex::coherent()
         }
         if(!bdCell->hasCoboundary(cell)){
           printf("Warning! Incoherent boundary/coboundary pair! Fixed. \n");
-          bdCell->addCoboundaryCell(ori, cell, false, false);
+	  bdCell->addCoboundaryCell(ori, cell, false, false);
           coherent = false;
         }
         
@@ -511,7 +511,7 @@ bool CellComplex::coherent()
       std::map<Cell*, int, Less_Cell> coboundary;
       cell->getCoboundary(coboundary);
       for(Cell::biter it = coboundary.begin();
-          it != coboundary.end(); it++){
+	  it != coboundary.end(); it++){
         Cell* cbdCell = (*it).first;
         int ori = (*it).second;
         citer cit = _cells[cbdCell->getDim()].find(cbdCell);
@@ -522,7 +522,7 @@ bool CellComplex::coherent()
         }
         if(!cbdCell->hasBoundary(cell)){
           printf("Warning! Incoherent coboundary/boundary pair! Fixed. \n");
-          cbdCell->addBoundaryCell(ori, cell, false, false);
+	  cbdCell->addBoundaryCell(ori, cell, false, false);
           coherent = false;
         }
         
@@ -543,12 +543,12 @@ bool CellComplex::hasCell(Cell* cell, bool orig)
 }
 
 void  CellComplex::getCells(std::set<Cell*, Less_Cell>& cells, 
-                            int dim, int domain){
+			    int dim, int domain){
   cells.clear();
   for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
     Cell* cell = *cit;
     if( (domain == 0 && !cell->inSubdomain()) || domain == 1
-        || (domain == 2 && cell->inSubdomain()) ){
+	|| (domain == 2 && cell->inSubdomain()) ){
       cells.insert(cell);
     }
   }
diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h
index ae6ced80e378880da21b28b0da12ecaec9a2021e..a801d1f9281fa219dcf7892442a169bf76e2ccb5 100644
--- a/Geo/CellComplex.h
+++ b/Geo/CellComplex.h
@@ -48,7 +48,7 @@ class CellComplex
   
   // enqueue cells in queue if they are not there already
   void enqueueCells(std::map<Cell*, int, Less_Cell>& cells, 
-                    std::queue<Cell*>& Q, std::set<Cell*, Less_Cell>& Qset);
+		    std::queue<Cell*>& Q, std::set<Cell*, Less_Cell>& Qset);
   // remove cell from the queue set
   void removeCellQset(Cell* cell, std::set<Cell*, Less_Cell>& Qset);
   
@@ -66,7 +66,7 @@ class CellComplex
  public: 
   
   CellComplex( std::vector<MElement*>& domainElements, 
-               std::vector<MElement*>& subdomainElements);
+	       std::vector<MElement*>& subdomainElements);
   ~CellComplex();
 
   // get the number of certain dimensional cells
@@ -99,7 +99,7 @@ class CellComplex
   // check whether two cells both belong to subdomain or if neither one does
   bool inSameDomain(Cell* c1, Cell* c2) const { 
     return ( (!c1->inSubdomain() && !c2->inSubdomain()) 
-             || (c1->inSubdomain() && c2->inSubdomain() )); }
+	     || (c1->inSubdomain() && c2->inSubdomain() )); }
   
   // remove cells in subdomain from this cell complex
   void removeSubdomain();
diff --git a/Geo/ChainComplex.cpp b/Geo/ChainComplex.cpp
index 3bffbd8d68504da11a652c86d860641e1dd7e314..2a0c624583cf60e26c53da26973fbd1ab6a4fab9 100644
--- a/Geo/ChainComplex.cpp
+++ b/Geo/ChainComplex.cpp
@@ -15,55 +15,43 @@ ChainComplex::ChainComplex(CellComplex* cellComplex, int domain)
   _dim = cellComplex->getDim();
   _cellComplex = cellComplex;
   
-  _HMatrix[4] = NULL;
-  _kerH[4] = NULL;
-  _codH[4] = NULL;
-  _JMatrix[4] = NULL;
-  _QMatrix[4] = NULL;
-  _Hbasis[4] = NULL;
-     
+  for(int i = 0; i < 5; i++){
+    _HMatrix[i] = NULL;
+    _kerH[i] = NULL;
+    _codH[i] = NULL;
+    _JMatrix[i] = NULL;
+    _QMatrix[i] = NULL;
+    _Hbasis[i] = NULL;
+  }
+
+  int lastCols = 0;
   for(int dim = 0; dim < 4; dim++){
     unsigned int cols = cellComplex->getSize(dim);
     unsigned int rows = 0;
-    if(dim > 0) rows = cellComplex->getSize(dim-1);
     
     int index = 1;
     // ignore cells depending on domain
     for(CellComplex::citer cit = cellComplex->firstCell(dim); 
-        cit != cellComplex->lastCell(dim); cit++){
+	cit != cellComplex->lastCell(dim); cit++){
       Cell* cell = *cit;
       cell->setIndex(0);
       cols--;
-      if((domain == 0 && !cell->inSubdomain()) 
-         || (domain == 2 && cell->inSubdomain()) ){
+      if((domain == 0 && !cell->inSubdomain()) || domain == 1 
+	 || (domain == 2 && cell->inSubdomain()) ){
         cols++;
-        cell->setIndex(index);
-        index++;
-        _cellIndices[dim][cell->getIndex()] = cell;
-      }
-    }
-    index = 1;
-    if(dim > 0){
-      for(CellComplex::citer cit = cellComplex->firstCell(dim-1); 
-          cit != cellComplex->lastCell(dim-1); cit++){
-        Cell* cell = *cit;
-        cell->setIndex(0);
-        rows--;
-        if((domain == 0 && !cell->inSubdomain()) 
-           || (domain == 2 && cell->inSubdomain()) ){
-          rows++;
-          cell->setIndex(index);
-          index++;
-          _cellIndices[dim-1][cell->getIndex()] = cell;
-        }  
+	cell->setIndex(index);
+	index++;
+	_cellIndices[dim][cell] = cell->getIndex();
       }
     }
+    if(dim > 0) rows = lastCols;
+    lastCols = cols;
     
-    if( cols == 0 ){ // no dim-cells, no map
+    if(cols == 0){ // no dim-cells, no map
       //_HMatrix[dim] = create_gmp_matrix_zero(rows, 1);
       _HMatrix[dim] = NULL;
     }
-    else if( rows == 0){ // no dim-1-cells, maps everything to zero
+    else if(rows == 0){ // no dim-1-cells, maps everything to zero
       _HMatrix[dim] = create_gmp_matrix_zero(1, cols);
       //_HMatrix[dim] = NULL;
     }
@@ -73,34 +61,34 @@ ChainComplex::ChainComplex(CellComplex* cellComplex, int domain)
       mpz_init(elem);
       _HMatrix[dim] = create_gmp_matrix_zero(rows, cols);
       for( std::set<Cell*, Less_Cell>::iterator cit = 
-             cellComplex->firstCell(dim);
-           cit != cellComplex->lastCell(dim); cit++){
+	     cellComplex->firstCell(dim);
+	   cit != cellComplex->lastCell(dim); cit++){
         Cell* cell = *cit;
         if( (domain == 0 && !cell->inSubdomain()) || domain == 1 
-            || (domain == 2 && cell->inSubdomain()) ){
+	    || (domain == 2 && cell->inSubdomain()) ){
           for(Cell::biter it = cell->firstBoundary();
-              it != cell->lastBoundary(); it++){
+	      it != cell->lastBoundary(); it++){
             Cell* bdCell = (*it).first;
             if((domain == 0 && !bdCell->inSubdomain()) || domain == 1 
-               || (domain == 2 && cell->inSubdomain()) ){
+	       || (domain == 2 && cell->inSubdomain()) ){
               int old_elem = 0;
 
               if(bdCell->getIndex() > (int)gmp_matrix_rows( _HMatrix[dim]) 
-                 || bdCell->getIndex() < 1 
+		 || bdCell->getIndex() < 1 
                  || cell->getIndex() > (int)gmp_matrix_cols( _HMatrix[dim]) 
-                 || cell->getIndex() < 1){
-                //printf("Warning: Index out of bound! HMatrix: %d. \n", dim);
+		 || cell->getIndex() < 1){
+                printf("Warning: Index out of bound! HMatrix: %d. \n", dim);
               }
               else{
                 gmp_matrix_get_elem(elem, bdCell->getIndex(), 
-                                    cell->getIndex(), _HMatrix[dim]);
+				    cell->getIndex(), _HMatrix[dim]);
                 old_elem = mpz_get_si(elem);
                 mpz_set_si(elem, old_elem + (*it).second);
                 if( abs((old_elem + (*it).second)) > 1){
-                  //printf("Incidence index: %d, in HMatrix: %d. \n", (old_elem + (*it).second), dim);
+		  //printf("Incidence index: %d, in HMatrix: %d. \n", (old_elem + (*it).second), dim);
                 }
                 gmp_matrix_set_elem(elem, bdCell->getIndex(), 
-                                    cell->getIndex(), _HMatrix[dim]);
+				    cell->getIndex(), _HMatrix[dim]);
               }
             }
           }
@@ -115,9 +103,19 @@ ChainComplex::ChainComplex(CellComplex* cellComplex, int domain)
     _QMatrix[dim] = NULL;
     _Hbasis[dim] = NULL;     
   }
-  return;
 }
 
+ChainComplex::~ChainComplex()
+{
+  for(int i = 0; i < 5; i++){
+    destroy_gmp_matrix(_HMatrix[i]);
+    destroy_gmp_matrix(_kerH[i]);
+    destroy_gmp_matrix(_codH[i]);
+    destroy_gmp_matrix(_JMatrix[i]);
+    destroy_gmp_matrix(_QMatrix[i]);
+    destroy_gmp_matrix(_Hbasis[i]);
+  }
+}
 
 void ChainComplex::KerCod(int dim)
 { 
@@ -125,8 +123,8 @@ void ChainComplex::KerCod(int dim)
   
   gmp_matrix* HMatrix 
     = copy_gmp_matrix(_HMatrix[dim], 1, 1, 
-                      gmp_matrix_rows(_HMatrix[dim]),
-                      gmp_matrix_cols(_HMatrix[dim]));
+		      gmp_matrix_rows(_HMatrix[dim]),
+		      gmp_matrix_cols(_HMatrix[dim]));
   
   gmp_normal_form* normalForm 
     = create_gmp_Hermite_normal_form(HMatrix, NOT_INVERTED, INVERTED);
@@ -135,7 +133,7 @@ void ChainComplex::KerCod(int dim)
   //printMatrix(normalForm->right);
   
   int minRowCol = std::min(gmp_matrix_rows(normalForm->canonical), 
-                           gmp_matrix_cols(normalForm->canonical));
+			   gmp_matrix_cols(normalForm->canonical));
   int rank = 0;
   mpz_t elem;
   mpz_init(elem);
@@ -150,14 +148,14 @@ void ChainComplex::KerCod(int dim)
   if(rank != (int)gmp_matrix_cols(normalForm->canonical)){
     _kerH[dim] 
       = copy_gmp_matrix(normalForm->right, 1, rank+1, 
-                        gmp_matrix_rows(normalForm->right),
-                        gmp_matrix_cols(normalForm->right));
+			gmp_matrix_rows(normalForm->right),
+			gmp_matrix_cols(normalForm->right));
   }
   
   if(rank > 0){
      _codH[dim] = 
        copy_gmp_matrix(normalForm->canonical, 1, 1,
-                       gmp_matrix_rows(normalForm->canonical), rank);
+		       gmp_matrix_rows(normalForm->canonical), rank);
      gmp_matrix_left_mult(normalForm->left, _codH[dim]);
   }
   
@@ -167,7 +165,7 @@ void ChainComplex::KerCod(int dim)
   return;
 }
 
-//j:B_(k+1)->Z_k
+//j:B_k->Z_k
 void ChainComplex::Inclusion(int lowDim, int highDim)
 {
   if(getKerHMatrix(lowDim) == NULL 
@@ -176,12 +174,12 @@ void ChainComplex::Inclusion(int lowDim, int highDim)
   
   gmp_matrix* Zbasis = 
     copy_gmp_matrix(_kerH[lowDim], 1, 1,
-                    gmp_matrix_rows(_kerH[lowDim]), 
-                    gmp_matrix_cols(_kerH[lowDim]));
+		    gmp_matrix_rows(_kerH[lowDim]), 
+		    gmp_matrix_cols(_kerH[lowDim]));
   gmp_matrix* Bbasis 
     = copy_gmp_matrix(_codH[highDim], 1, 1,
-                      gmp_matrix_rows(_codH[highDim]), 
-                      gmp_matrix_cols(_codH[highDim]));
+		      gmp_matrix_rows(_codH[highDim]), 
+		      gmp_matrix_cols(_codH[highDim]));
   
   
   int rows = gmp_matrix_rows(Bbasis);
@@ -192,7 +190,7 @@ void ChainComplex::Inclusion(int lowDim, int highDim)
   cols = gmp_matrix_cols(Zbasis);
   if(rows < cols) return;
   
-  // A*inv(V) = U*S
+  // inv(U)*A*inv(V) = S
   gmp_normal_form* normalForm 
     = create_gmp_Smith_normal_form(Zbasis, INVERTED, INVERTED);
   
@@ -211,8 +209,8 @@ void ChainComplex::Inclusion(int lowDim, int highDim)
   gmp_matrix_left_mult(normalForm->left, Bbasis); 
   
   gmp_matrix* LB = copy_gmp_matrix(Bbasis, 1, 1, 
-                                   gmp_matrix_cols(Zbasis), 
-                                   gmp_matrix_cols(Bbasis));
+				   gmp_matrix_cols(Zbasis), 
+				   gmp_matrix_cols(Bbasis));
   destroy_gmp_matrix(Bbasis);
   
   rows = gmp_matrix_rows(LB);
@@ -245,8 +243,6 @@ void ChainComplex::Inclusion(int lowDim, int highDim)
   mpz_clear(divisor);
   mpz_clear(result);
   destroy_gmp_normal_form(normalForm);
-  
-  return;
 }
 
 void ChainComplex::Quotient(int dim)
@@ -255,8 +251,8 @@ void ChainComplex::Quotient(int dim)
   
   gmp_matrix* JMatrix = 
     copy_gmp_matrix(_JMatrix[dim], 1, 1,
-                    gmp_matrix_rows(_JMatrix[dim]), 
-                    gmp_matrix_cols(_JMatrix[dim]));
+		    gmp_matrix_rows(_JMatrix[dim]), 
+		    gmp_matrix_cols(_JMatrix[dim]));
   int rows = gmp_matrix_rows(JMatrix);
   int cols = gmp_matrix_cols(JMatrix);
   
@@ -321,13 +317,13 @@ void ChainComplex::computeHomology(bool dual)
        &&  gmp_matrix_cols(getHMatrix(lowDim)) > 0 
        && getHMatrix(highDim) == NULL) {
       setHbasis( setDim, 
-                 create_gmp_matrix_identity(gmp_matrix_cols(getHMatrix(lowDim))) );
+		 create_gmp_matrix_identity(gmp_matrix_cols(getHMatrix(lowDim))) );
     }
     else if(highDim == 0 && dual 
-            &&  gmp_matrix_rows(getHMatrix(highDim)) > 0 
-            && getHMatrix(lowDim) == NULL) {
+	    &&  gmp_matrix_rows(getHMatrix(highDim)) > 0 
+	    && getHMatrix(lowDim) == NULL) {
       setHbasis( setDim, 
-                 create_gmp_matrix_identity(gmp_matrix_rows(getHMatrix(highDim))) );
+		 create_gmp_matrix_identity(gmp_matrix_rows(getHMatrix(highDim))) );
     }
     
     // 2) this dimension is empty
@@ -337,9 +333,9 @@ void ChainComplex::computeHomology(bool dual)
     // 3) No higher dimension cells -> none of the cycles are boundaries
     else if(getHMatrix(highDim) == NULL){
       setHbasis( setDim, 
-                 copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1,
-                                 gmp_matrix_rows(getKerHMatrix(lowDim)), 
-                                 gmp_matrix_cols(getKerHMatrix(lowDim))) );
+		 copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1,
+				 gmp_matrix_rows(getKerHMatrix(lowDim)), 
+				 gmp_matrix_cols(getKerHMatrix(lowDim))) );
     }
     
    
@@ -352,37 +348,37 @@ void ChainComplex::computeHomology(bool dual)
       // 4) No lower dimension cells -> all chains are cycles
       if(getHMatrix(lowDim) == NULL){
         setKerHMatrix(lowDim, 
-                      create_gmp_matrix_identity(gmp_matrix_rows(getHMatrix(highDim))) );
+		      create_gmp_matrix_identity(gmp_matrix_rows(getHMatrix(highDim))) );
       }
       Inclusion(lowDim, highDim);
       Quotient(lowDim);
       
       if(getCodHMatrix(highDim) == NULL){
         setHbasis(setDim, 
-                  copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1,
-                                  gmp_matrix_rows(getKerHMatrix(lowDim)), 
-                                  gmp_matrix_cols(getKerHMatrix(lowDim))) );
+		  copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1,
+				  gmp_matrix_rows(getKerHMatrix(lowDim)), 
+				  gmp_matrix_cols(getKerHMatrix(lowDim))) );
       }  
       else if(getJMatrix(lowDim) == NULL || getQMatrix(lowDim) == NULL){
         setHbasis(setDim, NULL);
       } 
       else{
         setHbasis(setDim, 
-                  copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1, 
-                                  gmp_matrix_rows(getKerHMatrix(lowDim)), 
-                                  gmp_matrix_cols(getKerHMatrix(lowDim))) );
+		  copy_gmp_matrix(getKerHMatrix(lowDim), 1, 1, 
+				  gmp_matrix_rows(getKerHMatrix(lowDim)), 
+				  gmp_matrix_cols(getKerHMatrix(lowDim))) );
         
         gmp_matrix_right_mult(getHbasis(setDim), getQMatrix(lowDim));
       } 
     } 
-    
-    destroy_gmp_matrix(getKerHMatrix(lowDim));
-    destroy_gmp_matrix(getCodHMatrix(lowDim));
+
+    //destroy_gmp_matrix(getKerHMatrix(lowDim));
+    //destroy_gmp_matrix(getCodHMatrix(lowDim));
     destroy_gmp_matrix(getJMatrix(lowDim));
     destroy_gmp_matrix(getQMatrix(lowDim));
     
-    setKerHMatrix(lowDim, NULL);
-    setCodHMatrix(lowDim, NULL);
+    //setKerHMatrix(lowDim, NULL);
+    //setCodHMatrix(lowDim, NULL);
     setJMatrix(lowDim, NULL);
     setQMatrix(lowDim, NULL);  
   } 
@@ -433,50 +429,406 @@ std::vector<int> ChainComplex::getCoeffVector(int dim, int chainNumber)
   return coeffVector;  
 }
 
-void ChainComplex::getChain(std::map<Cell*, int, Less_Cell>& chain, 
-                            int dim, int chainNumber)
+gmp_matrix* ChainComplex::getBasis(int dim, int basis)
 {
+  if(dim > -2 && dim < 5 && basis == 2) return _codH[dim+1];
+  if(dim < 0 || dim > 4) return NULL;
+  if(basis == 0) return create_gmp_matrix_identity(getBasisSize(dim, 0));
+  else if(basis == 1) return _kerH[dim];
+  else if(basis == 3) return _Hbasis[dim];
+  else return NULL;
+}
+
+void ChainComplex::getBasisChain(std::map<Cell*, int, Less_Cell>& chain, 
+				 int num, int dim, int basis)
+{
+  gmp_matrix* basisMatrix;
+  if(basis == 0) basisMatrix = getBasis(dim, 0);
+  else if(basis == 1) basisMatrix = getBasis(dim, 1);
+  else if(basis == 2) basisMatrix = getBasis(dim, 2);
+  else if(basis == 3) basisMatrix = getBasis(dim, 3);
+  else return;
+
   chain.clear();
   if(dim < 0 || dim > 4) return;
-  if(_Hbasis[dim] == NULL
-     || (int)gmp_matrix_cols(_Hbasis[dim]) < chainNumber) return;
+  if(basisMatrix == NULL
+     || (int)gmp_matrix_cols(basisMatrix) < num) return;
 
-  int rows = gmp_matrix_rows(_Hbasis[dim]);
+  int rows = gmp_matrix_rows(basisMatrix);
 
   int elemi;
   long int elemli;
   mpz_t elem;
   mpz_init(elem);
 
-  for(int i = 1; i <= rows; i++){
-    gmp_matrix_get_elem(elem, i, chainNumber, _Hbasis[dim]);
+  for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
+    Cell* cell = cit->first;
+    int index = cit->second;
+    gmp_matrix_get_elem(elem, index, num, basisMatrix); 
     elemli = mpz_get_si(elem);
     elemi = elemli;
-    Cell* cell = _cellIndices[dim][i];
-    if(cell == NULL){
-      //printf("Warning: Missing cell in %d-chain %d. \n", dim, chainNumber);
-      continue;
-    }
-
-    std::map<Cell*, int, Less_Cell > subCells;
-    cell->getCells(subCells);
-    for(Cell::citer it = subCells.begin(); it != subCells.end(); it++){
-      Cell* subCell = (*it).first;
-      int coeff = (*it).second;
-      chain[subCell] = coeff*elemi;
+    if(elemli != 0){
+      std::map<Cell*, int, Less_Cell > subCells;
+      cell->getCells(subCells);
+      for(Cell::citer it = subCells.begin(); it != subCells.end(); it++){
+	Cell* subCell = (*it).first;
+	int coeff = (*it).second;
+	chain[subCell] = coeff*elemi; 
+      }
     }
   }
   mpz_clear(elem);
 }
 
-int ChainComplex::getTorsion(int dim, int chainNumber)
+int ChainComplex::getBasisSize(int dim, int basis)
+{
+    gmp_matrix* basisMatrix;
+    if(basis == 0 && _HMatrix[dim] != NULL){
+      return gmp_matrix_cols(_HMatrix[dim]);
+    }
+    else if(basis == 1) basisMatrix = getBasis(dim, 1);
+    else if(basis == 2) basisMatrix = getBasis(dim, 2);
+    else if(basis == 3) basisMatrix = getBasis(dim, 3);
+    else return 0;
+    
+    if(basisMatrix != NULL) return gmp_matrix_cols(basisMatrix);
+    else return 0; 
+}
+
+
+int ChainComplex::getTorsion(int dim, int num)
 {
   if(dim < 0 || dim > 4) return 0;
   if(_Hbasis[dim] == NULL 
-     || (int)gmp_matrix_cols(_Hbasis[dim]) < chainNumber) return 0;
+     || (int)gmp_matrix_cols(_Hbasis[dim]) < num) return 0;
   if(_torsion[dim].empty() 
-     || (int)_torsion[dim].size() < chainNumber) return 1;
-  else return _torsion[dim].at(chainNumber-1);
+     || (int)_torsion[dim].size() < num) return 1;
+  else return _torsion[dim].at(num-1);
+}
+
+
+HomologySequence::HomologySequence(ChainComplex* subcomplex, 
+				   ChainComplex* complex, 
+				   ChainComplex* relcomplex)
+{
+  _subcomplex = subcomplex;
+  _complex = complex;
+  _relcomplex = relcomplex;
+
+  mpz_t elem;
+  mpz_init_set_si(elem, -1);  
+
+  for(int i = 0; i < 4; i++){
+    
+    //printf("Dimension %d. \n", i);
+    _Ic_sub[i] = NULL;
+    _Ic_rel[i] = NULL;
+
+    _Dh[i] = NULL;
+    _invDh[i] = NULL;
+
+    _Jh[i] = NULL;
+    _Ih[i] = NULL;
+    _invJh[i] = NULL;
+    _invIh[i] = NULL;
+
+    mpz_t one;
+    mpz_init_set_si(one, 1);
+    if(_complex->getBasisSize(i, 0) > 0 
+       && _subcomplex->getBasisSize(i, 0) > 0){
+      _Ic_sub[i] = create_gmp_matrix_zero(_complex->getBasisSize(i, 0), 
+					  _subcomplex->getBasisSize(i, 0));
+      //printf("rows %d, cols %d. \n", _complex->getBasisSize(i, 0),
+      //	     _subcomplex->getBasisSize(i, 0));
+      for(ChainComplex::citer cit = _complex->firstCell(i);
+	  cit != _complex->lastCell(i); cit++){
+	Cell* cell = cit->first;
+	int row = cit->second;
+	int col = _subcomplex->cellIndex(cell);
+	//printf("row %d, col %d. \n", row, col);
+	if(col != 0) gmp_matrix_set_elem(one, row, col, _Ic_sub[i]);
+      }
+    }
+
+    if(_complex->getBasisSize(i, 0) > 0 
+       && _relcomplex->getBasisSize(i, 0) > 0){
+      _Ic_rel[i] = create_gmp_matrix_zero(_complex->getBasisSize(i, 0), 
+					  _relcomplex->getBasisSize(i, 0));
+      //printf("rows %d, cols %d. \n", _complex->getBasisSize(i, 0), 
+      for(ChainComplex::citer cit = _complex->firstCell(i);
+	  cit != _complex->lastCell(i); cit++){
+	Cell* cell = cit->first;
+	int row = cit->second;
+	int col = _relcomplex->cellIndex(cell);
+	//printf("row %d, col %d. \n", row, col);
+	if(col != 0) gmp_matrix_set_elem(one, row, col, _Ic_rel[i]);
+      }
+    }
+    mpz_clear(one);
+
+    if(_Ic_sub[i] != NULL 
+       && _complex->getBasisSize(i, 3) > 0 
+       && _subcomplex->getBasisSize(i, 3) > 0){
+      gmp_matrix* IH = copy_gmp_matrix(_Ic_sub[i], 1, 1, 
+				       gmp_matrix_rows(_Ic_sub[i]), 
+				       gmp_matrix_cols(_Ic_sub[i]));
+      gmp_matrix_right_mult(IH, _subcomplex->getBasis(i, 3));
+      _Ih[i] = createIncMap(IH, _complex->getBasis(i, 3)); 
+    }
+    if(_Ic_sub[i] != NULL 
+       && _complex->getBasisSize(i, 3) > 0 
+       && _subcomplex->getBasisSize(i, 3) > 0){
+      gmp_matrix* IH = copy_gmp_matrix(_Ic_sub[i], 1, 1, 
+				       gmp_matrix_rows(_Ic_sub[i]), 
+				       gmp_matrix_cols(_Ic_sub[i]));
+      gmp_matrix_transp(IH);
+      gmp_matrix_right_mult(IH, _complex->getBasis(i, 3));
+      _invIh[i] = createIncMap(IH, _subcomplex->getBasis(i, 3)); 
+    }
+
+    if(_Ic_rel[i] != NULL 
+       && _complex->getBasisSize(i, 3) > 0 
+       && _relcomplex->getBasisSize(i, 3) > 0){
+      gmp_matrix* JH = copy_gmp_matrix(_Ic_rel[i], 1, 1, 
+				       gmp_matrix_rows(_Ic_rel[i]), 
+				       gmp_matrix_cols(_Ic_rel[i]));
+      gmp_matrix_transp(JH);
+      gmp_matrix_right_mult(JH, _complex->getBasis(i, 3));
+      _Jh[i] = createIncMap(JH, _relcomplex->getBasis(i, 3)); 
+    }
+    if(_Ic_rel[i] != NULL 
+       && _complex->getBasisSize(i, 3) > 0 
+       && _relcomplex->getBasisSize(i, 3) > 0){
+      gmp_matrix* JH = copy_gmp_matrix(_Ic_rel[i], 1, 1, 
+				       gmp_matrix_rows(_Ic_rel[i]), 
+				       gmp_matrix_cols(_Ic_rel[i]));
+      gmp_matrix_right_mult(JH, _relcomplex->getBasis(i, 3));
+      _invJh[i] = createIncMap(JH, _complex->getBasis(i, 3)); 
+    }
+
+    //printMatrix(_Ih[i]);
+    //printMatrix(_invIh[i]);
+    //printMatrix(_Jh[i]);
+    //printMatrix(_invJh[i]);
+    
+    if(i > 0 && _relcomplex->getBasisSize(i, 3) > 0 
+       && _subcomplex->getBasisSize(i-1, 3) > 0
+       && _complex->getBoundaryOp(i) != NULL){
+      gmp_matrix* JDIH = copy_gmp_matrix(_Ic_sub[i-1], 1, 1, 
+					 gmp_matrix_rows(_Ic_sub[i-1]), 
+					 gmp_matrix_cols(_Ic_sub[i-1]));
+      gmp_matrix_transp(JDIH);
+      gmp_matrix_right_mult(JDIH, _complex->getBoundaryOp(i));
+      gmp_matrix_right_mult(JDIH, _Ic_rel[i]);
+      gmp_matrix_right_mult(JDIH, _relcomplex->getBasis(i, 3));
+      _Dh[i] = createIncMap(JDIH, _subcomplex->getBasis(i-1, 3));
+    }
+
+    if(i > 0 && _relcomplex->getBasisSize(i, 3) > 0 
+       && _subcomplex->getBasisSize(i-1, 3) > 0
+       && _complex->getBoundaryOp(i) != NULL){
+      gmp_matrix* JDIH = copy_gmp_matrix(_Ic_rel[i], 1, 1, 
+					 gmp_matrix_rows(_Ic_rel[i]), 
+					 gmp_matrix_cols(_Ic_rel[i]));
+      gmp_matrix_transp(JDIH);
+      gmp_matrix* bd = _complex->getBoundaryOp(i);
+      gmp_matrix_transp(bd);
+      gmp_matrix_right_mult(JDIH, bd);
+      gmp_matrix_transp(bd);
+      gmp_matrix_right_mult(JDIH, _Ic_sub[i-1]);
+      gmp_matrix_right_mult(JDIH, _subcomplex->getBasis(i-1, 3));
+      _invDh[i] = createIncMap(JDIH, _relcomplex->getBasis(i, 3));
+    }
+    
+    //printMatrix(_Dh[i]);
+    //printMatrix(_invDh[i]);
+
+  }
+  for(int i = 0; i < 3; i++){
+    blockHBasis(_Dh[i+1], _invIh[i], _subcomplex, i);
+    blockHBasis(_Ih[i], _invJh[i], _complex, i);
+    blockHBasis(_Jh[i], _invDh[i], _relcomplex, i);
+  }
+  
+}
+
+HomologySequence::~HomologySequence() 
+{
+  for(int i = 0; i < 4; i++){
+    destroy_gmp_matrix(_Ic_sub[i]);
+    destroy_gmp_matrix(_Ic_rel[i]);
+    destroy_gmp_matrix(_Ih[i]);
+    destroy_gmp_matrix(_Jh[i]);
+    destroy_gmp_matrix(_invIh[i]);
+    destroy_gmp_matrix(_invJh[i]);
+    destroy_gmp_matrix(_Dh[i]);
+    destroy_gmp_matrix(_invDh[i]);
+  }
 }
 
+//i: a->b  : aBasis = bBasis*incMap
+gmp_matrix* HomologySequence::createIncMap(gmp_matrix* domBasis, 
+					   gmp_matrix* codBasis) 
+{
+  if(domBasis == NULL || codBasis == NULL){
+    printf("ERROR: null matrix given. \n");
+    return NULL;
+  }
+  
+  int rows = gmp_matrix_rows(domBasis);
+  int cols = gmp_matrix_cols(domBasis);
+  if(rows < cols || rows == 0 || cols == 0) return NULL;
+ 
+  rows = gmp_matrix_rows(codBasis);
+  cols = gmp_matrix_cols(codBasis);
+  if(rows < cols || rows == 0 || cols == 0) return NULL;
+
+  gmp_matrix* temp = codBasis;  
+  codBasis = copy_gmp_matrix(temp, 1, 1,
+			     gmp_matrix_rows(temp),
+			     gmp_matrix_cols(temp));
+  // inv(U)*A*inv(V) = S
+  gmp_normal_form* normalForm 
+    = create_gmp_Smith_normal_form(codBasis, INVERTED, 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 NULL;
+    }
+  }
+  
+  gmp_matrix_left_mult(normalForm->left, domBasis); 
+  gmp_matrix* LB = copy_gmp_matrix(domBasis, 1, 1, 
+				   gmp_matrix_cols(codBasis), 
+				   gmp_matrix_cols(domBasis));
+  destroy_gmp_matrix(domBasis);
+
+  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 NULL;
+    }
+  }
+
+  gmp_matrix_left_mult(normalForm->right, LB);
+
+  mpz_clear(elem);
+  mpz_clear(divisor);
+  mpz_clear(result);
+  destroy_gmp_normal_form(normalForm);
+  return LB;
+}
+
+
+gmp_matrix* HomologySequence::removeZeroCols(gmp_matrix* matrix) // FIXME
+{
+  mpz_t elem;
+  mpz_init(elem);
+
+  int rows = gmp_matrix_rows(matrix);
+  int cols = gmp_matrix_cols(matrix);
+
+  std::vector<int> zcols;
+
+  for(int j = 1; j <= cols; j++){
+    bool zcol = true;
+    for(int i = 1; i <= rows; i++){
+      gmp_matrix_get_elem(elem, i, j, matrix);
+      if(mpz_cmp_si(elem, 0) != 0){
+	zcol = false;
+	break;
+      }
+    }
+    if(zcol) zcols.push_back(j);
+  }
+  if(zcols.empty()) return matrix;
+  
+  gmp_matrix* newMatrix = create_gmp_matrix_zero(rows, cols-zcols.size());
+  if(cols-zcols.size() == 0) return newMatrix;
+
+  int k = 0;
+  for(int j = 1; j <= cols; j++){
+    if(zcols.size()-1 < k) break;
+    if(zcols.at(k) == j) { k++; continue; }
+    for(int i = 1; i <= rows; i++){
+      gmp_matrix_get_elem(elem, i, j, matrix);
+      gmp_matrix_set_elem(elem, i, j-k, newMatrix);
+    }
+  }
+
+  destroy_gmp_matrix(matrix);
+  mpz_clear(elem);
+  return newMatrix;
+}
+
+void HomologySequence::blockHBasis(gmp_matrix* block1T, 
+				   gmp_matrix* block2T, 
+				   ChainComplex* complex, int dim)
+{
+  if(block1T == NULL && block2T == NULL) return;
+
+  gmp_matrix* Hbasis = complex->getBasis(dim, 3);
+  
+  if(block1T == NULL && block2T != NULL){
+    gmp_matrix_right_mult(Hbasis, block2T);
+    return;
+  }
+  if(block1T != NULL && block2T == NULL){
+    gmp_matrix_right_mult(Hbasis, block1T);
+    return;
+  }
+
+  int rows = gmp_matrix_rows(Hbasis);
+  int cols = gmp_matrix_cols(Hbasis);
+  gmp_matrix* temp1 = copy_gmp_matrix(Hbasis, 1, 1, rows, cols); 
+  gmp_matrix* temp2 = copy_gmp_matrix(Hbasis, 1, 1, rows, cols);
+
+  gmp_matrix_right_mult(temp1, block1T); 
+  gmp_matrix_right_mult(temp2, block2T);
+  
+  
+  temp1 = removeZeroCols(temp1);
+  temp2 = removeZeroCols(temp2);
+  //printMatrix(temp1);
+  //printMatrix(temp2);
+
+  int bcol = gmp_matrix_cols(temp1);
+  
+  mpz_t elem;
+  mpz_init(elem);
+  for(int i = 1; i <= rows; i++){
+    for(int j = 1; j <= cols; j++){
+      if(j <= bcol) gmp_matrix_get_elem(elem, i, j, temp1);
+      else gmp_matrix_get_elem(elem, i, j-bcol, temp2);
+      gmp_matrix_set_elem(elem, i, j, Hbasis);
+    }
+  }
+
+  //printMatrix(Hbasis);
+  mpz_clear(elem);
+  destroy_gmp_matrix(temp1);
+  destroy_gmp_matrix(temp2);
+}
+
+
 #endif
diff --git a/Geo/ChainComplex.h b/Geo/ChainComplex.h
index ef2308128e8b82c9285c2e803fd45b76c67debb9..dcf9b2fe3923202566cb2eb076864be3166aa186 100644
--- a/Geo/ChainComplex.h
+++ b/Geo/ChainComplex.h
@@ -33,7 +33,8 @@ class CellComplex;
 // This should only be constructed for a reduced cell complex because of
 // dense matrix representations and great computational complexity in 
 // its methods.
-class ChainComplex{
+class ChainComplex
+{
  private:
   // boundary operator matrices for this chain complex
   // h_k: C_k -> C_(k-1)
@@ -44,17 +45,23 @@ class ChainComplex{
   gmp_matrix* _kerH[5];
   gmp_matrix* _codH[5];
   
+  // matrix of the mapping B_k -> Z_k
   gmp_matrix* _JMatrix[5];
+  // matrix of the mapping H_k -> Z_k
   gmp_matrix* _QMatrix[5];
-  std::vector<long int> _torsion[5];
-  
+
   // bases for homology groups
   gmp_matrix* _Hbasis[5];
+  // torsion coefficients of homology generators
+  // corresponding the columns of _Hbasis
+  std::vector<long int> _torsion[5];
   
   int _dim;
   CellComplex* _cellComplex;
 
-  std::map<int, Cell*> _cellIndices[4];
+  // index to cell map 
+  // matrix indices correspond to these cells in _cellComplex
+  std::map<Cell*, int, Less_Cell> _cellIndices[4];
   
   // set the matrices
   void setHMatrix(int dim, gmp_matrix* matrix) { 
@@ -69,49 +76,51 @@ class ChainComplex{
     if(dim > -1 && dim < 5)  _QMatrix[dim] = matrix;}
   void setHbasis(int dim, gmp_matrix* matrix) { 
     if(dim > -1 && dim < 5) _Hbasis[dim] = matrix;}
-  
- public:
-  
-  // domain = 0 : relative chain space
-  // domain = 1 : absolute chain space of all cells in cellComplex
-  // domain = 2 : absolute chain space of cells in subdomain
-  ChainComplex(CellComplex* cellComplex, int domain=0);  
-  ~ChainComplex(){
-    for(int i = 0; i < 5; i++){
-      destroy_gmp_matrix(_HMatrix[i]);
-      destroy_gmp_matrix(_kerH[i]);
-      destroy_gmp_matrix(_codH[i]);
-      destroy_gmp_matrix(_JMatrix[i]);
-      destroy_gmp_matrix(_QMatrix[i]);
-      destroy_gmp_matrix(_Hbasis[i]);
-    }
-  }
-  
-  int getDim() { return _dim; }
-  
+
+
   // get the boundary operator matrix dim->dim-1
-  gmp_matrix* getHMatrix(int dim) { 
+  gmp_matrix* getHMatrix(int dim) const { 
     if(dim > -1 && dim < 5) return _HMatrix[dim]; else return NULL;}
-  gmp_matrix* getKerHMatrix(int dim) { 
+  gmp_matrix* getKerHMatrix(int dim) const { 
     if(dim > -1 && dim < 5) return _kerH[dim]; else return NULL;}
-  gmp_matrix* getCodHMatrix(int dim) { 
+  gmp_matrix* getCodHMatrix(int dim) const { 
     if(dim > -1 && dim < 5) return _codH[dim]; else return NULL;}
-  gmp_matrix* getJMatrix(int dim) { 
+  gmp_matrix* getJMatrix(int dim) const { 
     if(dim > -1 && dim < 5) return _JMatrix[dim]; else return NULL;}
-  gmp_matrix* getQMatrix(int dim) { 
+  gmp_matrix* getQMatrix(int dim) const { 
     if(dim > -1 && dim < 5) return _QMatrix[dim]; else return NULL;}
-  gmp_matrix* getHbasis(int dim) { 
+  gmp_matrix* getHbasis(int dim) const { 
     if(dim > -1 && dim < 5) return _Hbasis[dim]; else return NULL;}
+
+  
+ public:  
+  // domain = 0 : relative chain space
+  // domain = 1 : absolute chain space of all cells in cellComplex
+  // domain = 2 : absolute chain space of cells in subdomain
+  ChainComplex(CellComplex* cellComplex, int domain=0);  
+  ~ChainComplex();
+  
+  int getDim() const { return _dim; }
   
-  // Compute basis for kernel and codomain of boundary operator matrix
+  // 0 : C basis (chains)
+  // 1 : Z basis (cycles)
+  // 2 : B basis (boundaries)
+  // 3 : H basis (homology)
+  // get the bases for various spaces
+  gmp_matrix* getBasis(int dim, int basis);  
+  gmp_matrix* getBoundaryOp(int dim) {
+    if(dim > -1 && dim < 5) return _HMatrix[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) )
   void KerCod(int dim);
-   // Compute matrix representation J for inclusion relation from dim-cells
+   // 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) )
   void Inclusion(int lowDim, int highDim);
-  // Compute quotient problem for given inclusion relation j to find
-  //representatives of homology groups and possible torsion coeffcients
+  // compute quotient problem for given inclusion relation j to find
+  // representatives of homology group generators and possible 
+  // torsion coeffcients
   void Quotient(int dim);
   
   // transpose the boundary operator matrices, these are boundary operator 
@@ -124,26 +133,89 @@ class ChainComplex{
   // Compute bases for the homology groups of this chain complex 
   void computeHomology(bool dual=false);
   
-  // get coefficient vector for dim-dimensional chain chainNumber 
-  // (columns of _Hbasis[dim]) 
+  
+  typedef std::map<Cell*, int, Less_Cell>::iterator citer;
+  citer firstCell(int dim){ return _cellIndices[dim].begin(); } 
+  citer lastCell(int dim){ return _cellIndices[dim].end(); } 
+  // get the cell index
+  int cellIndex(Cell* cell){
+    citer cit = _cellIndices[cell->getDim()].find(cell);
+    if(cit != lastCell(cell->getDim())) return cit->second;
+    else return 0;
+  }
+
+  // get coefficient vector for dim-dimensional Hbasis chain chainNumber
   std::vector<int> getCoeffVector(int dim, int chainNumber);
-  void getChain(std::map<Cell*, int, Less_Cell>& chain, int dim, int chainNumber);
-  // torsion coefficient for dim-dimensional chain chainNumber 
-  int getTorsion(int dim, int chainNumber);
-  // get rank of homology group of dimension dim
-  int getBasisSize(int dim) { 
-    if(dim > -1 && dim < 5) return gmp_matrix_cols(_Hbasis[dim]);
-    else return 0; } 
+  // get basis chain from a basis matrix
+  void getBasisChain(std::map<Cell*, int, Less_Cell>& chain, 
+		     int num, int dim, int basis);
+  // get rank of a basis
+  int getBasisSize(int dim, int basis);
+  // homology torsion coefficient for dim-dimensional chain num 
+  int getTorsion(int dim, int num);
+  
+  // apply a transformation T to a basis (T should be unimodular)
+  void transformBasis(gmp_matrix* T, int dim, int basis){
+    if(basis == 3 && _Hbasis[dim] != NULL) {
+      gmp_matrix_right_mult(_Hbasis[dim], T);
+    }
+  }
   
+  // debugging aid
   int printMatrix(gmp_matrix* matrix){ 
     printf("%d rows and %d columns\n", 
-           (int)gmp_matrix_rows(matrix), (int)gmp_matrix_cols(matrix)); 
+	   (int)gmp_matrix_rows(matrix), (int)gmp_matrix_cols(matrix)); 
     return gmp_matrix_printf(matrix); } 
-  
-  // debugging aid
   void matrixTest();
 };
 
+
+// An experimental class to modify computed bases for homnology spaces
+// so that the basis chains are decomposed according to the long
+// exact homology sequence.
+class HomologySequence
+{
+ private:
+  ChainComplex* _subcomplex;
+  ChainComplex* _complex;
+  ChainComplex* _relcomplex;
+  
+  gmp_matrix* _Ic_sub[4];
+  gmp_matrix* _Ic_rel[4];
+
+  gmp_matrix* _Ih[4];
+  gmp_matrix* _Jh[4];
+  gmp_matrix* _invIh[4];
+  gmp_matrix* _invJh[4];
+  
+
+  gmp_matrix* _Dh[4];
+  gmp_matrix* _invDh[4];
+
+ public:
+  
+  HomologySequence(ChainComplex* subcomplex, ChainComplex* complex, 
+		   ChainComplex* relcomplex);
+  ~HomologySequence();
+
+  // create an inclusion map from domBasis to codBasis
+  // (deletes domBasis, leaves codBasis unaffected)
+  gmp_matrix* createIncMap(gmp_matrix* domBasis, 
+			   gmp_matrix* codBasis);
+
+
+  gmp_matrix* removeZeroCols(gmp_matrix* matrix);
+  void blockHBasis(gmp_matrix* block1T, gmp_matrix* block2T, 
+		   ChainComplex* complex, int dim);
+    
+  int printMatrix(gmp_matrix* matrix){
+    if(matrix == NULL){ printf("NULL matrix. \n"); return 0; }
+    printf("%d rows and %d columns\n",
+           (int)gmp_matrix_rows(matrix), (int)gmp_matrix_cols(matrix));
+    return gmp_matrix_printf(matrix); }  
+
+};
+
 #endif
    
 #endif
diff --git a/Geo/Homology.cpp b/Geo/Homology.cpp
index c0e571a8f8252882fcdfe86c7d80531bf746340b..eef7aca4cb1be41eb8711ba1416128cab67b88e4 100644
--- a/Geo/Homology.cpp
+++ b/Geo/Homology.cpp
@@ -11,7 +11,7 @@
 #if defined(HAVE_KBIPACK)
 
 Homology::Homology(GModel* model, std::vector<int> physicalDomain, 
-                   std::vector<int> physicalSubdomain)
+		   std::vector<int> physicalSubdomain)
 { 
   _model = model; 
   _domain = physicalDomain;
@@ -37,10 +37,10 @@ Homology::Homology(GModel* model, std::vector<int> physicalDomain,
     for(int j = 0; j < 4; j++){
       it = groups[j].find(_domain.at(i));
       if(it != groups[j].end()){
-        std::vector<GEntity*> physicalGroup = (*it).second;
-        for(unsigned int k = 0; k < physicalGroup.size(); k++){
-          _domainEntities.push_back(physicalGroup.at(k));
-        }
+	std::vector<GEntity*> physicalGroup = (*it).second;
+	for(unsigned int k = 0; k < physicalGroup.size(); k++){
+	  _domainEntities.push_back(physicalGroup.at(k));
+	}
       }
     }
   }
@@ -48,10 +48,10 @@ Homology::Homology(GModel* model, std::vector<int> physicalDomain,
     for(int j = 0; j < 4; j++){
       it = groups[j].find(_subdomain.at(i));
       if(it != groups[j].end()){
-        std::vector<GEntity*> physicalGroup = (*it).second;
-        for(unsigned int k = 0; k < physicalGroup.size(); k++){
-          _subdomainEntities.push_back(physicalGroup.at(k));
-        }         
+	std::vector<GEntity*> physicalGroup = (*it).second;
+	for(unsigned int k = 0; k < physicalGroup.size(); k++){
+	  _subdomainEntities.push_back(physicalGroup.at(k));
+	}	  
       }
     }
   }
@@ -59,7 +59,7 @@ Homology::Homology(GModel* model, std::vector<int> physicalDomain,
 }
 
 CellComplex* Homology::createCellComplex(std::vector<GEntity*>& domainEntities,
-                            std::vector<GEntity*>& subdomainEntities){
+			    std::vector<GEntity*>& subdomainEntities){
   Msg::Info("Creating a Cell Complex...");
   Msg::StatusBar(1, false, "Cell Complex...");
   Msg::StatusBar(2, false, "");
@@ -79,14 +79,14 @@ CellComplex* Homology::createCellComplex(std::vector<GEntity*>& domainEntities,
   }
   for(unsigned int j=0; j < subdomainEntities.size(); j++) {
     for(unsigned int i=0; i < subdomainEntities.at(j)->getNumMeshElements();
-        i++){
+	i++){
       MElement* element = subdomainEntities.at(j)->getMeshElement(i);
       subdomainElements.push_back(element);
     }
   }
 
   CellComplex* cellComplex =  new CellComplex(domainElements, 
-                                              subdomainElements);
+					      subdomainElements);
 
   if(cellComplex->getSize(0) == 0){ 
     Msg::Error("Cell Complex is empty!");
@@ -96,10 +96,10 @@ CellComplex* Homology::createCellComplex(std::vector<GEntity*>& domainEntities,
   Msg::Info("Cell Complex complete (%g s).", t2 - t1);
   Msg::Info("%d volumes, %d faces, %d edges and %d vertices.",
             cellComplex->getSize(3), cellComplex->getSize(2), 
-            cellComplex->getSize(1), cellComplex->getSize(0));
+	    cellComplex->getSize(1), cellComplex->getSize(0));
   Msg::StatusBar(2, false, "%d V, %d F, %d E, %d V.",
-                 cellComplex->getSize(3), cellComplex->getSize(2), 
-                 cellComplex->getSize(1), cellComplex->getSize(0));
+		 cellComplex->getSize(3), cellComplex->getSize(2), 
+		 cellComplex->getSize(1), cellComplex->getSize(0));
   return cellComplex;
 }
 
@@ -113,7 +113,7 @@ void Homology::findGenerators(CellComplex* cellComplex)
   bool ownComplex = false;
   if(cellComplex==NULL){
     cellComplex = createCellComplex(_domainEntities, 
-                                    _subdomainEntities);
+				    _subdomainEntities);
     ownComplex = true;
   }
   std::string domainString = getDomainString(_domain, _subdomain);
@@ -127,10 +127,10 @@ void Homology::findGenerators(CellComplex* cellComplex)
   Msg::Info("Cell Complex reduction complete (%g s).", t2 - t1);
   Msg::Info("%d volumes, %d faces, %d edges and %d vertices.",
             cellComplex->getSize(3), cellComplex->getSize(2), 
-            cellComplex->getSize(1), cellComplex->getSize(0));
+	    cellComplex->getSize(1), cellComplex->getSize(0));
   Msg::StatusBar(2, false, "%d V, %d F, %d E, %d N.",
-                 cellComplex->getSize(3), cellComplex->getSize(2), 
-                 cellComplex->getSize(1), cellComplex->getSize(0));
+		 cellComplex->getSize(3), cellComplex->getSize(2), 
+		 cellComplex->getSize(1), cellComplex->getSize(0));
   
   Msg::Info("Computing homology spaces...");
   Msg::StatusBar(1, false, "Computing...");
@@ -145,29 +145,33 @@ void Homology::findGenerators(CellComplex* cellComplex)
     HRank[j] = 0;
     std::string dimension = "";
     convert(j, dimension);
-    for(int i = 1; i <= chains->getBasisSize(j); i++){
+    for(int i = 1; i <= chains->getBasisSize(j, 3); i++){
       
       std::string generator = "";
       convert(i, generator);
       
       std::string name = "H" + dimension + domainString + generator;
-      std::set<Cell*, Less_Cell> cells;
+      std::map<Cell*, int, Less_Cell> protoChain;
+      chains->getBasisChain(protoChain, i, j, 3);
+      Chain* chain = new Chain(protoChain, cellComplex, _model, name, 
+			       chains->getTorsion(j,i));      
+      /* std::set<Cell*, Less_Cell> cells;
       cellComplex->getCells(cells, j);
       Chain* chain = new Chain(cells,
                                chains->getCoeffVector(j,i), cellComplex,
-                               _model, name, chains->getTorsion(j,i));
+                               _model, name, chains->getTorsion(j,i));*/
       t1 = Cpu();
       int start = chain->getSize();
       chain->smoothenChain();
       t2 = Cpu();
       Msg::Info("Smoothened H%d %d from %d cells to %d cells (%g s).", 
-                j, i, start, chain->getSize(), t2 - t1);
+		j, i, start, chain->getSize(), t2 - t1);
       if(chain->getSize() != 0) {
         HRank[j] = HRank[j] + 1;
         if(chain->getTorsion() != 1){
-          Msg::Warning("H%d %d has torsion coefficient %d!", 
-                       j, i, chain->getTorsion());
-        }
+	  Msg::Warning("H%d %d has torsion coefficient %d!", 
+		       j, i, chain->getTorsion());
+	}
       }
       _generators.push_back(chain->createPGroup());
       delete chain;
@@ -179,10 +183,10 @@ void Homology::findGenerators(CellComplex* cellComplex)
         std::string name = "H" + dimension + domainString + generator;
         std::vector<int> coeffs (cellComplex->getOmitted(i).size(),1);
         Chain* chain = new Chain(cellComplex->getOmitted(i), coeffs, 
-                                 cellComplex, _model, name, 1);
+				 cellComplex, _model, name, 1);
         if(chain->getSize() != 0) HRank[j] = HRank[j] + 1;
-        _generators.push_back(chain->createPGroup());
-        delete chain;
+	_generators.push_back(chain->createPGroup());
+	delete chain;
       }
     }
   }
@@ -201,7 +205,7 @@ void Homology::findGenerators(CellComplex* cellComplex)
   
   Msg::StatusBar(1, false, "Homology");
   Msg::StatusBar(2, false, "H0: %d, H1: %d, H2: %d, H3: %d.", 
-                 HRank[0], HRank[1], HRank[2], HRank[3]);
+		 HRank[0], HRank[1], HRank[2], HRank[3]);
 }
 
 void Homology::findDualGenerators(CellComplex* cellComplex)
@@ -209,7 +213,7 @@ void Homology::findDualGenerators(CellComplex* cellComplex)
   bool ownComplex = false;
   if(cellComplex==NULL){
     cellComplex = createCellComplex(_domainEntities, 
-                                    _subdomainEntities);
+				    _subdomainEntities);
     ownComplex = true;
   }
 
@@ -223,10 +227,10 @@ void Homology::findDualGenerators(CellComplex* cellComplex)
   Msg::Info("Cell Complex reduction complete (%g s).", t2 - t1);
   Msg::Info("%d volumes, %d faces, %d edges and %d vertices.",
             cellComplex->getSize(3), cellComplex->getSize(2), 
-            cellComplex->getSize(1), cellComplex->getSize(0));
+	    cellComplex->getSize(1), cellComplex->getSize(0));
   Msg::StatusBar(2, false, "%d V, %d F, %d E, %d N.",
-                 cellComplex->getSize(3), cellComplex->getSize(2), 
-                 cellComplex->getSize(1), cellComplex->getSize(0));
+		 cellComplex->getSize(3), cellComplex->getSize(2), 
+		 cellComplex->getSize(1), cellComplex->getSize(0));
    
   Msg::Info("Computing homology spaces...");
   Msg::StatusBar(1, false, "Computing...");
@@ -238,33 +242,37 @@ void Homology::findDualGenerators(CellComplex* cellComplex)
   Msg::Info("Homology Computation complete (%g s).", t2- t1);
   
   int dim = cellComplex->getDim();
-   
+ 
   int HRank[4];
   for(int i = 0; i < 4; i++) HRank[i] = 0;
   for(int j = 3; j > -1; j--){
     std::string dimension = "";
     convert(dim-j, dimension);
 
-    for(int i = 1; i <= chains->getBasisSize(j); i++){
+    for(int i = 1; i <= chains->getBasisSize(j, 3); i++){
       
       std::string generator = "";
       convert(i, generator);
       
       std::string name = "H" + dimension + "*" + 
-        getDomainString(_domain, _subdomain) + generator;
-      std::set<Cell*, Less_Cell> cells;
+	getDomainString(_domain, _subdomain) + generator;
+      std::map<Cell*, int, Less_Cell> protoChain;
+      chains->getBasisChain(protoChain, i, j, 3);
+      Chain* chain = new Chain(protoChain, cellComplex, _model, name, 
+			       chains->getTorsion(j,i));
+      /*std::set<Cell*, Less_Cell> cells;
       cellComplex->getCells(cells, j);
       Chain* chain = new Chain(cells, 
-                               chains->getCoeffVector(j,i), cellComplex, 
-                               _model, name, chains->getTorsion(j,i));
+      chains->getCoeffVector(j,i), cellComplex, 
+      _model, name, chains->getTorsion(j,i));*/
       _generators.push_back(chain->createPGroup());
       delete chain;
       if(chain->getSize() != 0){
         HRank[dim-j] = HRank[dim-j] + 1;
         if(chain->getTorsion() != 1){ 
-          Msg::Warning("H%d* %d has torsion coefficient %d!", 
-                       dim-j, i, chain->getTorsion());
-        }
+	  Msg::Warning("H%d* %d has torsion coefficient %d!", 
+		       dim-j, i, chain->getTorsion());
+	}
       }     
     }
     
@@ -274,14 +282,14 @@ void Homology::findDualGenerators(CellComplex* cellComplex)
         std::string generator;
         convert(i+1, generator);
         std::string name 
-          = "H" + dimension + "*" + 
-          getDomainString(_domain, _subdomain) + generator;
+	  = "H" + dimension + "*" + 
+	  getDomainString(_domain, _subdomain) + generator;
         std::vector<int> coeffs (cellComplex->getOmitted(i).size(),1);
         Chain* chain = new Chain(cellComplex->getOmitted(i), coeffs, 
-                                 cellComplex, _model, name, 1);
+				 cellComplex, _model, name, 1);
         if(chain->getSize() != 0) HRank[dim-j] = HRank[dim-j] + 1;
-        _generators.push_back(chain->createPGroup());
-        delete chain;
+	_generators.push_back(chain->createPGroup());
+	delete chain;
       }
     }
   }
@@ -300,12 +308,12 @@ void Homology::findDualGenerators(CellComplex* cellComplex)
   
   Msg::StatusBar(1, false, "Homology");
   Msg::StatusBar(2, false, "H0*: %d, H1*: %d, H2*: %d, H3*: %d.", 
-                 HRank[0], HRank[1], HRank[2], HRank[3]);
+		 HRank[0], HRank[1], HRank[2], HRank[3]);
 }
 
 void Homology::findHomSequence(){
   CellComplex* cellComplex = createCellComplex(_domainEntities, 
-                                               _subdomainEntities);
+					       _subdomainEntities);
   Msg::Info("Reducing the Cell Complex...");
   Msg::StatusBar(1, false, "Reducing...");
 
@@ -316,58 +324,79 @@ void Homology::findHomSequence(){
   Msg::Info("Cell Complex reduction complete (%g s).", t2 - t1);
   Msg::Info("%d volumes, %d faces, %d edges and %d vertices.",
             cellComplex->getSize(3), cellComplex->getSize(2), 
-            cellComplex->getSize(1), cellComplex->getSize(0));
+	    cellComplex->getSize(1), cellComplex->getSize(0));
   Msg::StatusBar(2, false, "%d V, %d F, %d E, %d N.",
-                 cellComplex->getSize(3), cellComplex->getSize(2), 
-                 cellComplex->getSize(1), cellComplex->getSize(0));
+		 cellComplex->getSize(3), cellComplex->getSize(2), 
+		 cellComplex->getSize(1), cellComplex->getSize(0));
   
   Msg::Info("Computing homology spaces...");
   Msg::StatusBar(1, false, "Computing...");
   t1 = Cpu();
   
+  ChainComplex* subcomplex = new ChainComplex(cellComplex, 2);
+  ChainComplex* complex = new ChainComplex(cellComplex, 1);
+  ChainComplex* relcomplex = new ChainComplex(cellComplex, 0);
+
+  subcomplex->computeHomology();
+  complex->computeHomology();
+  relcomplex->computeHomology();  
+
+  t2 = Cpu();
+  Msg::Info("Homology computation complete (%g s).", t2 - t1);
+
+  Msg::Info("Computing homology sequence...");
+  HomologySequence* seq = new HomologySequence(subcomplex, 
+					       complex, relcomplex);
+  t1 = Cpu();
+  Msg::Info("Homology sequence computation complete (%g s).", t1 - t2);
+  
   for(int task = 0; task < 3; task++){
-    ChainComplex* chains = new ChainComplex(cellComplex, task);
+    ChainComplex* chains;
+
     std::string domainString = "";
     std::vector<int> empty;
-    if(task == 0) domainString = getDomainString(_domain, _subdomain);
-    else if(task == 1) domainString = getDomainString(_domain, empty);
-    else if(task == 2) domainString = getDomainString(_subdomain, empty);
-    chains->computeHomology();
-    t2 = Cpu();
-    Msg::Info("Homology Computation complete (%g s).", t2 - t1);
+    if(task == 0) {
+      chains = subcomplex;
+      domainString = getDomainString(_subdomain, empty);
+    }
+    else if(task == 1) {
+      chains = complex;
+      domainString = getDomainString(_domain, empty);
+    }
+    else{
+      chains = relcomplex;
+      domainString = getDomainString(_domain, _subdomain);
+    }
     
     int HRank[4];
     for(int j = 0; j < 4; j++){
       HRank[j] = 0;
       std::string dimension = "";
       convert(j, dimension);
-      for(int i = 1; i <= chains->getBasisSize(j); i++){
-        
-        std::string generator = "";
-        convert(i, generator);
+      for(int i = 1; i <= chains->getBasisSize(j, 3); i++){
+	
+	std::string generator = "";
+	convert(i, generator);
       
-        std::string name = "H" + dimension + domainString + generator;
-        std::set<Cell*, Less_Cell> cells;
-        cellComplex->getCells(cells, j, task);
-        Chain* chain = new Chain(cells, 
-                                 chains->getCoeffVector(j,i), 
-                                 cellComplex, _model, name, 
-                                 chains->getTorsion(j,i));
-        t1 = Cpu();
-        int start = chain->getSize();
-        //chain->smoothenChain();
-        t2 = Cpu();
-        //Msg::Info("Smoothened H%d %d from %d cells to %d cells (%g s).", 
-        //        j, i, start, chain->getSize(), t2 - t1);
-        if(chain->getSize() != 0) {
-          HRank[j] = HRank[j] + 1;
-          if(chain->getTorsion() != 1){
-          Msg::Warning("H%d %d has torsion coefficient %d!", 
-                       j, i, chain->getTorsion());
-          }
-        }
-        _generators.push_back(chain->createPGroup());
-        delete chain;
+	std::string name = "H" + dimension + domainString + generator;
+	std::map<Cell*, int, Less_Cell> protoChain;
+	chains->getBasisChain(protoChain, i, j, 3);
+	Chain* chain = new Chain(protoChain, cellComplex, _model, name, 
+				 chains->getTorsion(j,i));
+	if(chain->getSize() == 0) continue;
+	t1 = Cpu();
+	int start = chain->getSize();
+	//chain->smoothenChain();
+	t2 = Cpu();
+	//Msg::Info("Smoothened H%d %d from %d cells to %d cells (%g s).", 
+	//	  j, i, start, chain->getSize(), t2 - t1);
+	HRank[j] = HRank[j] + 1;
+	if(chain->getTorsion() != 1){
+	  Msg::Warning("H%d %d has torsion coefficient %d!", 
+		       j, i, chain->getTorsion());
+	}
+	_generators.push_back(chain->createPGroup());
+	delete chain;
       }
       
     }
@@ -387,16 +416,19 @@ void Homology::findHomSequence(){
 
     Msg::StatusBar(1, false, "Homology");
     Msg::StatusBar(2, false, "H0: %d, H1: %d, H2: %d, H3: %d.",
-                   HRank[0], HRank[1], HRank[2], HRank[3]);
-    delete chains;
+		   HRank[0], HRank[1], HRank[2], HRank[3]);
   }
 
+  delete subcomplex;
+  delete complex;
+  delete relcomplex;
+
   if(_fileName != "") writeGeneratorsMSH();
   delete cellComplex;
 }
 
 std::string Homology::getDomainString(const std::vector<int>& domain,
-                                      const std::vector<int>& subdomain) 
+				      const std::vector<int>& subdomain) 
 {
   std::string domainString = "({";
   if(domain.empty()) domainString += "0";
@@ -406,7 +438,7 @@ std::string Homology::getDomainString(const std::vector<int>& domain,
       convert(domain.at(i),temp);
       domainString += temp;
       if (domain.size()-1 > i){ 
-        domainString += ", ";
+	domainString += ", ";
       }
     }
   }
@@ -436,8 +468,8 @@ bool Homology::writeGeneratorsMSH(bool binary)
   return true;
 }
 Chain::Chain(std::set<Cell*, Less_Cell> cells, std::vector<int> coeffs, 
-             CellComplex* cellComplex, GModel* model,
-             std::string name, int torsion)
+	     CellComplex* cellComplex, GModel* model,
+	     std::string name, int torsion)
 {  
   int i = 0;
   for(std::set<Cell*, Less_Cell>::iterator cit = cells.begin();
@@ -447,7 +479,7 @@ Chain::Chain(std::set<Cell*, Less_Cell> cells, std::vector<int> coeffs,
     if((int)coeffs.size() > i){
       if(coeffs.at(i) != 0){
         std::map<Cell*, int, Less_Cell > subCells;
-        cell->getCells(subCells);
+	cell->getCells(subCells);
         for(Cell::citer it = subCells.begin(); it != subCells.end(); it++){
           Cell* subCell = (*it).first;
           int coeff = (*it).second;
@@ -502,8 +534,8 @@ void Homology::storeCells(CellComplex* cellComplex, int dim)
 }
 
 Chain::Chain(std::map<Cell*, int, Less_Cell>& chain, 
-             CellComplex* cellComplex, GModel* model,
-             std::string name, int torsion)
+	     CellComplex* cellComplex, GModel* model,
+	     std::string name, int torsion)
 {  
   _cells = chain;
   if(!_cells.empty()) _dim = firstCell()->first->getDim();
@@ -516,7 +548,7 @@ Chain::Chain(std::map<Cell*, int, Less_Cell>& chain,
 }
 
 bool Chain::deform(std::map<Cell*, int, Less_Cell>& cellsInChain, 
-                   std::map<Cell*, int, Less_Cell>& cellsNotInChain)
+		   std::map<Cell*, int, Less_Cell>& cellsNotInChain)
 {
   std::vector<int> cc;
   std::vector<int> bc;
@@ -565,12 +597,12 @@ bool Chain::deformChain(std::pair<Cell*, int> cell, bool bend)
     Cell* c1CbdCell = (*cit).first;
 
     for(citer cit2 = c1CbdCell->firstBoundary(true);
-        cit2 != c1CbdCell->lastBoundary(true); cit2++){
+	cit2 != c1CbdCell->lastBoundary(true); cit2++){
       Cell* c1CbdBdCell = (*cit2).first;
       int coeff = (*cit2).second;
       if( (hasCell(c1CbdBdCell) && getCoeff(c1CbdBdCell) != 0) 
-          || c1CbdBdCell->inSubdomain()){
-        cellsInChain.insert(std::make_pair(c1CbdBdCell, coeff));
+	  || c1CbdBdCell->inSubdomain()){
+	cellsInChain.insert(std::make_pair(c1CbdBdCell, coeff));
       }
       else cellsNotInChain.insert(std::make_pair(c1CbdBdCell, coeff));
     }
@@ -586,30 +618,30 @@ bool Chain::deformChain(std::pair<Cell*, int> cell, bool bend)
     }
     
     for(citer cit2 = cellsNotInChain.begin(); cit2 != cellsNotInChain.end();
-        cit2++){
+	cit2++){
       Cell* c = (*cit2).first;
       if(c->inSubdomain()) next = true;
     }    
     if(next) continue;
     
     if( (getDim() == 1 && cellsInChain.size() == 2 
-         && cellsNotInChain.size() == 1) || 
-        (getDim() == 2 && cellsInChain.size() == 3 
-         && cellsNotInChain.size() == 1)){
+	 && cellsNotInChain.size() == 1) || 
+	(getDim() == 2 && cellsInChain.size() == 3 
+	 && cellsNotInChain.size() == 1)){
       //printf("straighten \n");
       return deform(cellsInChain, cellsNotInChain);
     }
     else if ( (getDim() == 1 && cellsInChain.size() == 1 
-               && cellsNotInChain.size() == 2 && bend) ||
+	       && cellsNotInChain.size() == 2 && bend) ||
               (getDim() == 2 && cellsInChain.size() == 2 
-               && cellsNotInChain.size() == 2 && bend)){
+	       && cellsNotInChain.size() == 2 && bend)){
       //printf("bend \n");
       return deform(cellsInChain, cellsNotInChain);
     }
     else if ((getDim() == 1 && cellsInChain.size() == 3 
-              && cellsNotInChain.size() == 0) ||
+	      && cellsNotInChain.size() == 0) ||
              (getDim() == 2 && cellsInChain.size() == 4 
-              && cellsNotInChain.size() == 0)){
+	      && cellsNotInChain.size() == 0)){
       //printf("remove boundary \n");
       return deform(cellsInChain, cellsNotInChain);
     }
@@ -648,7 +680,7 @@ void Chain::smoothenChain()
   eraseNullCells();
   double t2 = Cpu();
   Msg::Debug("Smoothened a %d-chain from %d cells to %d cells (%g s).\n",
-             getDim(), start, getSize(), t2-t1);
+	     getDim(), start, getSize(), t2-t1);
   return;
 }
 
@@ -747,7 +779,7 @@ int Chain::createPGroup()
     
     // create PView for visualization
     PView* chain = new PView(getName(), "ElementData", getGModel(), 
-                             data, 0, 1);
+			     data, 0, 1);
   }
    
   return physicalNum;
diff --git a/Geo/Homology.h b/Geo/Homology.h
index 9bd285f598362c063d9e5a637b934548e096957b..2f7298ea0cef021627cee8d4f0dd3c89e1045288 100644
--- a/Geo/Homology.h
+++ b/Geo/Homology.h
@@ -33,57 +33,60 @@ class Homology
 {
  private:
   
-  // the model of the homology computation
+  // the Gmsh model for homology computation
   GModel* _model;
 
   // domain and the relative subdomain of the homology computation
+  // physical group IDs
   std::vector<int> _domain;
   std::vector<int> _subdomain;
+  // corresponding geometrical entities
   std::vector<GEntity*> _domainEntities;
   std::vector<GEntity*> _subdomainEntities;  
 
-  // physical group numbers of generator chains in model
+  // physical group numbers of resulted generator chains in model
   std::vector<int> _generators;
 
+  // file name to store the results
   std::string _fileName;
  
  public:
   
   Homology(GModel* model, std::vector<int> physicalDomain,
-           std::vector<int> physicalSubdomain);
+	   std::vector<int> physicalSubdomain);
   ~Homology();
   
-  
+  // create a cell complex from a mesh in geometrical entities of Gmsh
   CellComplex* createCellComplex(std::vector<GEntity*>& domainEntities,
-                                 std::vector<GEntity*>& subdomainEntities);
+				 std::vector<GEntity*>& subdomainEntities);
   CellComplex* createCellComplex() { 
     return createCellComplex(_domainEntities, _subdomainEntities); }
 
   void setFileName(std::string fileName) { _fileName = fileName; }
 
-  // Find the generators/duals of homology spaces,
-  // or just compute the ranks of homology spaces
+  // find the generators/dual generarators  of homology spaces,
   void findGenerators(CellComplex* cellComplex=NULL);
   void findDualGenerators(CellComplex* cellComplex=NULL);
 
-  void computeRanks() {}  
-  void findHomSequence();
 
+  // experimental
+  void findHomSequence();
+  void computeRanks() {}  
    
-  // Create a string describing the generator
+  // create a string describing the generator
   std::string getDomainString(const std::vector<int>& domain,
-                              const std::vector<int>& subdomain);
+			      const std::vector<int>& subdomain);
   
   // write the generators to a file
   bool writeGeneratorsMSH(bool binary=false);
-  // store dim-dimensional cells of cellComplex as a pshysical group
+  // store dim-dimensional cells of cellComplex as a physical group
   // in _model, for debugging
   void storeCells(CellComplex* cellComplex, int dim);
 
 };
 
 // A class representing a chain.
-// Used to visualize generators of the homology groups.
+// Used to visualize and post-process generators of the homology spaces in Gmsh.
 class Chain{
   
  private:
@@ -103,20 +106,20 @@ class Chain{
   int _dim;
   
   bool deform(std::map<Cell*, int, Less_Cell> &cellsInChain, 
-              std::map<Cell*, int, Less_Cell> &cellsNotInChain);
+	      std::map<Cell*, int, Less_Cell> &cellsNotInChain);
   bool deformChain(std::pair<Cell*, int> cell, bool bend);
   
   
  public:
   Chain() {}
   Chain(std::set<Cell*, Less_Cell> cells, std::vector<int> coeffs, 
-        CellComplex* cellComplex, GModel* model,
-        std::string name="Chain", int torsion=0);
+	CellComplex* cellComplex, GModel* model,
+	std::string name="Chain", int torsion=0);
   Chain(std::map<Cell*, int, Less_Cell>& chain,
         CellComplex* cellComplex, GModel* model,
         std::string name="Chain", int torsion=0);
   Chain(Chain* chain){ 
-    _cells = chain->getCells();
+    chain->getCells(_cells);
     _torsion = chain->getTorsion();
     _name = chain->getName();
     _cellComplex = chain->getCellComplex();
@@ -141,25 +144,26 @@ class Chain{
   int getCoeff(Cell* c);
   
   
-  int getTorsion() { return _torsion; }
-  int getDim() { return _dim; }
-  CellComplex* getCellComplex() { return _cellComplex; }
-  GModel* getGModel() { return _model; }
-  std::map<Cell*, int, Less_Cell>  getCells() { return _cells; }
+  int getTorsion() const { return _torsion; }
+  int getDim() const { return _dim; }
+  CellComplex* getCellComplex() const { return _cellComplex; }
+  GModel* getGModel() const { return _model; }
+  void getCells(std::map<Cell*, int, Less_Cell> cells) const{ cells = _cells; }
   
   // erase cells from the chain with zero coefficient
   void eraseNullCells();
-   
+
+  // set all cell in chain not immune
   void deImmuneCells();
   
   // number of cells in this chain 
-  int getSize() { return _cells.size();}
+  int getSize() const { return _cells.size();}
   
   // get/set chain name
-  std::string getName() { return _name; }
+  std::string getName() const { return _name; }
   void setName(std::string name) { _name=name; }
   // get/set physical group number
-  int getNum() { return _num; }
+  int getNum() const { return _num; }
   void setNum(int num) { _num=num; }
   
   // make local deformations to the chain to make it smoother and smaller
diff --git a/contrib/kbipack/gmp_matrix.c b/contrib/kbipack/gmp_matrix.c
index c690292c6c70a4c07757ea8a974761aae76f4938..a9a4f9eeee77aef68f069eb842ed68f63895c769 100644
--- a/contrib/kbipack/gmp_matrix.c
+++ b/contrib/kbipack/gmp_matrix.c
@@ -619,6 +619,36 @@ gmp_matrix_transp(gmp_matrix * M)
   return EXIT_SUCCESS;
 }
 
+int
+gmp_matrix_sum(gmp_matrix * A, const gmp_matrix * B)
+{
+  size_t i,j;
+  size_t rows_A, cols_A, rows_B, cols_B;
+
+  if((A == NULL) || (B == NULL))
+    {
+      return EXIT_FAILURE;
+    }
+  
+  rows_A = A->rows;
+  cols_A = A->cols;
+  rows_B = B->rows;
+  cols_B = B->cols;
+
+  if(cols_A != cols_B || rows_A != rows_B)
+    {
+      return EXIT_FAILURE;
+    }
+  mpz_t a;
+  mpz_init_set_si(a, 1);
+  /* Compute the sum */
+  for(i = 1; i <= rows_A; i++)
+    {
+    
+    }
+
+  return EXIT_SUCCESS;
+}
 
 int
 gmp_matrix_right_mult(gmp_matrix * A, const gmp_matrix * B)
diff --git a/contrib/kbipack/gmp_matrix.h b/contrib/kbipack/gmp_matrix.h
index 931f3828036a15ed73221d9d54a43cdddabeebe5..318dd85657c06d91b0bea17a99be6563d220af2d 100644
--- a/contrib/kbipack/gmp_matrix.h
+++ b/contrib/kbipack/gmp_matrix.h
@@ -127,6 +127,10 @@ gmp_matrix_row_inz (size_t r, size_t c1, size_t c2,
 int
 gmp_matrix_transp(gmp_matrix * M);
 
+/* A <- A+B */
+int
+gmp_matrix_sum(gmp_matrix * A, const gmp_matrix * B);
+
 /* A <- A*B */
 int
 gmp_matrix_right_mult(gmp_matrix * A, const gmp_matrix * B);