503
505
Place& place2 = parent->_places[p2];
505
507
// C2, C3. Consumer and producer-sets must match
506
if(place1.consumers.size() != place2.consumers.size() ||
507
place1.producers.size() != place2.producers.size())
508
if(place1.consumers.size() < place2.consumers.size() ||
509
place1.producers.size() > place2.producers.size())
510
uint mult = std::numeric_limits<uint>::max();
512
long double mult = 1;
512
514
// C8. Consumers must match with weights
514
for(int i = place1.consumers.size() - 1; i >= 0; --i)
517
for(size_t i = 0; i < place2.consumers.size(); ++i)
516
if(place1.consumers[i] != place2.consumers[i])
519
while(j < place1.consumers.size() && place1.consumers[j] < place2.consumers[i] ) ++j;
520
if(place1.consumers.size() <= j || place1.consumers[j] != place2.consumers[i])
522
Transition& trans = getTransition(place1.consumers[i]);
526
Transition& trans = getTransition(place1.consumers[j]);
523
527
auto a1 = getInArc(p1, trans);
524
528
auto a2 = getInArc(p2, trans);
525
if(a2 == trans.pre.end())
530
529
assert(a1 != trans.pre.end());
532
if(mult == std::numeric_limits<uint>::max())
534
if(a2->weight < a1->weight || (a2->weight % a1->weight) != 0)
539
mult = a2->weight / a1->weight;
541
else if(a1->weight*mult != a2->weight)
530
assert(a2 != trans.pre.end());
531
mult = std::max(mult, ((long double)a2->weight) / ((long double)a1->weight));
548
534
if(ok == 2) break;
549
else if(ok == 1) continue;
536
// C6. We do not care about excess markings in p2.
537
if(mult != std::numeric_limits<long double>::max() &&
538
(((long double)parent->initialMarking[p1]) * mult) > ((long double)parent->initialMarking[p2]))
551
544
// C7. Producers must match with weights
552
for(int i = place1.producers.size() - 1; i >= 0; --i)
546
for(size_t i = 0; i < place1.producers.size(); ++i)
554
if(place1.producers[i] != place2.producers[i])
548
while(place2.producers[j] < place1.producers[i] && j < place2.producers.size()) ++j;
549
if(place1.producers[i] != place2.producers[j])
784
766
return continueReductions;
769
bool Reducer::ReducebyRuleI(uint32_t* placeInQuery, bool remove_loops, bool remove_consumers) {
770
bool reduced = false;
773
std::vector<uint32_t> wtrans;
774
std::vector<bool> tseen(parent->numberOfTransitions(), false);
776
for(uint32_t p = 0; p < parent->numberOfPlaces(); ++p)
778
if(hasTimedout()) return false;
779
if(placeInQuery[p] > 0)
781
const Place& place = parent->_places[p];
782
for(auto t : place.consumers)
790
for(auto t : place.producers)
801
std::vector<bool> pseen(parent->numberOfPlaces(), false);
802
while(!wtrans.empty())
804
if(hasTimedout()) return false;
805
auto t = wtrans.back();
807
const Transition& trans = parent->_transitions[t];
808
for(const Arc& arc : trans.pre)
810
const Place& place = parent->_places[arc.place];
813
for(auto pt : place.consumers)
817
Transition& trans = parent->_transitions[pt];
818
auto it = trans.post.begin();
819
for(; it != trans.post.end(); ++it)
820
if(it->place >= arc.place) break;
821
if(it != trans.pre.end() && it->place == arc.place)
823
auto it2 = trans.pre.begin();
824
for(; it2 != trans.pre.end(); ++it2)
825
if(it2->place >= arc.place || it2->inhib) break;
826
if(it->weight <= it2->weight) continue;
829
wtrans.push_back(pt);
835
for(auto pt : place.producers)
839
Transition& trans = parent->_transitions[pt];
840
auto it = trans.pre.begin();
841
for(; it != trans.pre.end(); ++it)
842
if(it->place >= arc.place) break;
844
if(it != trans.pre.end() && it->place == arc.place && !it->inhib)
846
auto it2 = trans.post.begin();
847
for(; it2 != trans.post.end(); ++it2)
848
if(it2->place >= arc.place) break;
849
if(it->weight >= it2->weight) continue;
853
wtrans.push_back(pt);
857
for(auto pt : place.consumers)
859
if(!tseen[pt] && (!remove_consumers || placeInQuery[arc.place] > 0))
862
wtrans.push_back(pt);
866
pseen[arc.place] = true;
870
for(size_t t = 0; t < parent->numberOfTransitions(); ++t)
872
if(!tseen[t] && !parent->_transitions[t].skip)
879
for(size_t p = 0; p < parent->numberOfPlaces(); ++p)
881
if(!pseen[p] && !parent->_places[p].skip && placeInQuery[p] == 0)
883
assert(placeInQuery[p] == 0);
894
const size_t numberofplaces = parent->numberOfPlaces();
895
for(uint32_t p = 0; p < numberofplaces; ++p)
897
if(hasTimedout()) return false;
898
Place& place = parent->_places[p];
899
if(place.skip) continue;
900
if(place.inhib) continue;
901
if(placeInQuery[p] > 0) continue;
902
if(place.consumers.size() > 0) continue;
907
std::vector<uint32_t> torem;
908
for(auto& t : place.producers)
910
auto& trans = parent->_transitions[t];
911
if(trans.post.size() != 1) // place will be removed later
914
for(auto& a : trans.pre)
916
if(placeInQuery[a.place] > 0)
921
if(ok) torem.push_back(t);
926
assert(consistent());
787
933
bool Reducer::ReducebyRuleF(uint32_t* placeInQuery) {
788
934
bool continueReductions = false;
789
935
const size_t numberofplaces = parent->numberOfPlaces();
793
939
Place& place = parent->_places[p];
794
940
if(place.skip) continue;
795
941
if(place.inhib) continue;
796
if(placeInQuery[p] > 0) continue;
797
if(place.consumers.size() > 0) continue;
942
if(place.producers.size() < place.consumers.size()) continue;
943
if(placeInQuery[p] != 0) continue;
946
for(uint cons : place.consumers)
948
Transition& t = getTransition(cons);
949
auto w = getInArc(p, t)->weight;
950
if(w > parent->initialMarking[p])
957
auto it = getOutArc(t, p);
958
if(it == t.post.end() ||
800
continueReductions = true;
802
std::vector<uint32_t> torem;
803
for(auto& t : place.producers)
805
auto& trans = parent->_transitions[t];
806
if(trans.post.size() != 0)
809
for(auto& a : trans.pre)
811
if(placeInQuery[a.place] > 0)
816
if(ok) torem.push_back(t);
821
assert(consistent());
823
return continueReductions;
826
void Reducer::Reduce(QueryPlaceAnalysisContext& context, int enablereduction, bool reconstructTrace, int timeout) {
972
if((numberofplaces - _removedPlaces) > 1)
975
continueReductions = true;
979
assert(consistent());
980
return continueReductions;
984
bool Reducer::ReducebyRuleG(uint32_t* placeInQuery, bool remove_loops, bool remove_consumers) {
985
if(!remove_loops) return false;
986
bool continueReductions = false;
987
for(uint32_t t = 0; t < parent->numberOfTransitions(); ++t)
989
if(hasTimedout()) return false;
990
Transition& trans = parent->_transitions[t];
991
if(trans.skip) continue;
992
if(trans.inhib) continue;
993
if(trans.pre.size() < trans.post.size()) continue;
994
if(!remove_loops && trans.pre.size() == 0) continue;
996
auto postit = trans.post.begin();
997
auto preit = trans.pre.begin();
1002
if(preit == trans.pre.end() && postit == trans.post.end())
1004
if(preit == trans.pre.end())
1014
if(postit != trans.post.end() && preit->place == postit->place)
1016
if(!remove_consumers && preit->weight != postit->weight)
1021
if((placeInQuery[preit->place] > 0 && preit->weight != postit->weight) ||
1022
(placeInQuery[preit->place] == 0 && preit->weight < postit->weight))
1030
else if(postit == trans.post.end() || preit->place < postit->place)
1032
if(placeInQuery[preit->place] > 0 || !remove_consumers)
1041
// could not match a post with a pre
1051
assert(consistent());
1052
return continueReductions;
1055
bool Reducer::ReducebyRuleH(uint32_t* placeInQuery)
1057
bool continueReductions = false;
1058
for(uint32_t t1 = 0; t1 < parent->numberOfTransitions(); ++t1)
1060
auto& trans1 = parent->_transitions[t1];
1061
if(trans1.skip) continue;
1062
if(trans1.inhib) continue;
1063
if(trans1.pre.size() != 1) continue;
1064
if(trans1.post.size() != 1) continue;
1065
auto p1 = trans1.pre[0].place;
1066
auto p2 = trans1.post[0].place;
1067
if(trans1.pre[0].weight != 1) continue;
1068
if(trans1.post[0].weight != 1) continue;
1069
if(p1 == p2) continue;
1070
if(placeInQuery[p1] > 0) continue;
1071
if(placeInQuery[p2] > 0) continue;
1072
if(parent->_places[p1].inhib) continue;
1073
if(parent->_places[p2].inhib) continue;
1075
for(uint32_t t2 = t1 + 1; t2 < parent->numberOfTransitions(); ++t2)
1077
auto& trans2 = parent->_transitions[t2];
1078
if(trans2.skip) continue;
1079
if(trans2.inhib) continue;
1080
if(trans2.pre.size() != 1) continue;
1081
if(trans2.post.size() != 1) continue;
1082
if(trans2.pre[0].weight != 1) continue;
1083
if(trans2.post[0].weight != 1) continue;
1084
if(trans2.pre[0].place != p2) continue;
1085
if(trans2.post[0].place != p1) continue;
1090
auto& place1 = parent->_places[p1];
1091
auto& place2 = parent->_places[p2];
1095
for(auto p2it : place2.consumers)
1097
auto& t = parent->_transitions[p2it];
1098
auto arc = getInArc(p2, t);
1099
assert(arc != t.pre.end());
1100
assert(arc->place == p2);
1103
auto dest = std::lower_bound(t.pre.begin(), t.pre.end(), a);
1104
if(dest == t.pre.end() || dest->place != p1)
1106
t.pre.insert(dest, a);
1107
auto lb = std::lower_bound(place1.consumers.begin(), place1.consumers.end(), p2it);
1108
place1.consumers.insert(lb, p2it);
1112
dest->weight += a.weight;
1119
auto p2it = place2.producers.begin();
1121
for(;p2it != place2.producers.end(); ++p2it)
1123
auto& t = parent->_transitions[*p2it];
1124
Arc a = *getOutArc(t, p2);
1126
auto dest = std::lower_bound(t.post.begin(), t.post.end(), a);
1127
if(dest == t.post.end() || dest->place != p1)
1129
t.post.insert(dest, a);
1130
auto lb = std::lower_bound(place1.producers.begin(), place1.producers.end(), *p2it);
1131
place1.producers.insert(lb, *p2it);
1135
dest->weight += a.weight;
1141
parent->initialMarking[p1] += parent->initialMarking[p2];
1144
continueReductions = true;
1147
return continueReductions;
1150
void Reducer::Reduce(QueryPlaceAnalysisContext& context, int enablereduction, bool reconstructTrace, int timeout, bool remove_loops, bool remove_consumers, bool next_safe) {
827
1151
this->_timeout = timeout;
828
1152
_timer = std::chrono::high_resolution_clock::now();
829
1153
assert(consistent());
832
1156
bool changed = false;
1159
if(remove_loops && !next_safe)
1160
ReducebyRuleI(context.getQueryPlaceCount(), remove_loops, remove_consumers);
836
1162
changed = false;
837
changed |= ReducebyRuleA(context.getQueryPlaceCount());
838
changed |= ReducebyRuleB(context.getQueryPlaceCount());
1164
changed |= ReducebyRuleB(context.getQueryPlaceCount());
1165
changed |= ReducebyRuleA(context.getQueryPlaceCount());
839
1167
changed |= ReducebyRuleE(context.getQueryPlaceCount());
840
changed |= ReducebyRuleF(context.getQueryPlaceCount());
1170
changed |= ReducebyRuleF(context.getQueryPlaceCount());
1171
changed |= ReducebyRuleG(context.getQueryPlaceCount(), remove_loops, remove_consumers);
1173
changed |= ReducebyRuleI(context.getQueryPlaceCount(), remove_loops, remove_consumers);
841
1175
} while(changed && !hasTimedout());
842
1176
// RuleC and RuleD are expensive, so wait with those till nothing else changes
843
changed |= ReducebyRuleD(context.getQueryPlaceCount());
844
1177
changed |= ReducebyRuleC(context.getQueryPlaceCount());
1180
changed |= ReducebyRuleD(context.getQueryPlaceCount());
1183
// Only try RuleH last. It can reduce applicability of other rules.
1184
changed |= ReducebyRuleH(context.getQueryPlaceCount());
845
1186
} while(!hasTimedout() && changed);
847
} else if (enablereduction == 2) { // for k-boundedness checking only rules A and D are applicable
849
ReducebyRuleA(context.getQueryPlaceCount()) ||
850
ReducebyRuleD(context.getQueryPlaceCount())
851
) && !hasTimedout()) {
1188
} else if (enablereduction == 2) { // for k-boundedness checking only rules A, D and H are applicable
1189
bool changed = true;
1190
while (changed && !hasTimedout()) {
1194
changed |= ReducebyRuleA(context.getQueryPlaceCount());
1195
changed |= ReducebyRuleD(context.getQueryPlaceCount());
1196
changed |= ReducebyRuleH(context.getQueryPlaceCount());