@Override public Collection<? extends AbstractState> getAbstractSuccessorsForEdge( AbstractState pElement, Precision pPrecision, CFAEdge pCfaEdge) throws CPATransferException { Preconditions.checkArgument(pElement instanceof AutomatonState); if (pElement instanceof AutomatonUnknownState) { // the last CFA edge could not be processed properly // (strengthen was not called on the AutomatonUnknownState or the strengthen operation had not // enough information to determine a new following state.) AutomatonState top = cpa.getTopState(); return Collections.singleton(top); } if (!(pCfaEdge instanceof MultiEdge)) { Collection<? extends AbstractState> result = getAbstractSuccessors0((AutomatonState) pElement, pPrecision, pCfaEdge); automatonSuccessors.setNextValue(result.size()); return result; } final List<CFAEdge> edges = ((MultiEdge) pCfaEdge).getEdges(); checkArgument(!edges.isEmpty()); // As long as each transition produces only 0 or 1 successors, // we can just iterate through the edges. AutomatonState currentState = (AutomatonState) pElement; Collection<AutomatonState> currentSuccessors = null; int edgeIndex; for (edgeIndex = 0; edgeIndex < edges.size(); edgeIndex++) { CFAEdge edge = edges.get(edgeIndex); currentSuccessors = getAbstractSuccessors0(currentState, pPrecision, edge); if (currentSuccessors.isEmpty()) { automatonSuccessors.setNextValue(0); return currentSuccessors; // bottom } else if (currentSuccessors.size() == 1) { automatonSuccessors.setNextValue(1); currentState = Iterables.getOnlyElement(currentSuccessors); } else { // currentSuccessors.size() > 1 break; } } if (edgeIndex == edges.size()) { automatonSuccessors.setNextValue(currentSuccessors.size()); return currentSuccessors; } // If there are two or more successors once, we use a waitlist algorithm. Deque<Pair<AutomatonState, Integer>> queue = new ArrayDeque<>(1); for (AutomatonState successor : currentSuccessors) { queue.addLast(Pair.of(successor, edgeIndex)); } currentSuccessors.clear(); List<AutomatonState> results = new ArrayList<>(); while (!queue.isEmpty()) { Pair<AutomatonState, Integer> entry = queue.pollFirst(); AutomatonState state = entry.getFirst(); edgeIndex = entry.getSecond(); CFAEdge edge = edges.get(edgeIndex); Integer successorIndex = edgeIndex + 1; if (successorIndex == edges.size()) { // last iteration results.addAll(getAbstractSuccessors0(state, pPrecision, edge)); } else { for (AutomatonState successor : getAbstractSuccessors0(state, pPrecision, edge)) { queue.addLast(Pair.of(successor, successorIndex)); } } } automatonSuccessors.setNextValue(results.size()); return results; }
/** * Returns the <code>AutomatonStates</code> that follow this State in the ControlAutomatonCPA. If * the passed <code>AutomatonExpressionArguments</code> are not sufficient to determine the * following state this method returns a <code>AutomatonUnknownState</code> that contains this as * previous State. The strengthen method of the <code>AutomatonUnknownState</code> should be used * once enough Information is available to determine the correct following State. * * <p>If the state is a NonDet-State multiple following states may be returned. If the only * following state is BOTTOM an empty set is returned. * * @throws CPATransferException */ private Collection<AutomatonState> getFollowStates( AutomatonState state, List<AbstractState> otherElements, CFAEdge edge, boolean failOnUnknownMatch) throws CPATransferException { Preconditions.checkArgument(!(state instanceof AutomatonUnknownState)); if (state == cpa.getBottomState()) { return Collections.emptySet(); } if (collectTokenInformation) { SourceLocationMapper.getKnownToEdge(edge); } if (state.getInternalState().getTransitions().isEmpty()) { // shortcut return Collections.singleton(state); } Collection<AutomatonState> lSuccessors = Sets.newHashSetWithExpectedSize(2); AutomatonExpressionArguments exprArgs = new AutomatonExpressionArguments(state, state.getVars(), otherElements, edge, logger); boolean edgeMatched = false; int failedMatches = 0; boolean nonDetState = state.getInternalState().isNonDetState(); // these transitions cannot be evaluated until last, because they might have sideeffects on // other CPAs (dont want to execute them twice) // the transitionVariables have to be cached (produced during the match operation) // the list holds a Transition and the TransitionVariables generated during its match List<Pair<AutomatonTransition, Map<Integer, String>>> transitionsToBeTaken = new ArrayList<>(2); for (AutomatonTransition t : state.getInternalState().getTransitions()) { exprArgs.clearTransitionVariables(); matchTime.start(); ResultValue<Boolean> match = t.match(exprArgs); matchTime.stop(); // System.out.println("----------------------"); // System.out.println(t.getTrigger()); // System.out.println(t.getFollowState().getName()); // System.out.println(edge.getPredecessor().getNodeNumber()); // System.out.println(edge.getCode()); // System.out.println(match.getValue()); if (match.canNotEvaluate()) { if (failOnUnknownMatch) { throw new CPATransferException( "Automaton transition condition could not be evaluated: " + match.getFailureMessage()); } // if one transition cannot be evaluated the evaluation must be postponed until enough // information is available return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } else { if (match.getValue()) { edgeMatched = true; assertionsTime.start(); ResultValue<Boolean> assertionsHold = t.assertionsHold(exprArgs); assertionsTime.stop(); if (assertionsHold.canNotEvaluate()) { if (failOnUnknownMatch) { throw new CPATransferException( "Automaton transition assertions could not be evaluated: " + assertionsHold.getFailureMessage()); } // cannot yet be evaluated return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } else if (assertionsHold.getValue()) { if (!t.canExecuteActionsOn(exprArgs)) { if (failOnUnknownMatch) { throw new CPATransferException("Automaton transition action could not be executed"); } // cannot yet execute, goto UnknownState return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } // delay execution as described above Map<Integer, String> transitionVariables = ImmutableMap.copyOf(exprArgs.getTransitionVariables()); transitionsToBeTaken.add(Pair.of(t, transitionVariables)); } else { // matching transitions, but unfulfilled assertions: goto error state AutomatonState errorState = AutomatonState.automatonStateFactory( Collections.<String, AutomatonVariable>emptyMap(), AutomatonInternalState.ERROR, cpa, 0, 0, ""); logger.log( Level.INFO, "Automaton going to ErrorState on edge \"" + edge.getDescription() + "\""); lSuccessors.add(errorState); } if (!nonDetState) { // not a nondet State, break on the first matching edge break; } } else { // do nothing if the edge did not match failedMatches++; } } } if (edgeMatched) { // execute Transitions for (Pair<AutomatonTransition, Map<Integer, String>> pair : transitionsToBeTaken) { // this transition will be taken. copy the variables AutomatonTransition t = pair.getFirst(); Map<Integer, String> transitionVariables = pair.getSecond(); actionTime.start(); Map<String, AutomatonVariable> newVars = deepCloneVars(state.getVars()); exprArgs.setAutomatonVariables(newVars); exprArgs.putTransitionVariables(transitionVariables); t.executeActions(exprArgs); actionTime.stop(); String violatedPropertyDescription = null; if (t.getFollowState().isTarget()) { violatedPropertyDescription = t.getViolatedPropertyDescription(exprArgs); } AutomatonState lSuccessor = AutomatonState.automatonStateFactory( newVars, t.getFollowState(), cpa, t.getAssumptions(), state.getMatches() + 1, state.getFailedMatches(), violatedPropertyDescription); if (!(lSuccessor instanceof AutomatonState.BOTTOM)) { lSuccessors.add(lSuccessor); } else { // add nothing } } return lSuccessors; } else { // stay in same state, no transitions to be executed here (no transition matched) AutomatonState stateNewCounters = AutomatonState.automatonStateFactory( state.getVars(), state.getInternalState(), cpa, state.getMatches(), state.getFailedMatches() + failedMatches, null); if (collectTokenInformation) { stateNewCounters.addNoMatchTokens(state.getTokensSinceLastMatch()); if (edge.getEdgeType() != CFAEdgeType.DeclarationEdge) { stateNewCounters.addNoMatchTokens( SourceLocationMapper.getAbsoluteTokensFromCFAEdge(edge, true)); } } return Collections.singleton(stateNewCounters); } }