@Override
  public AbstractState strengthen(
      AbstractState s, Iterable<AbstractState> otherStates, CFAEdge cfaEdge, Precision precision) {

    ValuationState state = (ValuationState) s;
    ValuationState strengthenedState = null;

    for (AbstractState t : otherStates) {
      // TODO: Does not work correctly if BoundedAddressTracking returns more than
      // 		 one successor state.
      if (t instanceof BasedNumberValuation) {
        BasedNumberValuation exState = (BasedNumberValuation) t;
        for (Map.Entry<RTLVariable, BasedNumberElement> entry : exState.getVariableValuation()) {
          RTLVariable var = entry.getKey();
          BasedNumberElement exVal = entry.getValue();
          if (exVal.isTop() || exVal.isNumberTop()) continue;
          if (state.getVariableValue(var).isTop()) {
            if (strengthenedState == null) {
              strengthenedState = new ValuationState(state);
            }
            strengthenedState.setVariableValue(
                var, new IntervalElement(exVal.getRegion(), exVal.getNumber()));
            // logger.debug("Strengthened state " + state.getIdentifier() +
            //		" by setting " + var + " to " + state.getValue(var));
          }
        }
      }
    }

    return strengthenedState == null ? state : strengthenedState;
  }
  /*
   * @see org.jakstab.analysis.ConfigurableProgramAnalysis#merge(org.jakstab.analysis.AbstractState, org.jakstab.analysis.AbstractState)
   */
  @Override
  public AbstractState merge(AbstractState s1, AbstractState s2, Precision precision) {

    // Widen s2 towards s1.
    // return ((IntervalState)s2).widen((IntervalState)s1);

    if (s2.isTop() || s1.isBot()) return s2;
    if (s1.isTop()) return s1;

    ValuationState current = (ValuationState) s2;
    ValuationState towards = (ValuationState) s1;

    ValuationState widenedState = new ValuationState(valueFactory);
    // Widen variable valuations
    for (Iterator<Map.Entry<RTLVariable, AbstractDomainElement>> entryIt =
            current.variableIterator();
        entryIt.hasNext(); ) {
      Map.Entry<RTLVariable, AbstractDomainElement> entry = entryIt.next();
      RTLVariable var = entry.getKey();
      IntervalElement v = (IntervalElement) entry.getValue();
      widenedState.setVariableValue(var, v.widen((IntervalElement) towards.getVariableValue(var)));
    }

    // Widen memory
    for (EntryIterator<MemoryRegion, Long, AbstractDomainElement> entryIt = current.storeIterator();
        entryIt.hasEntry();
        entryIt.next()) {
      MemoryRegion region = entryIt.getLeftKey();
      Long offset = entryIt.getRightKey();
      IntervalElement v = (IntervalElement) entryIt.getValue();
      int bitWidth = v.getBitWidth();
      widenedState.setMemoryValue(
          region,
          offset,
          bitWidth,
          v.widen((IntervalElement) towards.getMemoryValue(region, offset, bitWidth)));
    }

    return widenedState;
  }
  public RTLExpression getStateFormula(ValuationState state) {
    RTLExpression result = null;

    for (Iterator<Map.Entry<RTLVariable, AbstractDomainElement>> entryIt = state.variableIterator();
        entryIt.hasNext(); ) {
      Map.Entry<RTLVariable, AbstractDomainElement> entry = entryIt.next();
      RTLVariable var = entry.getKey();
      IntervalElement interval = (IntervalElement) entry.getValue();

      if (interval.size() == 1) {
        result =
            addClause(
                result,
                ExpressionFactory.createEqual(
                    var, ExpressionFactory.createNumber(interval.getLeft(), var.getBitWidth())));
      } else {
        if (!interval.leftOpen()) {
          result =
              addClause(
                  result,
                  ExpressionFactory.createLessOrEqual(
                      ExpressionFactory.createNumber(interval.getLeft(), var.getBitWidth()), var));
        }

        if (!interval.rightOpen()) {
          result =
              addClause(
                  result,
                  ExpressionFactory.createLessOrEqual(
                      var, ExpressionFactory.createNumber(interval.getRight(), var.getBitWidth())));
        }
      }
    }

    if (result == null) {
      result = ExpressionFactory.TRUE;
    }

    return result;
  }