BitField StateConstraints::minimalTrap(const PetriNet& net, const MarkVal* marking, const MarkVal* resultMarking) const{ const size_t nPlaces = net.numberOfPlaces(); BitField trap(nPlaces); trap.set(); trap = maxTrap(net, trap, resultMarking); if(!isMarked(trap, marking)) return BitField(nPlaces).clear(); //Get the exclusion candidates BitField EC(trap); BitField tmp(nPlaces); while(EC.any()){ int exclude = EC.first(); tmp = trap; tmp.clear(exclude); EC.clear(exclude); tmp = maxTrap(net, tmp, resultMarking); if(isMarked(tmp, marking)){ trap = tmp; EC = tmp; } } return trap; }
bool StateConstraints::isInMaxTrap(const PetriNet& net, size_t place, const BitField& places, const MarkVal* resultMarking) const{ if(!places.test(place)) return false; /* 0 if M(p_i) = 1 0 if there is (p_i , t) â F such that x_j = 0 for every p_j â t⢠1 otherwise */ if(resultMarking[place] > 0) return false; for(unsigned int t = 0; t < net.numberOfTransitions(); t++){ if(net.inArc(place, t) > 0){ bool exclude = true; for(unsigned int j = 0; j < net.numberOfPlaces(); j++){ if(net.outArc(t, j) > 0){ exclude &= !places.test(j); } } if(exclude) return false; } } return true; }
inline bool KarpMillerL1SearchStrategy::fire(const PetriNet& net, uint8_t t, const MarkVal* old_m, MarkVal* new_m){ for(size_t i = 0; i < net.numberOfPlaces(); i++){ new_m[i] = old_m[i] + net.transitionVector(t)[i]; if(new_m[i] < 0) return false; } return true; }
int SmartState::getState(const PetriNet& net, MarkVal* marking, VarVal* valuation) const{ if(stored()){ memcpy(marking, _marking, sizeof(MarkVal) * net.numberOfPlaces()); memcpy(valuation, _valuation, sizeof(VarVal) * net.numberOfVariables()); return 0; } int depth = parent()->getState(net, marking, valuation); net.fireWithoutCheck(transition(), marking, valuation, marking, valuation, multiplicity()); return depth + 1; }
ReachabilityResult MonoDFS::reachable(const PetriNet &net, const MarkVal *m0, const VarVal *v0, const BoolVal *b0, PQL::Condition *query){ //Do we initially satisfy query? if(query->evaluate(PQL::EvaluationContext(m0, v0, b0))) return ReachabilityResult(ReachabilityResult::Satisfied, "A state satisfying the query was found"); //Create StateSet MonotonicityContext context(&net,query); context.analyze(); DFSStateSet states(net,&context, ModeNormal); StateAllocator<1000000> allocator(net); State* s0 = allocator.createState(); memcpy(s0->marking(), m0, sizeof(MarkVal)*net.numberOfPlaces()); memcpy(s0->intValuation(), v0, sizeof(VarVal)*net.numberOfIntVariables()); memcpy(s0->boolValuation(), b0, sizeof(BoolVal)*net.numberOfBoolVariables()); states.add(s0, 0); unsigned int max = 0; int count = 0; BigInt exploredStates = 0; BigInt expandedStates = 0; BigInt transitionFired = 0; State* ns = allocator.createState(); while(states.waitingSize()){ if(count++ & 1<<18){ if(states.waitingSize() > max) max = states.waitingSize(); count = 0; //report progress reportProgress((double)(max-states.waitingSize())/(double)max); //check abort if(abortRequested()) return ReachabilityResult(ReachabilityResult::Unknown, "Search was aborted."); } //Take first step of the stack Step tstep = states.getNextStep(); State* s = tstep.state; ns->setParent(s); bool foundSomething = false; for(unsigned int t = tstep.t; t < net.numberOfTransitions(); t++){ if(net.fire(t, s->marking(), s->intValuation(),s->boolValuation(), ns->marking(), ns->intValuation(), ns->boolValuation())){ transitionFired++; if(states.add(ns,t)){ ns->setTransition(t); if(query->evaluate(PQL::EvaluationContext(ns->marking(), ns->intValuation(), ns->boolValuation()))) return ReachabilityResult(ReachabilityResult::Satisfied, "A state satisfying the query was found", expandedStates, exploredStates, transitionFired, states.getCountRemove(), ns->pathLength(), ns->trace()); exploredStates++; foundSomething = true; ns = allocator.createState(); break; } } } if(!foundSomething){ states.popWating(); expandedStates++; } } //states.writeStatistics(); return ReachabilityResult(ReachabilityResult::NotSatisfied, "No state satisfying the query exists.", expandedStates, exploredStates, transitionFired, states.getCountRemove()); }
ReachabilityResult BestFirstReachabilitySearch::reachable(const PetriNet &net, const MarkVal *m0, const VarVal *v0, const BoolVal *ba, PQL::Condition *query){ StateAllocator<> allocator(net); State* s0 = allocator.createState(); memcpy(s0->marking(), m0, sizeof(MarkVal) * net.numberOfPlaces()); memcpy(s0->intValuation(), v0, sizeof(VarVal) * net.numberOfIntVariables()); memcpy(s0->boolValuation(), ba, sizeof(BoolVal) * net.numberOfBoolVariables()); if(query->evaluate(*s0)) return ReachabilityResult(ReachabilityResult::Satisfied, "Satisfied initially", 0, 0); //Initialize subclasses initialize(query, net); StateSet states(net); _states = &states; states.add(s0); //PriorityQueue<State*> queue; EnhancedPriorityQueue<State*> queue; queue.push(0, s0); //Allocate new state State* ns = allocator.createState(); State* ns2 = allocator.createState(); State* ns3 = allocator.createState(); int count = 0; BigInt expandedStates = 0; BigInt exploredStates = 0; BigInt transitionFired = 0; size_t max = 1; while(!queue.empty()){ if(count++ & 1<<17){ count = 0; if(queue.size() > max) max = queue.size(); this->reportProgress((double)(max - queue.size()) / ((double)(max))); if(this->abortRequested()) return ReachabilityResult(ReachabilityResult::Unknown, "Query aborted!"); } //Take something out of the queue State* s = queue.pop(depthFirst); expandedStates++; // Attempt to fire each transition for(unsigned int t = 0; t < net.numberOfTransitions(); t++){ if(net.fire(t, s->marking(), s->intValuation(), s->boolValuation(), ns->marking(), ns->intValuation(), ns->boolValuation())){ //If it's new transitionFired++; if(states.add(ns)){ exploredStates++; //Set parent and transition for the state ns->setParent(s); ns->setTransition(t); //Test query if(query->evaluate(*ns)){ //ns->dumpTrace(net); return ReachabilityResult(ReachabilityResult::Satisfied, "Query was satified!", expandedStates, exploredStates, transitionFired,0 , ns->pathLength(), ns->trace()); } // Insert in queue, with given priority double bestp = priority(ns, query, net); queue.push(bestp, ns); if(fireUntillNoBetter && net.fire(t, ns, ns2)){ if(query->evaluate(*ns2)){ ns2->setTransition(t); ns2->setParent(ns); return ReachabilityResult(ReachabilityResult::Satisfied, "Query was satified!", expandedStates, exploredStates, transitionFired,0, ns2->pathLength(), ns2->trace()); } double p = priority(ns2, query, net); if(p <= bestp){ bestp = p; while(net.fire(t, ns2, ns3) && (p = priority(ns3, query, net)) <= bestp){ ns3->setTransition(t); ns3->setParent(ns2); bestp = p; State* tmp = ns2; //SWAP ns2 and ns3 ns2 = ns3; ns3 = tmp; exploredStates++; if(query->evaluate(*ns2)){ return ReachabilityResult(ReachabilityResult::Satisfied, "Query was satisfied!", expandedStates, exploredStates, transitionFired, 0, ns2->pathLength(), ns2->trace()); } } if(states.add(ns2)){ queue.push(priority(ns2, query, net), ns2); ns2 = allocator.createState(); } } } //Allocate new stake, as states take ownership ns = allocator.createState(); } } } } return ReachabilityResult(ReachabilityResult::NotSatisfied, "Query cannot be satisfied!", expandedStates, exploredStates, transitionFired,0); }
ReachabilityResult HeuristicDFS::reachable(const PetriNet& net, const MarkVal* m0, const VarVal* v0, const BoolVal *ba, PQL::Condition* query){ //Do we initially satisfy query? if(query->evaluate(PQL::EvaluationContext(m0, v0, ba))) return ReachabilityResult(ReachabilityResult::Satisfied, "A state satisfying the query was found"); StateSet states(net); StateAllocator<> allocator(net); std::list<State*> stack; State* s0 = allocator.createState(); memcpy(s0->marking(), m0, sizeof(MarkVal)*net.numberOfPlaces()); memcpy(s0->intValuation(), v0, sizeof(VarVal)*net.numberOfIntVariables()); memcpy(s0->boolValuation(), ba, sizeof(BoolVal)*net.numberOfBoolVariables()); stack.push_back(s0); states.add(s0); Structures::DistanceMatrix distanceMatrix(net); State* ns = allocator.createState(); unsigned int max = 0; int count = 0; BigInt expandedStates = 0; BigInt exploredStates = 0; BigInt transitionFired = 0; while(!stack.empty()){ // Progress reporting and abort checking if(count++ & 1<<16){ if(stack.size() > max) max = stack.size(); count = 0; // Report progress reportProgress((double)(max - stack.size())/(double)max); // Check abort if(abortRequested()) return ReachabilityResult(ReachabilityResult::Unknown, "Search was aborted."); } State* s = stack.back(); stack.pop_back(); State* succ[net.numberOfTransitions()]; double distances[net.numberOfTransitions()]; memset(succ, 0, net.numberOfTransitions()*sizeof(State*)); for(unsigned int t = 0; t < net.numberOfTransitions(); t++){ if(net.fire(t, s, ns)){ transitionFired++; if(states.add(ns)){ exploredStates++; ns->setParent(s); ns->setTransition(t); if(query->evaluate(*ns)) return ReachabilityResult(ReachabilityResult::Satisfied, "A state satisfying the query was found", expandedStates, exploredStates, transitionFired, 0, ns->pathLength(), ns->trace()); PQL::DistanceContext context(net, _distanceStrategy, ns->marking(), ns->intValuation(), ns->boolValuation(), &distanceMatrix); succ[t] = ns; distances[t] = query->distance(context); ns = allocator.createState(); } } } // Pretty bobble sort of the successors while(true){ bool foundSomething = false; unsigned int min = 0; for(unsigned int t = 0; t < net.numberOfTransitions(); t++){ if(succ[t] && (!foundSomething || distances[t] < distances[min])){ min = t; foundSomething = true; } } if(foundSomething){ stack.push_back(succ[min]); succ[min] = NULL; }else break; } expandedStates++; } return ReachabilityResult(ReachabilityResult::NotSatisfied, "No state satisfying the query exists.", expandedStates, exploredStates, transitionFired, 0); }
int StateConstraints::fireVectorSize(const PetriNet& net, const MarkVal* m0, const VarVal*) const{ assert(nPlaces == net.numberOfPlaces()); assert(nVars == net.numberOfVariables()); // Create linary problem lprec* lp; lp = make_lp(0, net.numberOfTransitions()); // One variable for each entry in the firing vector assert(lp); if(!lp) return false; // Set verbosity set_verbose(lp, IMPORTANT); // Set transition names (not strictly needed) for(size_t i = 0; i < net.numberOfTransitions(); i++) set_col_name(lp, i+1, const_cast<char*>(net.transitionNames()[i].c_str())); // Start adding rows set_add_rowmode(lp, TRUE); REAL row[net.numberOfTransitions() + 1]; for(size_t p = 0; p < nPlaces; p++){ // Set row zero memset(row, 0, sizeof(REAL) * net.numberOfTransitions() + 1); for(size_t t = 0; t < net.numberOfTransitions(); t++){ int d = net.outArc(t, p) - net.inArc(p, t); row[1+t] = d; } if(pcs[p].min == pcs[p].max && pcs[p].max != CONSTRAINT_INFTY){ double target = pcs[p].min - m0[p]; add_constraint(lp, row, EQ, target); }else{ // There's always a min, even zero is interesting double target = pcs[p].min - m0[p]; add_constraint(lp, row, GE, target); if(pcs[p].max != CONSTRAINT_INFTY){ double target = pcs[p].max - m0[p]; add_constraint(lp, row, LE, target); } } } // Finished adding rows set_add_rowmode(lp, FALSE); // Create objective memset(row, 0, sizeof(REAL) * net.numberOfTransitions() + 1); for(size_t t = 0; t < net.numberOfTransitions(); t++) row[1+t] = 1; // The sum the components in the firing vector // Set objective set_obj_fn(lp, row); // Minimize the objective set_minim(lp); // Set variables as integer variables for(size_t i = 0; i < net.numberOfTransitions(); i++) set_int(lp, 1+i, TRUE); // Attempt to solve the problem int result = solve(lp); // Limit on traps to test size_t traplimit = nPlaces * OVER_APPROX_TRAP_FACTOR; // Try to add a minimal trap constraint while((result == OPTIMAL) && traplimit-- < 0){ memset(row, 0, sizeof(REAL) * net.numberOfTransitions() + 1); // Get the firing vector get_variables(lp, row); // Compute the resulting marking MarkVal rMark[net.numberOfPlaces()]; for(size_t p = 0; p < nPlaces; p++){ rMark[p] = m0[p]; for(size_t t = 0; t < net.numberOfTransitions(); t++) rMark[p] += (net.outArc(t, p) - net.inArc(p, t)) * (int)row[t]; } // Find an M-trap BitField trap(minimalTrap(net, m0, rMark)); //Break if there's no trap if(trap.none()) break; // Compute the new equation for(size_t t = 0; t < net.numberOfTransitions(); t++){ row[1+t] = 0; for(size_t p = 0; p < nPlaces; p++) if(trap.test(p)) row[1+t] += net.outArc(t, p) - net.inArc(p, t); } // Add a new row with target as greater than equal to 1 set_add_rowmode(lp, TRUE); add_constraint(lp, row, GE, 1); set_add_rowmode(lp, FALSE); // Attempt to solve the again result = solve(lp); } int retval = 0; if(result != INFEASIBLE){ get_variables(lp, row); for(size_t t = 0; t < net.numberOfTransitions(); t++) retval += (int)row[t]; } // Delete the linear problem delete_lp(lp); lp = NULL; // Return true, if it was infeasible return retval; }
ReachabilityResult MonoBFS::reachable(const PetriNet &net, const MarkVal *m0, const VarVal *v0, const BoolVal *ba, PQL::Condition *query){ //Do we initially satisfy query? if(query->evaluate(PQL::EvaluationContext(m0, v0,ba))) return ReachabilityResult(ReachabilityResult::Satisfied, "A state satisfying the query was found"); //Create StateSet MonotonicityContext context(&net, query); context.analyze(); BFSOrderableStateSet states(net,&context); StateAllocator<1000000> allocator(net); State* s0 = allocator.createState(); memcpy(s0->marking(), m0, sizeof(MarkVal)*net.numberOfPlaces()); memcpy(s0->intValuation(), v0, sizeof(VarVal)*net.numberOfIntVariables()); memcpy(s0->boolValuation(), ba, sizeof(BoolVal)*net.numberOfBoolVariables()); states.add(s0); unsigned int max = 0; int count = 0; BigInt expandedStates = 0; BigInt exploredStates = 0; BigInt transitionFired = 0; State* ns = allocator.createState(); State* s = states.getNextState(); while(s){ // Progress reporting and abort checking if(count++ & 1<<15){ if(states.waitingSize() > max) max = states.waitingSize(); count = 0; // Report progress reportProgress((double)(max - states.waitingSize())/(double)max); // Check abort if(abortRequested()) return ReachabilityResult(ReachabilityResult::Unknown, "Search was aborted."); } for(unsigned int t = 0; t < net.numberOfTransitions(); t++){ if(net.fire(t, s, ns)){ transitionFired++; if(states.add(ns)){ exploredStates++; ns->setParent(s); ns->setTransition(t); if(query->evaluate(PQL::EvaluationContext(ns->marking(), ns->intValuation(), ns->boolValuation()))){ //ns->dumpTrace(net); return ReachabilityResult(ReachabilityResult::Satisfied, "A state satisfying the query was found", expandedStates, exploredStates, transitionFired, states.getCountRemove(), ns->pathLength(), ns->trace()); } ns = allocator.createState(); } } } s = states.getNextState(); expandedStates++; } return ReachabilityResult(ReachabilityResult::NotSatisfied, "No state satisfying the query exists.", expandedStates, exploredStates, transitionFired, states.getCountRemove()); }
bool KarpMillerL1SearchStrategy::reachable(const PetriNet &net, const MarkVal *initialMarking, const VarVal*, PQL::Condition *query){ assert(net.numberOfVariables() == 0); if(net.numberOfVariables() > 0){ //TODO: Return unknown, or could not be found return false; } const unsigned int nTransitions = net.numberOfTransitions(), nPlaces = net.numberOfPlaces(); MarkVal old_m[nPlaces]; MarkVal new_m[nPlaces]; memcpy(old_m, initialMarking, nPlaces * sizeof(MarkVal)); size_t depth = 1; uint8_t* stack = new uint8_t[MAX_DEPTH]; stack[0] = 0; uint8_t t = 0; while(true){ // Invariant: // old_m is the current marking // stack[depth] is where the next transtion goes // t is the next transition to fire while(!fire(net, t, old_m, new_m)){ while(++t == nTransitions){ if(--depth == 0) //Pop the stack return false; //Terminate algorithm, we're done now // Reverse transition on the stack t = stack[depth]; for(size_t i = 0; i < nPlaces; i++) old_m[i] -= net.transitionVector(t)[i]; } } //Test if query is satisfied if(query->evaluate(PQL::EvaluationContext(new_m, NULL))) return true; //Check if it's seen bool seen = false; size_t d = depth; while(--d > 0){ seen = true; const MarkVal* tv = net.transitionVector(stack[d]); for(size_t i = 0; i < nPlaces; i++){ old_m[i] -= tv[i]; seen &= old_m[i] == new_m[i]; if(!seen) break; } if(seen) break; } if(seen) printf("|"); else printf("%i", (int)t); fflush(stdout); memcpy(old_m, new_m, nPlaces * sizeof(MarkVal)); if(!seen){ stack[depth++] = t; t = 0; }else{ for(size_t i = 0; i < nPlaces; i++) old_m[i] -= net.transitionVector(t)[i]; //Pop if needed as long as needed while(++t == nTransitions){ if(--depth == 0) //Pop the stack return false; //Terminate algorithm, we're done now // Reverse transition on the stack t = stack[depth]; for(size_t i = 0; i < nPlaces; i++) old_m[i] -= net.transitionVector(t)[i]; } } } }
ReachabilityResult IndexedBestFS::reachable(const PetriNet &net, const MarkVal *m0, const VarVal *v0, const BoolVal *ba, PQL::Condition *query){ StateAllocator<> allocator(net); State* s0 = allocator.createState(); memcpy(s0->marking(), m0, sizeof(MarkVal) * net.numberOfPlaces()); memcpy(s0->intValuation(), v0, sizeof(VarVal) * net.numberOfIntVariables()); memcpy(s0->boolValuation(), ba, sizeof(BoolVal) * net.numberOfBoolVariables()); if(query->evaluate(*s0)) return ReachabilityResult(ReachabilityResult::Satisfied, "Satisfied initially", 0, 0); //Initialize subclasses MonotonicityContext context(&net, query); context.analyze(); //Initialise StateSet IndexedBestFSStateSet states(net, &context, _distanceStrategy, query, _varianceFirst); states.add(s0); //Allocate new state State* ns = allocator.createState(); int count = 0; BigInt expandedStates = 0; BigInt exploredStates = 0; BigInt transitionFired = 0; size_t max = 1; State* s = states.getNextState(); while(s){ if(count++ & 1<<16){ count = 0; if(states.waitingSize() > max) max = states.waitingSize(); this->reportProgress((double)(max - states.waitingSize()) / ((double)(max))); if(this->abortRequested()) return ReachabilityResult(ReachabilityResult::Unknown, "Query aborted!"); } // Attempt to fire each transition for(unsigned int t = 0; t < net.numberOfTransitions(); t++){ if(net.fire(t, s, ns)){ //If it's new transitionFired++; if(states.add(ns)){ exploredStates++; //Set parent and transition for the state ns->setParent(s); ns->setTransition(t); //Test query if(query->evaluate(*ns)){ //ns->dumpTrace(net); return ReachabilityResult(ReachabilityResult::Satisfied, "Query was satified!", expandedStates, exploredStates, transitionFired, states.getCountRemove(), ns->pathLength(), ns->trace()); } //Allocate new state, as states take ownership ns = allocator.createState(); } } } //Take something out of the queue expandedStates++; s = states.getNextState(); } return ReachabilityResult(ReachabilityResult::NotSatisfied, "Query cannot be satisfied!", expandedStates, exploredStates, transitionFired, states.getCountRemove()); }
ReachabilityResult MagicSearch::reachable(const PetriNet &net, const MarkVal *m0, const VarVal *v0, PQL::Condition *query){ SmartStateAllocator<MEMORY_BOUND> allocator(net); SmartStateSet states(net); EnhancedPriorityQueue<Step> queue; _dm = new Structures::DistanceMatrix(net); { //Compute constraints ConstraintAnalysisContext context(net); query->findConstraints(context); if(context.canAnalyze) contraints = context.retval; } //Create s0 SmartState* s0 = allocator.createStoredState(); memcpy(s0->marking(), m0, sizeof(MarkVal) * net.numberOfPlaces()); memcpy(s0->valuation(), v0, sizeof(VarVal) * net.numberOfVariables()); states.add(s0, s0->marking(), s0->valuation()); Step step0; step0.depth = 0; step0.lastApprox = INT_MAX; step0.lastStored = 0; step0.state = s0; queue.push(0, step0); //Temporary marking and valuation to work with MarkVal tmpM[net.numberOfPlaces()]; VarVal tmpV[net.numberOfVariables()]; SmartState* ns = allocator.createStoredState(); SmartState* ls = allocator.createState(); //Statistics int lastReport = 0; BigInt expanded = 0, explored = 0; size_t max = 1; //Main loop while(!queue.empty()){ // Report progress if needed if(lastReport++ & 1<<17){ lastReport = 0; if(queue.size() > max) max = queue.size(); this->reportProgress((double)(max - queue.size()) / ((double)(max))); if(this->abortRequested()) return ReachabilityResult(ReachabilityResult::Unknown, "Query aborted!"); } //Pop stuff of the queue Step step = queue.pop(depthFirst); expanded++; //Cound expanded states // Get current state const MarkVal* m; const VarVal* v; if(step.state->stored()){ m = step.state->marking(); v = step.state->valuation(); }else{ step.state->getState(net, tmpM, tmpV); m = tmpM; v = tmpV; } //Attempt to exclude by over-approx if(step.lastApprox >= approxScale(step.depth)){ if(canExcludeByOverApprox(net, m, v)) continue; step.lastApprox = 0; } for(unsigned int t = 0; t < net.numberOfTransitions(); t++){ //Fire the transition if(net.fire(t, m, v, ns->marking(), ns->valuation())){ //Determine whether or not to store the entire state bool storeCurrentState = step.lastStored >= storeScale(allocator.percentMemoryUsed());// storeScale(allocator.percentMemoryUsed()); SmartState* storeState; if(storeCurrentState) storeState = ns; else storeState = ls; storeState->setParent(step.state); storeState->setTransition(t); //Add it to the state set if(states.add(storeState, ns->marking(), ns->valuation())){ explored++; //Count explored states //Test the query if(query->evaluate(EvaluationContext(ns->marking(), ns->valuation()))){ printf("\nmemory usage: %f\n",allocator.percentMemoryUsed()); return ReachabilityResult(ReachabilityResult::Satisfied, "Query was satified!", expanded, explored, storeState->pathLength(), storeState->trace()); } //Make the next step Step nextstep; nextstep.depth = step.depth + 1; nextstep.lastApprox = step.lastApprox + 1; if(storeState == ns) nextstep.lastStored = 0; else nextstep.lastStored = step.lastStored + 1; nextstep.state = storeState; //Push step on the queue double p = priority(ns->marking(), ns->valuation(), query, net); queue.push(p, nextstep); //Allocate new memory, depending on what was stored if(storeState == ns) ns = allocator.createStoredState(); else ls = allocator.createState(); } } } } return ReachabilityResult(ReachabilityResult::NotSatisfied, "Query cannot be satisfied!", expanded, explored); }