private Iterable<AbstractState> getWrappedStates(ARGState wrapper) {
   if (wrapper.getWrappedState() instanceof AbstractWrapperState) {
     return ((AbstractWrapperState) wrapper.getWrappedState()).getWrappedStates();
   } else {
     return Collections.singleton(wrapper.getWrappedState());
   }
 }
  /** This method builds an actual tree from multiple path. */
  private ARGState buildTreeFromMultiplePaths(final Collection<ARGPath> targetPaths) {
    ARGState itpTreeRoot = null;
    Deque<ARGState> todo = new ArrayDeque<>(extractTargets(targetPaths));

    // build the tree, bottom-up, starting from the target states
    while (!todo.isEmpty()) {
      final ARGState currentState = todo.removeFirst();

      if (currentState.getParents().iterator().hasNext()) {

        if (!predecessorRelation.containsKey(currentState)) {
          ARGState parentState = currentState.getParents().iterator().next();

          predecessorRelation.put(currentState, parentState);
          successorRelation.put(parentState, currentState);

          todo.addFirst(parentState);
        }

      } else if (itpTreeRoot == null) {
        itpTreeRoot = currentState;
      }
    }

    return itpTreeRoot;
  }
    @Override
    public ARGPath getNextPathForInterpolation() {
      ARGState current = sources.remove(0);

      assert current.isTarget() : "current element is not a target";

      ARGPathBuilder errorPathBuilder = ARGPath.reverseBuilder();

      errorPathBuilder.add(
          current, FluentIterable.from(AbstractStates.getOutgoingEdges(current)).first().orNull());

      while (predecessorRelation.get(current) != null) {

        ARGState parent = predecessorRelation.get(current);

        if (stateHasFalseInterpolant(parent)) {
          logger.log(
              Level.FINEST,
              "interpolant on path, namely for state ",
              parent.getStateId(),
              " is already false, so return empty path");
          return EMPTY_PATH;
        }

        if (predecessorRelation.get(parent) != null) {
          errorPathBuilder.add(parent, parent.getEdgeToChild(current));
        }

        current = parent;
      }

      return errorPathBuilder.build(current);
    }
  private Collection<Edge> getRelevantChildrenOfState(
      ARGState currentElement, Stack<FunctionBody> functionStack, Set<ARGState> elementsOnPath) {
    // find the next elements to add to the waitlist

    List<ARGState> relevantChildrenOfElement =
        from(currentElement.getChildren()).filter(in(elementsOnPath)).toList();
    relevantChildrenOfElement = chooseIfArbitrary(currentElement, relevantChildrenOfElement);

    // if there is only one child on the path
    if (relevantChildrenOfElement.size() == 1) {
      // get the next ARG state, create a new edge using the same stack and add it to the waitlist
      ARGState elem = Iterables.getOnlyElement(relevantChildrenOfElement);
      CFAEdge e = currentElement.getEdgeToChild(elem);
      Edge newEdge = new Edge(elem, currentElement, e, functionStack);
      return Collections.singleton(newEdge);

    } else if (relevantChildrenOfElement.size() > 1) {
      // if there are more than one relevant child, then this is a condition
      // we need to update the stack
      assert relevantChildrenOfElement.size() == 2;
      Collection<Edge> result = new ArrayList<>(2);
      int ind = 0;
      for (ARGState elem : relevantChildrenOfElement) {
        Stack<FunctionBody> newStack = cloneStack(functionStack);
        CFAEdge e = currentElement.getEdgeToChild(elem);
        FunctionBody currentFunction = newStack.peek();
        assert e instanceof CAssumeEdge;
        CAssumeEdge assumeEdge = (CAssumeEdge) e;
        boolean truthAssumption = assumeEdge.getTruthAssumption();

        String cond = "";

        if (ind == 0) {
          cond = "if ";
        } else if (ind == 1) {
          cond = "else if ";
        } else {
          throw new AssertionError();
        }
        ind++;

        if (truthAssumption) {
          cond += "(" + assumeEdge.getExpression().toASTString() + ")";
        } else {
          cond += "(!(" + assumeEdge.getExpression().toASTString() + "))";
        }

        // create a new block starting with this condition
        currentFunction.enterBlock(currentElement.getStateId(), assumeEdge, cond);

        Edge newEdge = new Edge(elem, currentElement, e, newStack);
        result.add(newEdge);
      }
      return result;
    }
    return Collections.emptyList();
  }
 private Collection<ARGState> getNonCoveredStatesInSubgraph(ARGState pRoot) {
   Collection<ARGState> subgraph = new HashSet<>();
   for (ARGState state : pRoot.getSubgraph()) {
     if (!state.isCovered()) {
       subgraph.add(state);
     }
   }
   return subgraph;
 }
  protected boolean checkCertificate(
      ReachedSet pReachedSet, ARGState pRoot, @Nullable List<ARGState> incompleteStates)
      throws CPAException, InterruptedException {
    // TODO does not account for strengthen yet (proof check will fail if strengthen is needed to
    // explain successor states)
    initChecking(pRoot);

    logger.log(Level.INFO, "Proof check algorithm started");

    ARGState initialState = (ARGState) pReachedSet.popFromWaitlist();
    Precision initialPrecision = pReachedSet.getPrecision(initialState);

    logger.log(Level.FINE, "Checking root state");

    if (!checkCovering(initialState, pRoot, initialPrecision)) {
      return false;
    }

    pReachedSet.add(pRoot, initialPrecision);

    do {

      if (!prepareNextWaitlistIteration(pReachedSet)) {
        return false;
      }

      while (pReachedSet.hasWaitingState()) {
        shutdownNotifier.shutdownIfNecessary();

        stats.increaseIteration();
        ARGState state = (ARGState) pReachedSet.popFromWaitlist();

        logger.log(Level.FINE, "Looking at state", state);

        if (!checkForStatePropertyAndOtherStateActions(state)) {
          logger.log(Level.INFO, "Property violation at state", state);
          return false;
        }

        if (state.isCovered()) {
          if (!checkCoveredStates(state, pReachedSet, initialPrecision)) {
            return false;
          }
        } else {
          if (!checkAndAddSuccessors(state, pReachedSet, initialPrecision, incompleteStates)) {
            return false;
          }
        }
      }
    } while (!isCheckComplete());

    stats.increaseProofSize(pReachedSet.size() - 1);
    return isCheckSuccessful();
  }
 private boolean isCoveringCycleFree(ARGState pState) {
   HashSet<ARGState> seen = new HashSet<>();
   seen.add(pState);
   while (pState.isCovered()) {
     pState = pState.getCoveringState();
     boolean isNew = seen.add(pState);
     if (!isNew) {
       return false;
     }
   }
   return true;
 }
    @Override
    public ARGPath getNextPathForInterpolation() {
      ARGPathBuilder errorPathBuilder = ARGPath.builder();

      ARGState current = sources.pop();

      if (!isValidInterpolationRoot(predecessorRelation.get(current))) {
        logger.log(
            Level.FINEST,
            "interpolant of predecessor of ",
            current.getStateId(),
            " is already false, so return empty path");
        return EMPTY_PATH;
      }

      // if the current state is not the root, it is a child of a branch , however, the path should
      // not start with the
      // child, but with the branching node (children are stored on the stack because this needs
      // less book-keeping)
      if (current != root) {
        errorPathBuilder.add(
            predecessorRelation.get(current),
            predecessorRelation.get(current).getEdgeToChild(current));
      }

      while (successorRelation.get(current).iterator().hasNext()) {
        Iterator<ARGState> children = successorRelation.get(current).iterator();
        ARGState child = children.next();
        errorPathBuilder.add(current, current.getEdgeToChild(child));

        // push all other children of the current state, if any, onto the stack for later
        // interpolations
        int size = 1;
        while (children.hasNext()) {
          size++;
          ARGState sibling = children.next();
          logger.log(
              Level.FINEST,
              "\tpush new root ",
              sibling.getStateId(),
              " onto stack for parent ",
              predecessorRelation.get(sibling).getStateId());
          sources.push(sibling);
        }
        assert (size <= 2);

        current = child;
      }

      return errorPathBuilder.build(current);
    }
 private List<ARGState> chooseIfArbitrary(
     ARGState parent, List<ARGState> pRelevantChildrenOfElement) {
   if (pRelevantChildrenOfElement.size() <= 1) {
     return pRelevantChildrenOfElement;
   }
   List<ARGState> result = new ArrayList<>(2);
   for (ARGState candidate : pRelevantChildrenOfElement) {
     boolean valid = true;
     if (!result.isEmpty()) {
       Set<ARGState> candidateParents = ImmutableSet.copyOf(candidate.getParents());
       Set<ARGState> candidateChildren = ImmutableSet.copyOf(candidate.getChildren());
       for (ARGState chosen : result) {
         if (parent.getEdgesToChild(chosen).equals(parent.getEdgesToChild(candidate))) {
           Set<ARGState> chosenParents = ImmutableSet.copyOf(chosen.getParents());
           Set<ARGState> chosenChildren = ImmutableSet.copyOf(chosen.getChildren());
           if (candidateParents.equals(chosenParents)
               && candidateChildren.equals(chosenChildren)) {
             valid = false;
             break;
           }
         }
       }
     }
     if (valid) {
       result.add(candidate);
     }
   }
   return result;
 }
 /**
  * Collect all precisions in the subgraph below refinementRoot and merge their predicates.
  *
  * @return a new precision with all these predicates.
  */
 private PredicatePrecision findAllPredicatesFromSubgraph(
     ARGState refinementRoot, UnmodifiableReachedSet reached) {
   return PredicatePrecision.unionOf(
       from(refinementRoot.getSubgraph())
           .filter(not(ARGState::isCovered))
           .transform(reached::getPrecision));
 }
  private boolean checkAndAddSuccessors(
      final ARGState pPredecessor,
      final ReachedSet pReachedSet,
      final Precision pPrecision,
      @Nullable List<ARGState> pIncompleteStates)
      throws InterruptedException, CPAException {
    stats.getTransferTimer().start();
    Collection<ARGState> successors = pPredecessor.getChildren();
    logger.log(Level.FINER, "Checking abstract successors", successors);
    if (!checkSuccessors(pPredecessor, successors, pPrecision)) {
      stats.getTransferTimer().stop();
      if (pIncompleteStates != null) {
        pIncompleteStates.add(pPredecessor);
        logger.log(
            Level.FINER,
            "State",
            pPredecessor,
            "is explored incompletely, will be recorded in the assumption automaton.");
        return true;
      }
      logger.log(Level.WARNING, "State", pPredecessor, "has other successors than", successors);
      return false;
    }
    stats.getTransferTimer().stop();

    if (!addSuccessors(successors, pReachedSet, pPrecision)) {
      return false;
    }
    return true;
  }
  /**
   * Processes an edge of the CFA and will write code to the output function body.
   *
   * @param childElement the state after the given edge
   * @param edge the edge to process
   * @param functionStack the current callstack
   */
  void processEdge(ARGState childElement, CFAEdge edge, Stack<FunctionBody> functionStack) {
    FunctionBody currentFunction = functionStack.peek();

    if (childElement.isTarget()) {
      currentFunction.write(getTargetState());
    }

    // handle the edge

    if (edge instanceof CFunctionCallEdge) {
      // if this is a function call edge we need to create a new state and push
      // it to the topmost stack to represent the function

      // create function and put in onto stack
      String freshFunctionName = startFunction(childElement, functionStack, edge.getPredecessor());

      // write summary edge to the caller site (with the new unique function name)
      currentFunction.write(processFunctionCall(edge, freshFunctionName));

    } else if (edge instanceof CFunctionReturnEdge) {
      functionStack.pop();

    } else {
      currentFunction.write(processSimpleEdge(edge, currentFunction.getCurrentBlock()));
    }
  }
  private boolean checkCoveredStates(
      final ARGState pCovered, final ReachedSet pReachedSet, final Precision pPrecision)
      throws CPAException, InterruptedException {
    logger.log(Level.FINER, "State is covered by another abstract state; checking coverage");
    ARGState coveringState = pCovered.getCoveringState();

    if (!pReachedSet.contains(coveringState)) {
      if (treatStateIfCoveredByUnkownState(pCovered, coveringState, pReachedSet, pPrecision)) {
        return true;
      }
    }

    stats.getStopTimer().start();
    if (!isCoveringCycleFree(pCovered)) {
      stats.getStopTimer().stop();
      logger.log(Level.WARNING, "Found cycle in covering relation for state", pCovered);
      return false;
    }
    if (!checkCovering(pCovered, coveringState, pPrecision)) {
      stats.getStopTimer().stop();
      logger.log(Level.WARNING, "State", pCovered, "is not covered by", coveringState);
      return false;
    }
    stats.getStopTimer().stop();
    return true;
  }
 /**
  * Merge all predicate precisions in the subgraph below the refinement root into a new predicate
  * precision
  *
  * @return a new predicate precision containing all predicate precision from the subgraph below
  *     the refinement root.
  */
 private PredicatePrecision mergePredicatePrecisionsForSubgraph(
     final ARGState pRefinementRoot, final ARGReachedSet pReached) {
   UnmodifiableReachedSet reached = pReached.asReachedSet();
   return PredicatePrecision.unionOf(
       from(pRefinementRoot.getSubgraph())
           .filter(not(ARGState::isCovered))
           .transform(reached::getPrecision));
 }
  /**
   * This method returns the target states in the subtree of the given state.
   *
   * @param state the state for which to collect the target states in its subtree.
   * @return target states in the subtree of the given state
   */
  public Collection<ARGState> getTargetsInSubtree(ARGState state) {
    Collection<ARGState> targetStates = new HashSet<>();

    Deque<ARGState> todo = new ArrayDeque<>(Collections.singleton(state));
    while (!todo.isEmpty()) {
      final ARGState currentState = todo.removeFirst();

      if (currentState.isTarget()) {
        targetStates.add(currentState);
        continue;
      }

      Collection<ARGState> successors = successorRelation.get(currentState);
      todo.addAll(successors);
    }

    return targetStates;
  }
  /**
   * This method extracts the precision increment for the given refinement root. It does so by
   * collection all non-trivial interpolants in the subtree of the given refinement root.
   *
   * @return the precision increment for the given refinement root
   */
  public Multimap<CFANode, MemoryLocation> extractPrecisionIncrement(ARGState pRefinementRoot) {
    Multimap<CFANode, MemoryLocation> increment = HashMultimap.create();

    Deque<ARGState> todo =
        new ArrayDeque<>(Collections.singleton(predecessorRelation.get(pRefinementRoot)));

    while (!todo.isEmpty()) {
      final ARGState currentState = todo.removeFirst();

      if (stateHasNonTrivialInterpolant(currentState) && !currentState.isTarget()) {
        I itp = interpolants.get(currentState);
        for (MemoryLocation memoryLocation : itp.getMemoryLocations()) {
          increment.put(AbstractStates.extractLocation(currentState), memoryLocation);
        }
      }

      if (!stateHasFalseInterpolant(currentState)) {
        todo.addAll(successorRelation.get(currentState));
      }
    }

    return increment;
  }
  private VariableTrackingPrecision mergeAllValuePrecisionsFromSubgraph(
      ARGState refinementRoot, UnmodifiableReachedSet reached) {

    VariableTrackingPrecision rootPrecision =
        Precisions.extractPrecisionByType(
            reached.getPrecision(refinementRoot), VariableTrackingPrecision.class);

    // find all distinct precisions to merge them
    Set<Precision> precisions = Sets.newIdentityHashSet();
    for (ARGState state : refinementRoot.getSubgraph()) {
      if (!state.isCovered()) {
        // covered states are not in reached set
        precisions.add(reached.getPrecision(state));
      }
    }

    for (Precision prec : precisions) {
      rootPrecision =
          rootPrecision.join(
              Precisions.extractPrecisionByType(prec, VariableTrackingPrecision.class));
    }

    return rootPrecision;
  }
  /**
   * Start the function, puts another body on the function stack.
   *
   * @param firstFunctionElement the first state inside the function
   * @param functionStack the current callstack
   * @param predecessor the previous node
   */
  protected String startFunction(
      ARGState firstFunctionElement, Stack<FunctionBody> functionStack, CFANode predecessor) {
    // create the first stack element using the first element of the function
    CFunctionEntryNode functionStartNode = extractFunctionCallLocation(firstFunctionElement);
    String freshFunctionName = getFreshFunctionName(functionStartNode);

    String lFunctionHeader =
        functionStartNode.getFunctionDefinition().getType().toASTString(freshFunctionName);
    // lFunctionHeader is for example "void foo_99(int a)"

    // create a new function
    FunctionBody newFunction = new FunctionBody(firstFunctionElement.getStateId(), lFunctionHeader);

    // register function
    mFunctionDecls.add(lFunctionHeader + ";");
    mFunctionBodies.add(newFunction);
    functionStack.push(newFunction); // add function to current stack
    return freshFunctionName;
  }
 @Override
 public boolean apply(ARGState pChild) {
   return pChild != null && predecessor.getEdgeToChild(pChild) == edge;
 }
 private ARGState getUncoveredSuccessor(ARGState pMaybeCovered) {
   while (pMaybeCovered.isCovered()) {
     pMaybeCovered = pMaybeCovered.getCoveringState();
   }
   return pMaybeCovered;
 }
  private Pair<Map<String, Integer>, List<AbstractState>>
      identifyCompositeStateTypesAndTheirInitialInstances(Collection<ARGState> rootNodes)
          throws InterruptedException, CPAException {
    logger.log(Level.FINE, "Derive composite state structure of combined ARG");

    List<AbstractState> initialState = new ArrayList<>();
    Map<String, Integer> stateToPos = new HashMap<>();
    List<String> automataStateNames = new ArrayList<>();

    String name;
    int nextId = 0;
    Iterable<AbstractState> wrapped;

    logger.log(Level.FINE, "Add non-automaton states");
    for (ARGState root : rootNodes) {
      shutdown.shutdownIfNecessary();

      wrapped = getWrappedStates(root);

      for (AbstractState innerWrapped : wrapped) {
        shutdown.shutdownIfNecessary();

        if (innerWrapped instanceof AssumptionStorageState) {
          continue;
        }

        name = getName(innerWrapped);

        if (stateToPos.containsKey(name)) {
          if (!initialState.get(stateToPos.get(name)).equals(innerWrapped)) {
            logger.log(
                Level.WARNING,
                "Abstract state ",
                innerWrapped.getClass(),
                " is used by multiple configurations, but cannot check that always start in the same initial state as it is assumed");
          }
        } else {
          assert (initialState.size() == nextId);

          if (innerWrapped instanceof AutomatonState) {
            automataStateNames.add(name);
          } else {
            stateToPos.put(name, nextId);
            initialState.add(innerWrapped);
            nextId++;
          }
        }
      }
    }

    logger.log(Level.FINE, "Add automaton states related to specification");
    Collections.sort(automataStateNames);

    int numRootStates = rootNodes.size();
    Set<String> commonAutomataStates = new TreeSet<>();
    for (int i = 1, j = 0; i < automataStateNames.size(); i++) {
      assert (j < i && j >= 0);
      if (automataStateNames.get(j).equals(automataStateNames.get(i))) {
        if (j + numRootStates - 1 == i) {
          // automaton states commonly used
          commonAutomataStates.add(automataStateNames.get(j));
        }
      } else {
        j = i;
      }
    }

    // assume root is the root node of the first ARG constructed
    ARGState root = rootNodes.iterator().next();

    if (root.getWrappedState() instanceof AbstractWrapperState) {
      wrapped = ((AbstractWrapperState) root.getWrappedState()).getWrappedStates();
    } else {
      wrapped = Collections.singleton(root.getWrappedState());
    }

    for (AbstractState innerWrapped : wrapped) {
      shutdown.shutdownIfNecessary();

      name = getName(innerWrapped);
      if (commonAutomataStates.contains(name)) {
        assert (initialState.size() == nextId);

        stateToPos.put(name, nextId);
        if (!automatonARGBuilderSupport.registerAutomaton((AutomatonState) innerWrapped)) {
          logger.log(
              Level.SEVERE,
              "Property specification, given by automata specification, is ambigous.");
          throw new CPAException(
              "Ambigious property specification,  automata specification contains automata with same name or same state names");
        }
        initialState.add(
            automatonARGBuilderSupport.replaceStateByStateInAutomatonOfSameInstance(
                (AutomatonState) innerWrapped));
        nextId++;
      }
    }

    return Pair.of(stateToPos, initialState);
  }
  private boolean combineARGs(
      List<ARGState> roots,
      ForwardingReachedSet pReceivedReachedSet,
      HistoryForwardingReachedSet pForwaredReachedSet)
      throws InterruptedException, CPAException {
    Pair<Map<String, Integer>, List<AbstractState>> initStates =
        identifyCompositeStateTypesAndTheirInitialInstances(roots);

    Map<String, Integer> stateToPos = initStates.getFirst();
    List<AbstractState> initialStates = initStates.getSecond();

    try {
      pReceivedReachedSet.setDelegate(new ReachedSetFactory(config, logger).create());
    } catch (InvalidConfigurationException e) {
      logger.log(Level.SEVERE, "Creating reached set which should contain combined ARG fails.");
      return false;
    }

    shutdown.shutdownIfNecessary();

    // combined root
    ARGState combinedRoot = new ARGState(new CompositeState(initialStates), null);

    CFANode locPred;
    ARGState composedState, composedSuccessor;
    Collection<ARGState> components;

    List<List<ARGState>> successorsForEdge = new ArrayList<>(initialStates.size());
    EdgeSuccessor edgeSuccessorIdentifier = new EdgeSuccessor();

    Map<Pair<List<AbstractState>, List<ARGState>>, ARGState> constructedCombinedStates =
        Maps.newHashMap();
    Deque<Pair<List<ARGState>, ARGState>> toVisit = new ArrayDeque<>();
    toVisit.add(Pair.of(roots, combinedRoot));

    // traverse through ARGs and construct combined ARG
    // assume that states in initial states are most general, represent top state (except for
    // automaton CPAs)
    while (!toVisit.isEmpty()) {
      shutdown.shutdownIfNecessary();

      components = toVisit.peek().getFirst();
      composedState = toVisit.poll().getSecond();

      // add composed state to reached set
      pReceivedReachedSet.add(composedState, SingletonPrecision.getInstance());
      pReceivedReachedSet.removeOnlyFromWaitlist(composedState);

      // identify possible successor edges
      locPred = AbstractStates.extractLocation(composedState);
      nextEdge:
      for (CFAEdge succEdge : CFAUtils.allLeavingEdges(locPred)) {
        shutdown.shutdownIfNecessary();

        successorsForEdge.clear();
        edgeSuccessorIdentifier.setCFAEdge(succEdge);

        for (ARGState component : components) {
          // get the successors of ARG state for this edge succEdge
          edgeSuccessorIdentifier.setPredecessor(component);
          successorsForEdge.add(
              Lists.newArrayList(
                  Iterables.filter(component.getChildren(), edgeSuccessorIdentifier)));
          // check if stopped because no concrete successors exists, then do not
          if (successorsForEdge.get(successorsForEdge.size() - 1).isEmpty()
              && noConcreteSuccessorExist(component, succEdge, pForwaredReachedSet)) {
            continue nextEdge;
          }
        }

        // construct successors for each identified combination
        for (Pair<List<AbstractState>, List<ARGState>> combinedSuccessor :
            computeCartesianProduct(successorsForEdge, stateToPos, initialStates)) {
          if (constructedCombinedStates.containsKey(combinedSuccessor)) {
            // handle coverage
            constructedCombinedStates.get(combinedSuccessor).addParent(composedState);
          } else {
            // construct and register composed successor
            composedSuccessor =
                new ARGState(new CompositeState(combinedSuccessor.getFirst()), composedState);
            constructedCombinedStates.put(combinedSuccessor, composedSuccessor);

            // add successor for further exploration
            toVisit.add(Pair.of(combinedSuccessor.getSecond(), composedSuccessor));
          }
        }
      }
    }
    return true;
  }
  @Override
  public AlgorithmStatus run(ReachedSet pReachedSet)
      throws CPAException, InterruptedException, CPAEnabledAnalysisPropertyViolationException {
    checkArgument(
        pReachedSet instanceof ForwardingReachedSet,
        "PartialARGsCombiner needs ForwardingReachedSet");

    HistoryForwardingReachedSet reached = new HistoryForwardingReachedSet(pReachedSet);

    logger.log(Level.INFO, "Start inner algorithm to analyze program(s)");
    AlgorithmStatus status = AlgorithmStatus.UNSOUND_AND_PRECISE;

    stats.analysisTime.start();
    try {
      status = restartAlgorithm.run(reached);
    } finally {
      stats.analysisTime.stop();
    }

    if (status.isSound()) {
      shutdown.shutdownIfNecessary();

      logger.log(Level.INFO, "Program(s) soundly analyzed, start combining ARGs.");

      stats.argCombineTime.start();
      try {
        Collection<ReachedSet> usedReachedSets = reached.getAllReachedSetsUsedAsDelegates();

        if (usedReachedSets.size() <= 1) {
          logger.log(Level.INFO, "Only a single ARG is considered. Do not need to combine ARGs");
          if (usedReachedSets.size() == 1) {
            ((ForwardingReachedSet) pReachedSet).setDelegate(reached.getDelegate());
          }
          return status;
        }

        if (from(reached.getDelegate()).anyMatch((IS_TARGET_STATE))) {
          logger.log(Level.INFO, "Error found, do not combine ARGs.");
          ((ForwardingReachedSet) pReachedSet).setDelegate(reached.getDelegate());
          return status;
        }

        logger.log(Level.FINE, "Extract root nodes of ARGs");
        List<ARGState> rootNodes = new ArrayList<>(usedReachedSets.size());
        for (ReachedSet usedReached : usedReachedSets) {
          checkArgument(
              usedReached.getFirstState() instanceof ARGState,
              "Require that all restart configurations use ARGCPA as top level CPA.");
          checkArgument(
              AbstractStates.extractLocation(usedReached.getFirstState()) != null,
              "Require that all restart configurations consider a location aware state");

          for (AbstractState errorState : from(usedReached).filter((IS_TARGET_STATE))) {
            logger.log(
                Level.INFO,
                "Error state found in reached set ",
                usedReached,
                "but not by last configuration. Error state must be infeasible.");
            logger.log(Level.FINE, "Remove infeasible error state", errorState);
            ((ARGState) errorState).removeFromARG();
          }

          rootNodes.add((ARGState) usedReached.getFirstState());
        }

        shutdown.shutdownIfNecessary();

        if (!combineARGs(rootNodes, (ForwardingReachedSet) pReachedSet, reached)) {
          logger.log(Level.SEVERE, "Combination of ARGs failed.");
          return status.withSound(false);
        }
      } finally {
        stats.argCombineTime.stop();
      }

      logger.log(Level.INFO, "Finished combination of ARGS");

    } else {
      logger.log(
          Level.INFO,
          "Program analysis is already unsound.",
          "Do not continue with combination of unsound results");
      // set reached set to last used by restart algorithm
      if (reached.getDelegate() != pReachedSet) {
        ((ForwardingReachedSet) pReachedSet).setDelegate(reached.getDelegate());
      }
      return status.withSound(false);
    }

    return status.withSound(true);
  }
  private ARGState relocateRefinementRoot(
      final ARGState pRefinementRoot, final boolean predicatePrecisionIsAvailable)
      throws InterruptedException {

    // no relocation needed if only running value analysis,
    // because there, this does slightly degrade performance
    // when running VA+PA, merging/covering and refinements
    // of both CPAs could lead to the state, where in two
    // subsequent refinements, two identical error paths
    // were found, through different parts of the ARG
    // So now, when running VA+PA, the refinement root
    // is set to the lowest common ancestor of those states
    // that are covered by the states in the subtree of the
    // original refinement root
    if (!predicatePrecisionIsAvailable) {
      return pRefinementRoot;
    }

    // no relocation needed if restart at top
    if (restartStrategy == RestartStrategy.ROOT) {
      return pRefinementRoot;
    }

    Set<ARGState> descendants = pRefinementRoot.getSubgraph();
    Set<ARGState> coveredStates = new HashSet<>();
    shutdownNotifier.shutdownIfNecessary();
    for (ARGState descendant : descendants) {
      coveredStates.addAll(descendant.getCoveredByThis());
    }
    coveredStates.add(pRefinementRoot);

    // no relocation needed if set of descendants is closed under coverage
    if (descendants.containsAll(coveredStates)) {
      return pRefinementRoot;
    }

    Map<ARGState, ARGState> predecessorRelation = Maps.newHashMap();
    SetMultimap<ARGState, ARGState> successorRelation = LinkedHashMultimap.create();

    Deque<ARGState> todo = new ArrayDeque<>(coveredStates);
    ARGState coverageTreeRoot = null;

    // build the coverage tree, bottom-up, starting from the covered states
    while (!todo.isEmpty()) {
      shutdownNotifier.shutdownIfNecessary();
      final ARGState currentState = todo.removeFirst();

      if (currentState.getParents().iterator().hasNext()) {
        ARGState parentState = currentState.getParents().iterator().next();
        todo.add(parentState);
        predecessorRelation.put(currentState, parentState);
        successorRelation.put(parentState, currentState);

      } else if (coverageTreeRoot == null) {
        coverageTreeRoot = currentState;
      }
    }

    // starting from the root of the coverage tree,
    // the new refinement root is either the first node
    // having two or more children, or the original
    // refinement root, what ever comes first
    shutdownNotifier.shutdownIfNecessary();
    ARGState newRefinementRoot = coverageTreeRoot;
    while (successorRelation.get(newRefinementRoot).size() == 1
        && newRefinementRoot != pRefinementRoot) {
      newRefinementRoot = Iterables.getOnlyElement(successorRelation.get(newRefinementRoot));
    }

    rootRelocations.inc();
    return newRefinementRoot;
  }
    private List<BooleanFormula> computeBlockFormulas(final ARGState pRoot)
        throws CPATransferException, InterruptedException {

      final Map<ARGState, ARGState> callStacks =
          new HashMap<>(); // contains states and their next higher callstate
      final Map<ARGState, PathFormula> finishedFormulas = new HashMap<>();
      final List<BooleanFormula> abstractionFormulas = new ArrayList<>();
      final Deque<ARGState> waitlist = new ArrayDeque<>();

      // initialize
      assert pRoot.getParents().isEmpty() : "rootState must be the first state of the program";
      callStacks.put(pRoot, null); // main-start has no callstack
      finishedFormulas.put(pRoot, pfmgr.makeEmptyPathFormula());
      waitlist.addAll(pRoot.getChildren());

      // iterate over all elements in the ARG with BFS
      while (!waitlist.isEmpty()) {
        final ARGState currentState = waitlist.pollFirst();
        if (finishedFormulas.containsKey(currentState)) {
          continue; // already handled
        }

        if (!finishedFormulas.keySet().containsAll(currentState.getParents())) {
          // parent not handled yet, re-queue current element and wait for all parents
          waitlist.addLast(currentState);
          continue;
        }

        // collect formulas for current location
        final List<PathFormula> currentFormulas = new ArrayList<>(currentState.getParents().size());
        final List<ARGState> currentStacks = new ArrayList<>(currentState.getParents().size());
        for (ARGState parentElement : currentState.getParents()) {
          PathFormula parentFormula = finishedFormulas.get(parentElement);
          final CFAEdge edge = parentElement.getEdgeToChild(currentState);
          assert edge != null : "ARG is invalid: parent has no edge to child";

          final ARGState prevCallState;
          // we enter a function, so lets add the previous state to the stack
          if (edge.getEdgeType() == CFAEdgeType.FunctionCallEdge) {
            prevCallState = parentElement;

          } else if (edge.getEdgeType() == CFAEdgeType.FunctionReturnEdge) {
            // we leave a function, so rebuild return-state before assigning the return-value.
            // rebuild states with info from previous state
            assert callStacks.containsKey(parentElement);
            final ARGState callState = callStacks.get(parentElement);

            assert extractLocation(callState).getLeavingSummaryEdge().getSuccessor()
                    == extractLocation(currentState)
                : "callstack does not match entry of current function-exit.";
            assert callState != null || currentState.getChildren().isEmpty()
                : "returning from empty callstack is only possible at program-exit";

            prevCallState = callStacks.get(callState);
            parentFormula =
                rebuildStateAfterFunctionCall(
                    parentFormula,
                    finishedFormulas.get(callState),
                    (FunctionExitNode) extractLocation(parentElement));

          } else {
            assert callStacks.containsKey(parentElement); // check for null is not enough
            prevCallState = callStacks.get(parentElement);
          }

          final PathFormula currentFormula = pfmgr.makeAnd(parentFormula, edge);
          currentFormulas.add(currentFormula);
          currentStacks.add(prevCallState);
        }

        assert currentFormulas.size() >= 1 : "each state except root must have parents";
        assert currentStacks.size() == currentFormulas.size()
            : "number of callstacks must match predecessors";

        // merging after functioncall with different callstates is ugly.
        // this is also guaranteed by the abstraction-locations at function-entries
        // (--> no merge of states with different latest abstractions).
        assert Sets.newHashSet(currentStacks).size() <= 1
            : "function with multiple entry-states not supported";

        callStacks.put(currentState, currentStacks.get(0));

        PathFormula currentFormula;
        final PredicateAbstractState predicateElement =
            extractStateByType(currentState, PredicateAbstractState.class);
        if (predicateElement.isAbstractionState()) {
          // abstraction element is the start of a new part of the ARG

          assert waitlist.isEmpty() : "todo should be empty, because of the special ARG structure";
          assert currentState.getParents().size() == 1
              : "there should be only one parent, because of the special ARG structure";

          // finishedFormulas.clear(); // free some memory
          // TODO disabled, we need to keep callStates for later usage

          // start new block with empty formula
          currentFormula = getOnlyElement(currentFormulas);
          abstractionFormulas.add(currentFormula.getFormula());
          currentFormula = pfmgr.makeEmptyPathFormula(currentFormula);

        } else {
          // merge the formulas
          Iterator<PathFormula> it = currentFormulas.iterator();
          currentFormula = it.next();
          while (it.hasNext()) {
            currentFormula = pfmgr.makeOr(currentFormula, it.next());
          }
        }

        assert !finishedFormulas.containsKey(currentState) : "a state should only be finished once";
        finishedFormulas.put(currentState, currentFormula);
        waitlist.addAll(currentState.getChildren());
      }
      return abstractionFormulas;
    }
  private Collection<Edge> handleEdge(
      Edge nextEdge,
      Map<Integer, MergeNode> mergeNodes,
      Set<ARGState> elementsOnPath,
      EdgeVisitor callback) {
    ARGState childElement = nextEdge.getChildState();
    CFAEdge edge = nextEdge.getEdge();
    Stack<FunctionBody> functionStack = nextEdge.getStack();

    // clone stack to have a different representation of the function calls and conditions
    // for every element
    functionStack = cloneStack(functionStack);

    // we do not have a single edge, instead a dynamic multi-edge
    if (edge == null) {
      List<CFAEdge> edges = nextEdge.getParentState().getEdgesToChild(childElement);
      for (CFAEdge inner : edges) {
        callback.visit(childElement, inner, functionStack);
      }
    } else {
      callback.visit(childElement, edge, functionStack);
    }

    // how many parents does the child have?
    // ignore parents not on the error path
    int noOfParents = from(childElement.getParents()).filter(in(elementsOnPath)).size();
    assert noOfParents >= 1;

    // handle merging if necessary
    if (noOfParents > 1) {
      assert !((edge instanceof CFunctionCallEdge) || (childElement.isTarget()));

      // this is the end of a condition, determine whether we should continue or backtrack

      int elemId = childElement.getStateId();
      FunctionBody currentFunction = functionStack.peek();
      currentFunction.write("goto label_" + elemId + ";");

      // get the merge node for that node
      MergeNode mergeNode = mergeNodes.get(elemId);
      // if null create new and put in the map
      if (mergeNode == null) {
        mergeNode = new MergeNode(elemId);
        mergeNodes.put(elemId, mergeNode);
      }

      // this tells us the number of edges (entering that node) processed so far
      int noOfProcessedBranches = mergeNode.addBranch(currentFunction);

      // if all edges are processed
      if (noOfParents == noOfProcessedBranches) {
        // all branches are processed, now decide which nodes to remove from the stack
        List<FunctionBody> incomingStacks = mergeNode.getIncomingStates();

        FunctionBody newFunction = processIncomingStacks(incomingStacks);

        // replace the current function body with the right one
        functionStack.pop();
        functionStack.push(newFunction);

        newFunction.write("label_" + elemId + ": ;");

      } else {
        return Collections.emptySet();
      }
    }

    return getRelevantChildrenOfState(childElement, functionStack, elementsOnPath);
  }
  public void writeCoverageReport(
      final PrintStream pStatisticsOutput, final ReachedSet pReached, final CFA pCfa) {

    if (!enabled) {
      return;
    }

    Multiset<FunctionEntryNode> reachedLocations = getFunctionEntriesFromReached(pReached);

    Map<String, FileCoverageInformation> infosPerFile = new HashMap<>();

    // Add information about existing functions
    for (FunctionEntryNode entryNode : pCfa.getAllFunctionHeads()) {
      final FileLocation loc = entryNode.getFileLocation();
      if (loc.getStartingLineNumber() == 0) {
        // dummy location
        continue;
      }
      final String functionName = entryNode.getFunctionName();
      final FileCoverageInformation infos = getFileInfoTarget(loc, infosPerFile);

      final int startingLine = loc.getStartingLineInOrigin();
      final int endingLine = loc.getEndingLineInOrigin();

      infos.addExistingFunction(functionName, startingLine, endingLine);

      if (reachedLocations.contains(entryNode)) {
        infos.addVisitedFunction(entryNode.getFunctionName(), reachedLocations.count(entryNode));
      }
    }

    // Add information about existing locations
    for (CFANode node : pCfa.getAllNodes()) {
      for (int i = 0; i < node.getNumLeavingEdges(); i++) {
        handleExistedEdge(node.getLeavingEdge(i), infosPerFile);
      }
    }

    Set<CFANode> reachedNodes =
        from(pReached).transform(EXTRACT_LOCATION).filter(notNull()).toSet();
    // Add information about visited locations
    for (AbstractState state : pReached) {
      ARGState argState = AbstractStates.extractStateByType(state, ARGState.class);
      if (argState != null) {
        for (ARGState child : argState.getChildren()) {
          if (!child.isCovered()) {
            List<CFAEdge> edges = argState.getEdgesToChild(child);
            if (edges.size() > 1) {
              for (CFAEdge innerEdge : edges) {
                handleCoveredEdge(innerEdge, infosPerFile);
              }

              // BAM produces paths with no edge connection thus the list will be empty
            } else if (!edges.isEmpty()) {
              handleCoveredEdge(Iterables.getOnlyElement(edges), infosPerFile);
            }
          }
        }
      } else {
        // Simple kind of analysis
        // Cover all edges from reached nodes
        // It is less precise, but without ARG it is impossible to know what path we chose
        CFANode node = AbstractStates.extractLocation(state);
        for (int i = 0; i < node.getNumLeavingEdges(); i++) {
          CFAEdge edge = node.getLeavingEdge(i);
          if (reachedNodes.contains(edge.getSuccessor())) {
            handleCoveredEdge(edge, infosPerFile);
          }
        }
      }
    }

    for (CoverageWriter w : reportWriters) {
      w.write(infosPerFile, pStatisticsOutput);
    }
  }