/** * This method chooses a new refinement root, in a bottom-up fashion along the error path. It * either picks the next state on the path sharing the same CFA location, or the (only) child of * the ARG root, what ever comes first. * * @param currentRoot the current refinement root * @return the relocated refinement root */ private ARGState relocateRepeatedRefinementRoot(final ARGState currentRoot) { repeatedRefinements.inc(); int currentRootNumber = AbstractStates.extractLocation(currentRoot).getNodeNumber(); ARGPath path = ARGUtils.getOnePathTo(currentRoot); for (ARGState currentState : path.asStatesList().reverse()) { // skip identity, because a new root has to be found if (currentState == currentRoot) { continue; } if (currentRootNumber == AbstractStates.extractLocation(currentState).getNodeNumber()) { return currentState; } } return Iterables.getOnlyElement(path.getFirstState().getChildren()); }
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; }