@Override
  public AbstractState getVariableReducedState(
      AbstractState pExpandedState, Block pContext, CFANode pLocation) {

    PredicateAbstractState predicateElement = (PredicateAbstractState) pExpandedState;

    if (!predicateElement.isAbstractionState()) {
      return predicateElement;
    }

    AbstractionFormula oldAbstraction = predicateElement.getAbstractionFormula();

    Region oldRegion = oldAbstraction.asRegion();

    Collection<AbstractionPredicate> predicates = pamgr.extractPredicates(oldRegion);
    Collection<AbstractionPredicate> removePredicates =
        cpa.getRelevantPredicatesComputer().getIrrelevantPredicates(pContext, predicates);

    PathFormula pathFormula = predicateElement.getPathFormula();

    assert bfmgr.isTrue(pathFormula.getFormula());

    AbstractionFormula newAbstraction =
        pamgr.reduce(oldAbstraction, removePredicates, pathFormula.getSsa());

    PersistentMap<CFANode, Integer> abstractionLocations =
        predicateElement.getAbstractionLocationsOnPath().empty();

    return PredicateAbstractState.mkAbstractionState(
        pathFormula, newAbstraction, abstractionLocations);
  }
  /**
   * Get the predicates out of an interpolant.
   *
   * @param pInterpolant The interpolant formula.
   * @return A set of predicates.
   */
  private final Collection<AbstractionPredicate> convertInterpolant(
      final BooleanFormula pInterpolant) {

    BooleanFormula interpolant = pInterpolant;

    if (bfmgr.isTrue(interpolant)) {
      return Collections.<AbstractionPredicate>emptySet();
    }

    Collection<AbstractionPredicate> preds;

    if (atomicPredicates) {
      preds = predAbsMgr.getPredicatesForAtomsOf(interpolant);

    } else {
      preds = ImmutableList.of(predAbsMgr.getPredicateFor(interpolant));
    }

    assert !preds.isEmpty()
        : "Interpolant without relevant predicates: "
            + pInterpolant
            + "; simplified to "
            + interpolant;

    logger.log(Level.FINEST, "Got predicates", preds);

    return preds;
  }
  @Override
  public AbstractState getVariableExpandedStateForProofChecking(
      AbstractState pRootState, Block pReducedContext, AbstractState pReducedState) {

    PredicateAbstractState rootState = (PredicateAbstractState) pRootState;
    PredicateAbstractState reducedState = (PredicateAbstractState) pReducedState;

    if (!reducedState.isAbstractionState()) {
      return reducedState;
    }

    AbstractionFormula rootAbstraction = rootState.getAbstractionFormula();
    AbstractionFormula reducedAbstraction = reducedState.getAbstractionFormula();

    // create region predicates for every atom in formula
    pamgr.extractPredicates(reducedAbstraction.asInstantiatedFormula());

    Collection<AbstractionPredicate> rootPredicates =
        pamgr.extractPredicates(rootAbstraction.asInstantiatedFormula());
    Collection<AbstractionPredicate> relevantRootPredicates =
        cpa.getRelevantPredicatesComputer().getRelevantPredicates(pReducedContext, rootPredicates);
    // for each removed predicate, we have to lookup the old (expanded) value and insert it to the
    // reducedStates region

    PathFormula oldPathFormula = reducedState.getPathFormula();
    SSAMap oldSSA = oldPathFormula.getSsa();

    // pathFormula.getSSa() might not contain index for the newly added variables in predicates;
    // while the actual index is not really important at this point,
    // there still should be at least _some_ index for each variable of the abstraction formula.
    SSAMapBuilder builder = oldSSA.builder();
    SSAMap rootSSA = rootState.getPathFormula().getSsa();
    for (String var : rootSSA.allVariables()) {
      // if we do not have the index in the reduced map..
      if (!oldSSA.containsVariable(var)) {
        // add an index (with the value of rootSSA)
        builder.setIndex(var, rootSSA.getType(var), rootSSA.getIndex(var));
      }
    }
    SSAMap newSSA = builder.build();
    PathFormula newPathFormula = pmgr.makeNewPathFormula(pmgr.makeEmptyPathFormula(), newSSA);

    Region reducedRegion = pamgr.buildRegionFromFormula(reducedAbstraction.asFormula());
    Region rootRegion = pamgr.buildRegionFromFormula(rootAbstraction.asFormula());

    AbstractionFormula newAbstractionFormula =
        pamgr.expand(
            reducedRegion,
            rootRegion,
            relevantRootPredicates,
            newSSA,
            reducedAbstraction.getBlockFormula());

    PersistentMap<CFANode, Integer> abstractionLocations =
        rootState.getAbstractionLocationsOnPath();

    return PredicateAbstractState.mkAbstractionState(
        newPathFormula, newAbstractionFormula, abstractionLocations);
  }
  /**
   * After a path was strengthened, we need to take care of the coverage relation. We also remove
   * the infeasible part from the ARG, and re-establish the coverage invariant (i.e., that states on
   * the path are either covered or cannot be covered).
   */
  @Override
  protected void finishRefinementOfPath(
      ARGState infeasiblePartOfART,
      List<ARGState> changedElements,
      ARGReachedSet pReached,
      boolean pRepeatedCounterexample)
      throws CPAException, InterruptedException {
    // only thing to do here is adding the false predicate for unreacheable states
    newPredicates.put(extractLocation(infeasiblePartOfART), predAbsMgr.makeFalsePredicate());
    changedElements.add(infeasiblePartOfART);

    if (restartAfterRefinement) {
      refinementRoot = (ARGState) reached.asReachedSet().getFirstState();

    } else if (refinementRoot == null) {
      refinementRoot = changedElements.get(0);

      // search parent of both refinement roots and use this as the new
      // refinement root
    } else {
      PathIterator firstPath = ARGUtils.getOnePathTo(refinementRoot).pathIterator();
      PathIterator secondPath = ARGUtils.getOnePathTo(changedElements.get(0)).pathIterator();

      // TODO should they be equal or identical?
      while (firstPath.getAbstractState().equals(secondPath.getAbstractState())) {
        refinementRoot = firstPath.getAbstractState();

        if (firstPath.hasNext() && secondPath.hasNext()) {
          firstPath.advance();
          secondPath.advance();
        } else {
          break;
        }
      }
    }
  }
 @Override
 protected void startRefinementOfPath() {
   checkState(lastAbstraction == null);
   lastAbstraction = predAbsMgr.makeTrueAbstractionFormula(null);
 }