private void addTuple(
     Tuple tuple,
     EquivalenceClassForSymmetricEGD equivalenceClass,
     CostManagerConfiguration costManagerConfiguration,
     IDatabase deltaDB,
     String stepId,
     Scenario scenario) {
   if (logger.isDebugEnabled())
     logger.trace("Adding tuple " + tuple + " to equivalence class: " + equivalenceClass);
   AttributeRef conclusionAttribute = equivalenceClass.getConclusionAttribute();
   Cell cellToChangeForForwardChasing = tuple.getCell(conclusionAttribute);
   if (logger.isDebugEnabled())
     logger.trace(
         "Attribute: " + conclusionAttribute + " - Cell: " + cellToChangeForForwardChasing);
   IValue conclusionValue = cellToChangeForForwardChasing.getValue();
   TupleOID originalOid = new TupleOID(ChaseUtility.getOriginalOid(tuple, conclusionAttribute));
   CellRef cellRef = new CellRef(originalOid, ChaseUtility.unAlias(conclusionAttribute));
   CellGroupCell targetCell =
       new CellGroupCell(cellRef, conclusionValue, null, LunaticConstants.TYPE_OCCURRENCE, null);
   CellGroup forwardCellGroup = new CellGroup(conclusionValue, true);
   forwardCellGroup.addOccurrenceCell(targetCell);
   addAdditionalAttributes(forwardCellGroup, originalOid, tuple, equivalenceClass.getEGD());
   CellGroup enrichedCellGroup =
       this.occurrenceHandler.enrichCellGroups(forwardCellGroup, deltaDB, stepId, scenario);
   EGDEquivalenceClassTuple tupleCells = new EGDEquivalenceClassTuple(enrichedCellGroup);
   for (BackwardAttribute backwardAttribute :
       equivalenceClass.getAttributesToChangeForBackwardChasing()) {
     AttributeRef attributeForBackwardChasing = backwardAttribute.getAttributeRef();
     Cell cellForBackward = tuple.getCell(attributeForBackwardChasing);
     TupleOID tupleOid =
         new TupleOID(ChaseUtility.getOriginalOid(tuple, attributeForBackwardChasing));
     Cell backwardCell =
         new Cell(
             tupleOid,
             ChaseUtility.unAlias(attributeForBackwardChasing),
             cellForBackward.getValue());
     IValue value = backwardCell.getValue();
     CellGroup backwardCellGroup = new CellGroup(value, true);
     backwardCellGroup.addOccurrenceCell(
         new CellGroupCell(backwardCell, null, LunaticConstants.TYPE_OCCURRENCE, null));
     CellGroup enrichedBackwardCellGroup =
         this.occurrenceHandler.enrichCellGroups(backwardCellGroup, deltaDB, stepId, scenario);
     tupleCells.setCellGroupForBackwardAttribute(backwardAttribute, enrichedBackwardCellGroup);
   }
   equivalenceClass.addTupleCells(tupleCells);
   equivalenceClass.addTupleCellsForValue(conclusionValue, tupleCells);
   if (costManagerConfiguration.isDoBackwardOnDependency(equivalenceClass.getEGD())) {
     indexCells(tupleCells, equivalenceClass);
   }
   if (logger.isDebugEnabled()) logger.trace("Equivalence class: " + equivalenceClass);
 }
 private void indexCells(
     EGDEquivalenceClassTuple tupleCells, EquivalenceClassForSymmetricEGD equivalenceClass) {
   for (Cell cell : tupleCells.getAllCells()) {
     equivalenceClass.indexTupleCellsForCell(cell, tupleCells);
   }
 }
 private EquivalenceClassForSymmetricEGD readNextEquivalenceClass(
     ITupleIterator it,
     Dependency egd,
     IDatabase deltaDB,
     String stepId,
     IChaseState chaseState,
     Scenario scenario) {
   if (!it.hasNext() && (this.lastTupleHandled || this.lastTuple == null)) {
     return null;
   }
   EquivalenceClassForSymmetricEGD equivalenceClass = createEquivalenceClass(egd);
   if (lastTuple != null && !this.lastTupleHandled) {
     if (logger.isDebugEnabled())
       logger.debug("Reading tuple : " + this.lastTuple.toStringWithOIDAndAlias());
     addTuple(
         this.lastTuple,
         equivalenceClass,
         scenario.getCostManagerConfiguration(),
         deltaDB,
         stepId,
         scenario);
     this.lastTupleHandled = true;
   }
   if (logger.isDebugEnabled()) logger.debug("Reading next equivalence class...");
   while (it.hasNext()) {
     if (chaseState.isCancelled())
       ChaseUtility.stopChase(
           chaseState); // throw new ChaseException("Chase interrupted by user");
     Tuple tuple = it.next();
     if (logger.isDebugEnabled())
       logger.debug("Reading tuple : " + tuple.toStringWithOIDAndAlias());
     if (lastTuple == null
         || equivalenceClass.isEmpty()
         || EquivalenceClassUtility.sameEquivalenceClass(tuple, this.lastTuple, egd)) {
       addTuple(
           tuple,
           equivalenceClass,
           scenario.getCostManagerConfiguration(),
           deltaDB,
           stepId,
           scenario);
       this.lastTuple = tuple;
       this.lastTupleHandled = true;
     } else {
       if (logger.isDebugEnabled()) logger.debug("Equivalence class is finished...");
       if (equivalenceClass.isEmpty()) {
         throw new IllegalArgumentException(
             "Unable to create equivalence class for egd:\n"
                 + egd
                 + "\nLast tuple: \n"
                 + lastTuple
                 + "\nCurrent tuple: \n"
                 + tuple);
       }
       this.lastTuple = tuple;
       this.lastTupleHandled = false;
       break;
     }
   }
   if (logger.isDebugEnabled()) logger.debug("Equivalence class loaded");
   if (logger.isDebugEnabled())
     logger.debug("-------- Equivalence class:\n" + equivalenceClass + "\n---------------");
   return equivalenceClass;
 }