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; }
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; }
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 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); }