private boolean purgeOverlappingContexts(
     Dependency egd, Repair repair, Set<AttributeRef> affectedAttributesSoFar) {
   // Needed also for FDs due to the presence of cellgroups that can span different eq. classes,
   //  but only if some earlier dependencies has generated a cell group for this attribute
   if (affectedAttributesSoFar.isEmpty()) {
     return true;
   }
   if (logger.isDebugEnabled())
     logger.debug("Checking independence of violation contexts for egd " + egd);
   boolean consistent = true;
   Map<AttributeRef, Set<CellRef>> changedCellMap = new HashMap<AttributeRef, Set<CellRef>>();
   for (Iterator<ChangeDescription> it = repair.getChangeDescriptions().iterator();
       it.hasNext(); ) {
     ChangeDescription changeDescription = it.next();
     Set<AttributeRef> changedAttributes =
         ChaseUtility.extractAffectedAttributes(changeDescription);
     if (LunaticUtility.hasEmptyIntersection(affectedAttributesSoFar, changedAttributes)) {
       continue;
     }
     if (ChaseUtility.occurrencesOverlap(changeDescription, changedCellMap)
         || ChaseUtility.witnessOverlaps(changeDescription, changedCellMap)) {
       if (logger.isDebugEnabled())
         logger.debug("Violation context has overlaps: " + changeDescription);
       it.remove();
       consistent = false;
     } else {
       ChaseUtility.addChangedCellsToMap(
           changeDescription.getCellGroup().getOccurrences(), changedCellMap);
     }
   }
   return consistent;
 }
 @Override
 public IValue generalizeNonAuthoritativeConstantCells(
     Set<CellGroupCell> nonAuthoritativeCells, CellGroup cellGroup, Scenario scenario) {
   IValue lubValue =
       super.generalizeNonAuthoritativeConstantCells(nonAuthoritativeCells, cellGroup, scenario);
   if (lubValue instanceof LLUNValue) {
     throw new ChaseFailedException(
         "Unable to equate cells " + LunaticUtility.printCollection(nonAuthoritativeCells));
   }
   return lubValue;
 }
 private List<BackwardAttribute> findAttributesForBackwardChasing(Dependency egd) {
   List<BackwardAttribute> attributesForBackwardChasing = new ArrayList<BackwardAttribute>();
   for (FormulaVariableOccurrence backwardAttributeOccurrence : egd.getBackwardAttributes()) {
     AttributeRef occurrenceAttribute =
         EquivalenceClassUtility.correctAttributeForSymmetricEGDs(
             backwardAttributeOccurrence.getAttributeRef(), egd);
     FormulaVariable variable =
         LunaticUtility.findPremiseVariableInDepedency(backwardAttributeOccurrence, egd);
     BackwardAttribute backwardAttribute = new BackwardAttribute(occurrenceAttribute, variable);
     if (attributesForBackwardChasing.contains(backwardAttribute)) {
       continue;
     }
     attributesForBackwardChasing.add(backwardAttribute);
   }
   return attributesForBackwardChasing;
 }
 @Override
 public NewChaseSteps chaseDependency(
     DeltaChaseStep currentNode,
     Dependency egd,
     IAlgebraOperator premiseQuery,
     Scenario scenario,
     IChaseState chaseState,
     IDatabase databaseForStep) {
   if (logger.isDebugEnabled())
     logger.debug("***** Step: " + currentNode.getId() + " - Chasing dependency: " + egd);
   if (logger.isTraceEnabled()) logger.trace(databaseForStep.printInstances());
   this.lastTuple = null;
   this.lastTupleHandled = false;
   if (logger.isDebugEnabled()) logger.debug("Executing premise query: " + premiseQuery);
   if (logger.isTraceEnabled())
     logger.debug(
         "Result:\n"
             + LunaticUtility.printIterator(
                 queryRunner.run(premiseQuery, scenario.getSource(), databaseForStep)));
   long violationQueryStart = new Date().getTime();
   ITupleIterator it = queryRunner.run(premiseQuery, scenario.getSource(), databaseForStep);
   long violationQueryEnd = new Date().getTime();
   ChaseStats.getInstance()
       .addStat(ChaseStats.EGD_VIOLATION_QUERY_TIME, violationQueryEnd - violationQueryStart);
   List<Repair> repairsForDependency = new ArrayList<Repair>();
   try {
     while (true) {
       long equivalenceClassStart = new Date().getTime();
       EquivalenceClassForSymmetricEGD equivalenceClass =
           readNextEquivalenceClass(
               it, egd, currentNode.getDeltaDB(), currentNode.getId(), chaseState, scenario);
       long equivalenceClassEnd = new Date().getTime();
       ChaseStats.getInstance()
           .addStat(
               ChaseStats.EGD_EQUIVALENCE_CLASS_TIME, equivalenceClassEnd - equivalenceClassStart);
       if (equivalenceClass == null) {
         break;
       }
       ICostManager costManager = CostManagerFactory.getCostManager(egd, scenario);
       long choosingRepairStart = new Date().getTime();
       List<Repair> repairsForEquivalenceClass =
           costManager.chooseRepairStrategy(
               new EquivalenceClassForEGDProxy(equivalenceClass),
               currentNode.getRoot(),
               repairsForDependency,
               scenario,
               currentNode.getId(),
               occurrenceHandler);
       long choosingRepairEnd = new Date().getTime();
       ChaseStats.getInstance()
           .addStat(ChaseStats.EGD_CHOOSING_REPAIR_TIME, choosingRepairEnd - choosingRepairStart);
       if (logger.isDebugEnabled())
         logger.debug(
             "Repairs for equivalence class: "
                 + LunaticUtility.printCollection(repairsForEquivalenceClass));
       repairsForDependency =
           ChaseUtility.accumulateRepairs(repairsForDependency, repairsForEquivalenceClass);
       if (noMoreTuples(it)) {
         break;
       }
       if (logger.isDebugEnabled())
         logger.debug("Repairs for equivalence classes so far: " + repairsForDependency.size());
     }
   } catch (ChaseFailedException e) {
     throw e;
   } finally {
     it.close();
   }
   if (logger.isDebugEnabled())
     logger.debug(
         "Total repairs for dependency: " + LunaticUtility.printCollection(repairsForDependency));
   long repairStart = new Date().getTime();
   NewChaseSteps newSteps = applyRepairs(currentNode, repairsForDependency, egd, scenario);
   long repairEnd = new Date().getTime();
   ChaseStats.getInstance().addStat(ChaseStats.EGD_REPAIR_TIME, repairEnd - repairStart);
   return newSteps;
 }