int TransitionGraph::eliminateBackEdges() { const EState* startState=getStartEState(); set<const EState*> visited; visited.insert(startState); TransitionPtrSet backEdges; // default empty determineBackEdges(startState, visited, backEdges); for(TransitionPtrSet::iterator i=backEdges.begin(); i!=backEdges.end(); ++i) { } return backEdges.size(); }
void TransitionGraph::determineBackEdges(const EState* state, set<const EState*>& visited, TransitionPtrSet& tpSet) { TransitionPtrSet succPtrs=outEdges(state); for(TransitionPtrSet::iterator i=succPtrs.begin(); i!=succPtrs.end(); ++i) { if(visited.find((*i)->target)!=visited.end()) { // target node exists in visited-set tpSet.insert(*i); return; } visited.insert((*i)->target); determineBackEdges((*i)->target,visited,tpSet); } return; }
/*! * \author Markus Schordan * \date 2012. */ void TransitionGraph::reduceEState2(const EState* estate) { /* description of essential operations: * inedges: (n_i,b) * outedges: (b,n_j) * insert(ni,t,nj) where t=union(t(n_i))+union(t(n_j))+{EDGE_PATH} * remove(n_i,b) * remove(b,n_j) * delete b * ea: (n1,cfge,n2) == ((l1,p1,c1,io1),(l1,t12,l2),(l2,p2,c2,io2)) * eb: (n2,cfge,n3) == ((l2,p2,c2,io2),(l2,t23,l3),(l3,p3,c3,io3)) * ==> (n1,cfge',n3) == ((l1,p1,c1,io1),(l1,{t12,t13,EDGE_PATH}},l3),(l3,p3,c3,io3)) */ ROSE_ASSERT(estate); // check self-edge if(const Transition* trans=hasSelfEdge(estate)) { this->erase(*trans); } TransitionGraph::TransitionPtrSet in=inEdges(estate); TransitionGraph::TransitionPtrSet out=outEdges(estate); if(in.size()!=0 && out.size()!=0 ) { set<Transition> newTransitions; for(TransitionPtrSet::iterator i=in.begin(); i!=in.end(); ++i) { for(TransitionPtrSet::iterator j=out.begin(); j!=out.end(); ++j) { if((*i)->source!=estate && (*j)->target!=estate) { Edge newEdge((*i)->source->label(),EDGE_PATH,(*j)->target->label()); Transition t((*i)->source,newEdge,(*j)->target); newTransitions.insert(t); //assert(newTransitions.find(t)!=newTransitions.end()); } } } //cout << "DEBUG: number of new transitions: "<<newTransitions.size()<<endl; TransitionPtrSet all=in; for(TransitionPtrSet::iterator j=out.begin(); j!=out.end(); ++j) { all.insert(*j); } // 1. remove all old transitions for(TransitionPtrSet::iterator i=all.begin(); i!=all.end(); ++i) { this->erase(**i); } // 2. add new transitions for(set<Transition>::iterator k=newTransitions.begin(); k!=newTransitions.end(); ++k) { //check if a single transition to the target already exists, delete this shorter path TransitionPtrSet outEdgesTransSource = outEdges((*k).source); for (TransitionPtrSet::iterator iter = outEdgesTransSource.begin(); iter != outEdgesTransSource.end(); ++iter) { if ((*iter)->target == (*k).target) { erase(**iter); } } this->add(*k); //assert(find(*k)!=end()); } eliminateEState(estate); assert(newTransitions.size()<=in.size()*out.size()); } else { // need to eliminate node instead eliminateEState(estate); } }
PropertyValueTable* CounterexampleAnalyzer::cegarPrefixAnalysisForLtl(int property, SpotConnection& spotConnection, set<int> ltlInAlphabet, set<int> ltlOutAlphabet) { // visualizer for in-depth model outputs (.dot files) Visualizer visualizer(_analyzer->getLabeler(),_analyzer->getVariableIdMapping(), _analyzer->getFlow(),_analyzer->getPStateSet(),_analyzer->getEStateSet(),_analyzer->getTransitionGraph()); string vizFilenamePrefix = ""; if(args.count("viz-cegpra-detailed")) { vizFilenamePrefix=args["viz-cegpra-detailed"].as<string>(); string filename = vizFilenamePrefix + "_cegpra_init.dot"; writeDotGraphToDisk(filename, visualizer); } // OVERVIEW // (0) check if the initial model already satsifies the property // (0.5) initialization // (while (property != satisfied)) do // (1) Disconnect the concrete prefix (initially the start state) from the over-approx. part of the model // (2) Anaylze the most recent counterexample while adding the trace of the original program to the prefix part of the model // If the counterexample is real: reconnect once more to determine the model's size, ESCAPE the loop and return results // (3) Reconnect both parts of the model // (4) Check the property on the now slightly refined model // od // (5) return results; cout << "STATUS: CEGPRA is now analyzing LTL property " << property << "..." << endl; if (_csvOutput) { (*_csvOutput) << endl << property << ","; } TransitionGraph* model = _analyzer->getTransitionGraph(); assert(model->isComplete()); // (0) check if the given property already holds on the initial over-approximated model PropertyValueTable* currentResults = spotConnection.getLtlResults(); if (currentResults->getPropertyValue(property) != PROPERTY_VALUE_UNKNOWN) { cout << "STATUS: property " << property << " was already analyzed. CEGAR analysis will not be started." << endl; return currentResults; } spotConnection.checkSingleProperty(property, *model, ltlInAlphabet, ltlOutAlphabet, true, true); currentResults = spotConnection.getLtlResults(); // (0.5) prepare for the continuous tracing of concrete states (will become the prefix of a refined abstract model) // store connectors in the over-approx. part of the model (single row of input states in the initial "topified" model) const EState* startEState = model->getStartEState(); pair<EStatePtrSet, EStatePtrSet> concOutputAndAbstrInput = getConcreteOutputAndAbstractInput(model); EStatePtrSet startAndOuputStatesPrefix = concOutputAndAbstrInput.first; vector<const EState*> firstInputOverApprox(ltlInAlphabet.size()); firstInputOverApprox = sortAbstractInputStates(firstInputOverApprox, concOutputAndAbstrInput.second); int loopCount = 0; bool falsified = false; bool verified = true; // the usual case for the loop below to terminate is a verified property. string ce = "no counterexample yet"; // as long as the property is not satisfiable yet, refine by enlarging the prefix of concrete states according to counterexamples while (currentResults->getPropertyValue(property) != PROPERTY_VALUE_YES) { if (_maxCounterexamples > -1 && (loopCount + 1) > _maxCounterexamples) { verified = false; spotConnection.resetLtlResults(property); break; } loopCount++; if (loopCount % 50 == 0) { cout << "STATUS: " << loopCount << " counterexamples analyzed. most recent counterexample: " << endl; cout << ce << endl; } // (1) disconnect prefix and over-approx. part of the model model->setIsComplete(false); for (unsigned int i = 0; i < firstInputOverApprox.size(); i++) { TransitionPtrSet connectionsToPrefix = model->inEdges(firstInputOverApprox[i]); for (TransitionPtrSet::iterator k=connectionsToPrefix.begin(); k!=connectionsToPrefix.end(); ++k) { // check if predeccesor at the source of that transition is a concrete (prefix) state if ( !(*k)->source->isRersTopified(_analyzer->getVariableIdMapping()) ) { model->erase(**k); } } } model->setIsPrecise(true); if(args.count("viz-cegpra-detailed")) { stringstream filenameStream; filenameStream << vizFilenamePrefix << "cegpra_afterDisconnect_i" << loopCount << ".dot"; writeDotGraphToDisk(filenameStream.str(), visualizer); } // (2) add a trace to the prefix according to the most recent counterexample. Analyze the counterexample while adding the trace. ce = currentResults->getCounterexample(property); //cout << "STATUS: counterexample: " << ce << endl; CEAnalysisResult ceaResult = analyzeCounterexample(ce, startEState, false, false); if (ceaResult.analysisResult == CE_TYPE_REAL) { // still reconnect the concrete prefix with the over-approx. part of the model (step (3)) in order to report the size. falsified = true; verified = false; } else if (ceaResult.analysisResult == CE_TYPE_SPURIOUS) { if(!boolOptions["keep-error-states"]) { // remove a trace leading to an error state and mark the branches to it (do not reconnect in phase 3) removeAndMarkErroneousBranches(model); } //the trace eliminating the spurious counterexample (maybe including a few extra states) was added to the prefix during analysis. // --> nothing to do here } else { assert(0); //counterexample analysis not successfully completed } if(args.count("viz-cegpra-detailed")) { stringstream filenameStream; filenameStream << vizFilenamePrefix << "cegpra_afterCECheck_i" << loopCount << ".dot"; writeDotGraphToDisk(filenameStream.str(), visualizer); } // (3) reconnect both parts of the model model->setIsPrecise(false); //update set of output states (plus start state) in the precise prefix addAllPrefixOutputStates(startAndOuputStatesPrefix, model); for (set<const EState*>::iterator i=startAndOuputStatesPrefix.begin(); i!=startAndOuputStatesPrefix.end(); ++i) { vector<bool> inputSuccessors(ltlInAlphabet.size(), false); if(!boolOptions["keep-error-states"]) { inputSuccessors = setErrorBranches(inputSuccessors, *i); } // determine which input states exist as successors in the prefix inputSuccessors = hasFollowingInputStates(inputSuccessors, *i, model); //connect with the approx. part of the model for all input values not found among the successor states for (unsigned int k = 0; k < inputSuccessors.size(); k++) { if (!inputSuccessors[k]) { Edge newEdge; model->add(Transition((*i), newEdge, firstInputOverApprox[k])); } } } model->setIsComplete(true); if(args.count("viz-cegpra-detailed")) { stringstream filenameStream; filenameStream << vizFilenamePrefix << "cegpra_afterReconnect_i" << loopCount << ".dot"; writeDotGraphToDisk(filenameStream.str(), visualizer); } // if falsified: after reconnecting, leave the analysis loop, report size of the model and return the results if (falsified) { break; } // (4) check if the property holds on the refined model spotConnection.resetLtlResults(property); spotConnection.checkSingleProperty(property, *model, ltlInAlphabet, ltlOutAlphabet, true, true); currentResults = spotConnection.getLtlResults(); } // (5) check all properties using the current model and return the result spotConnection.checkLtlProperties(*model, ltlInAlphabet, ltlOutAlphabet, true, false); currentResults = spotConnection.getLtlResults(); printStgSizeAndCeCount(model, loopCount, property); if (_csvOutput) { if (verified && !falsified) (*_csvOutput) << "y,"; if (!verified && falsified) (*_csvOutput) << "n,"; if (!verified && !falsified) (*_csvOutput) << "?,"; if (verified && falsified) { cout << "ERROR: property can not be both verified and falsified. " << endl; assert(0); } (*_csvOutput) << currentResults->entriesWithValue(PROPERTY_VALUE_YES)<<","; (*_csvOutput) << currentResults->entriesWithValue(PROPERTY_VALUE_NO)<<","; (*_csvOutput) << currentResults->entriesWithValue(PROPERTY_VALUE_UNKNOWN); } return currentResults; }