Merge lp:~verifypn-stub/verifypn/ctl-structural into lp:verifypn
- ctl-structural
- Merge into new-trunk
Proposed by
Peter Gjøl Jensen
Status: | Merged |
---|---|
Approved by: | Jiri Srba |
Approved revision: | 224 |
Merged at revision: | 193 |
Proposed branch: | lp:~verifypn-stub/verifypn/ctl-structural |
Merge into: | lp:verifypn |
Diff against target: |
872 lines (+240/-109) 16 files modified
CTL/CTLEngine.cpp (+2/-2) CTL/CTLEngine.h (+1/-0) CTL/PetriNets/OnTheFlyDG.cpp (+21/-22) CTL/PetriNets/OnTheFlyDG.h (+26/-4) PetriEngine/PQL/Expressions.cpp (+4/-2) PetriEngine/PQL/Expressions.h (+15/-2) PetriEngine/PQL/PQL.h (+1/-1) PetriEngine/PetriNetBuilder.cpp (+2/-1) PetriEngine/PetriNetBuilder.h (+4/-0) PetriEngine/Reducer.cpp (+110/-45) PetriEngine/Reducer.h (+7/-2) PetriEngine/ReducingSuccessorGenerator.cpp (+9/-1) PetriEngine/ReducingSuccessorGenerator.h (+4/-2) PetriEngine/Structures/light_deque.h (+5/-0) PetriEngine/SuccessorGenerator.h (+2/-1) VerifyPN.cpp (+27/-24) |
To merge this branch: | bzr merge lp:~verifypn-stub/verifypn/ctl-structural |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jiri Srba | Approve | ||
Review via email: mp+335697@code.launchpad.net |
Commit message
Description of the change
Adds structural reductions to the CTL verification -- only enabled if the formulas are next-free.
Also adds partial order reduction to EF leafs in CTL verification, although only yielding a minor speedup.
Consistent on 2017 models.
Improvements;
CTLCardinality:
r180: 3916
r187: 3922
r188: 3999
trunk: 4154
this: 4201
CTLFireability:
r180: 3111
r187: 3171
r188: 3248
trunk: 3575
this: 3655
To post a comment you must log in.
- 224. By Peter Gjøl Jensen
-
propagating switch for po-reduction to ctl-engine
Revision history for this message
Jiri Srba (srba) wrote : | # |
Please, fix the warning:
CTL/PetriNets/
'
^
review:
Needs Fixing
- 225. By Peter Gjøl Jensen
-
fixed reorder warning
Revision history for this message
Jiri Srba (srba) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CTL/CTLEngine.cpp' | |||
2 | --- CTL/CTLEngine.cpp 2017-12-04 13:45:29 +0000 | |||
3 | +++ CTL/CTLEngine.cpp 2018-01-04 10:26:07 +0000 | |||
4 | @@ -66,7 +66,6 @@ | |||
5 | 66 | cout << " Processed Edges : " << result.processedEdges << endl; | 66 | cout << " Processed Edges : " << result.processedEdges << endl; |
6 | 67 | cout << " Processed N. Edges: " << result.processedNegationEdges << endl; | 67 | cout << " Processed N. Edges: " << result.processedNegationEdges << endl; |
7 | 68 | cout << " Explored Configs : " << result.exploredConfigurations << endl; | 68 | cout << " Explored Configs : " << result.exploredConfigurations << endl; |
8 | 69 | if(!only_stats) result.query->toString(cout); | ||
9 | 70 | std::cout << endl; | 69 | std::cout << endl; |
10 | 71 | } | 70 | } |
11 | 72 | } | 71 | } |
12 | @@ -77,6 +76,7 @@ | |||
13 | 77 | bool gamemode, | 76 | bool gamemode, |
14 | 78 | bool printstatistics, | 77 | bool printstatistics, |
15 | 79 | bool mccoutput, | 78 | bool mccoutput, |
16 | 79 | bool partial_order, | ||
17 | 80 | const std::vector<std::string>& querynames, | 80 | const std::vector<std::string>& querynames, |
18 | 81 | const std::vector<std::shared_ptr<Condition>>& queries, | 81 | const std::vector<std::shared_ptr<Condition>>& queries, |
19 | 82 | const std::vector<size_t>& querynumbers | 82 | const std::vector<size_t>& querynumbers |
20 | @@ -90,7 +90,7 @@ | |||
21 | 90 | 90 | ||
22 | 91 | for(auto qnum : querynumbers){ | 91 | for(auto qnum : querynumbers){ |
23 | 92 | CTLResult result(queries[qnum]); | 92 | CTLResult result(queries[qnum]); |
25 | 93 | PetriNets::OnTheFlyDG graph(net); | 93 | PetriNets::OnTheFlyDG graph(net, partial_order); |
26 | 94 | graph.setQuery(result.query); | 94 | graph.setQuery(result.query); |
27 | 95 | std::shared_ptr<Algorithm::FixedPointAlgorithm> alg = nullptr; | 95 | std::shared_ptr<Algorithm::FixedPointAlgorithm> alg = nullptr; |
28 | 96 | bool solved = false; | 96 | bool solved = false; |
29 | 97 | 97 | ||
30 | === modified file 'CTL/CTLEngine.h' | |||
31 | --- CTL/CTLEngine.h 2017-11-26 13:43:04 +0000 | |||
32 | +++ CTL/CTLEngine.h 2018-01-04 10:26:07 +0000 | |||
33 | @@ -16,6 +16,7 @@ | |||
34 | 16 | bool gamemode, | 16 | bool gamemode, |
35 | 17 | bool printstatistics, | 17 | bool printstatistics, |
36 | 18 | bool mccoutput, | 18 | bool mccoutput, |
37 | 19 | bool partial_order, | ||
38 | 19 | const std::vector<std::string>& querynames, | 20 | const std::vector<std::string>& querynames, |
39 | 20 | const std::vector<std::shared_ptr<PetriEngine::PQL::Condition>>& reducedQueries, | 21 | const std::vector<std::shared_ptr<PetriEngine::PQL::Condition>>& reducedQueries, |
40 | 21 | const std::vector<size_t>& ids); | 22 | const std::vector<size_t>& ids); |
41 | 22 | 23 | ||
42 | === modified file 'CTL/PetriNets/OnTheFlyDG.cpp' | |||
43 | --- CTL/PetriNets/OnTheFlyDG.cpp 2017-11-29 21:20:21 +0000 | |||
44 | +++ CTL/PetriNets/OnTheFlyDG.cpp 2018-01-04 10:26:07 +0000 | |||
45 | @@ -18,9 +18,10 @@ | |||
46 | 18 | 18 | ||
47 | 19 | namespace PetriNets { | 19 | namespace PetriNets { |
48 | 20 | 20 | ||
50 | 21 | OnTheFlyDG::OnTheFlyDG(PetriEngine::PetriNet *t_net) : encoder(t_net->numberOfPlaces(), 0), | 21 | OnTheFlyDG::OnTheFlyDG(PetriEngine::PetriNet *t_net, bool partial_order) : encoder(t_net->numberOfPlaces(), 0), |
51 | 22 | edge_alloc(new linked_bucket_t<DependencyGraph::Edge,1024*10>(1)), | 22 | edge_alloc(new linked_bucket_t<DependencyGraph::Edge,1024*10>(1)), |
53 | 23 | conf_alloc(new linked_bucket_t<char[sizeof(PetriConfig)], 1024*1024>(1)) { | 23 | conf_alloc(new linked_bucket_t<char[sizeof(PetriConfig)], 1024*1024>(1)), |
54 | 24 | _redgen(*t_net), _partial_order(partial_order) { | ||
55 | 24 | net = t_net; | 25 | net = t_net; |
56 | 25 | n_places = t_net->numberOfPlaces(); | 26 | n_places = t_net->numberOfPlaces(); |
57 | 26 | n_transitions = t_net->numberOfTransitions(); | 27 | n_transitions = t_net->numberOfTransitions(); |
58 | @@ -37,7 +38,6 @@ | |||
59 | 37 | { | 38 | { |
60 | 38 | ((PetriConfig*)&(*conf_alloc)[i])->~PetriConfig(); | 39 | ((PetriConfig*)&(*conf_alloc)[i])->~PetriConfig(); |
61 | 39 | } | 40 | } |
62 | 40 | std::cout << "NEDGES " << edge_alloc->size() << std::endl; | ||
63 | 41 | delete conf_alloc; | 41 | delete conf_alloc; |
64 | 42 | delete edge_alloc; | 42 | delete edge_alloc; |
65 | 43 | } | 43 | } |
66 | @@ -176,7 +176,7 @@ | |||
67 | 176 | if (valid || left != NULL) { | 176 | if (valid || left != NULL) { |
68 | 177 | //if left side is guaranteed to be not satisfied, skip successor generation | 177 | //if left side is guaranteed to be not satisfied, skip successor generation |
69 | 178 | Edge* leftEdge = NULL; | 178 | Edge* leftEdge = NULL; |
71 | 179 | nextStates (query_marking, | 179 | nextStates (query_marking, cond, |
72 | 180 | [&](){ leftEdge = newEdge(*v, std::numeric_limits<uint32_t>::max());}, | 180 | [&](){ leftEdge = newEdge(*v, std::numeric_limits<uint32_t>::max());}, |
73 | 181 | [&](Marking& mark){ | 181 | [&](Marking& mark){ |
74 | 182 | auto res = fastEval(cond, &mark); | 182 | auto res = fastEval(cond, &mark); |
75 | @@ -227,7 +227,7 @@ | |||
76 | 227 | subquery->addTarget(c); | 227 | subquery->addTarget(c); |
77 | 228 | } | 228 | } |
78 | 229 | Edge* e1 = NULL; | 229 | Edge* e1 = NULL; |
80 | 230 | nextStates(query_marking, | 230 | nextStates(query_marking, cond, |
81 | 231 | [&](){e1 = newEdge(*v, std::numeric_limits<uint32_t>::max());}, | 231 | [&](){e1 = newEdge(*v, std::numeric_limits<uint32_t>::max());}, |
82 | 232 | [&](Marking& mark) | 232 | [&](Marking& mark) |
83 | 233 | { | 233 | { |
84 | @@ -264,7 +264,7 @@ | |||
85 | 264 | auto cond = static_cast<AXCondition*>(v->query); | 264 | auto cond = static_cast<AXCondition*>(v->query); |
86 | 265 | Edge* e = newEdge(*v, std::numeric_limits<uint32_t>::max()); | 265 | Edge* e = newEdge(*v, std::numeric_limits<uint32_t>::max()); |
87 | 266 | Condition::Result allValid = Condition::RTRUE; | 266 | Condition::Result allValid = Condition::RTRUE; |
89 | 267 | nextStates(query_marking, | 267 | nextStates(query_marking, cond, |
90 | 268 | [](){}, | 268 | [](){}, |
91 | 269 | [&](Marking& mark){ | 269 | [&](Marking& mark){ |
92 | 270 | auto res = fastEval((*cond)[0], &mark); | 270 | auto res = fastEval((*cond)[0], &mark); |
93 | @@ -326,7 +326,7 @@ | |||
94 | 326 | 326 | ||
95 | 327 | Configuration *left = NULL; | 327 | Configuration *left = NULL; |
96 | 328 | bool valid = false; | 328 | bool valid = false; |
98 | 329 | nextStates(query_marking, | 329 | nextStates(query_marking, cond, |
99 | 330 | [&](){ | 330 | [&](){ |
100 | 331 | auto r0 = fastEval((*cond)[0], &query_marking); | 331 | auto r0 = fastEval((*cond)[0], &query_marking); |
101 | 332 | if (r0 == Condition::RUNKNOWN) { | 332 | if (r0 == Condition::RUNKNOWN) { |
102 | @@ -389,7 +389,7 @@ | |||
103 | 389 | subquery->addTarget(c); | 389 | subquery->addTarget(c); |
104 | 390 | } | 390 | } |
105 | 391 | 391 | ||
107 | 392 | nextStates(query_marking, | 392 | nextStates(query_marking, cond, |
108 | 393 | [](){}, | 393 | [](){}, |
109 | 394 | [&](Marking& mark){ | 394 | [&](Marking& mark){ |
110 | 395 | auto res = fastEval(cond, &mark); | 395 | auto res = fastEval(cond, &mark); |
111 | @@ -424,7 +424,7 @@ | |||
112 | 424 | else if(v->query->getPath() == X){ | 424 | else if(v->query->getPath() == X){ |
113 | 425 | auto cond = static_cast<EXCondition*>(v->query); | 425 | auto cond = static_cast<EXCondition*>(v->query); |
114 | 426 | auto query = (*cond)[0]; | 426 | auto query = (*cond)[0]; |
116 | 427 | nextStates(query_marking, | 427 | nextStates(query_marking, cond, |
117 | 428 | [](){}, | 428 | [](){}, |
118 | 429 | [&](Marking& marking) { | 429 | [&](Marking& marking) { |
119 | 430 | auto res = fastEval(query, &marking); | 430 | auto res = fastEval(query, &marking); |
120 | @@ -478,25 +478,24 @@ | |||
121 | 478 | return initial_config; | 478 | return initial_config; |
122 | 479 | } | 479 | } |
123 | 480 | 480 | ||
125 | 481 | void OnTheFlyDG::nextStates(Marking& t_marking, | 481 | |
126 | 482 | void OnTheFlyDG::nextStates(Marking& t_marking, Condition* ptr, | ||
127 | 482 | std::function<void ()> pre, | 483 | std::function<void ()> pre, |
128 | 483 | std::function<bool (Marking&)> foreach, | 484 | std::function<bool (Marking&)> foreach, |
129 | 484 | std::function<void ()> post) | 485 | std::function<void ()> post) |
130 | 485 | { | 486 | { |
131 | 486 | |||
132 | 487 | bool first = true; | 487 | bool first = true; |
133 | 488 | PetriEngine::SuccessorGenerator PNGen(*net); | ||
134 | 489 | PNGen.prepare(&query_marking); | ||
135 | 490 | memcpy(working_marking.marking(), query_marking.marking(), n_places*sizeof(PetriEngine::MarkVal)); | 488 | memcpy(working_marking.marking(), query_marking.marking(), n_places*sizeof(PetriEngine::MarkVal)); |
145 | 491 | 489 | auto qf = static_cast<QuantifierCondition*>(ptr); | |
146 | 492 | 490 | if(!_partial_order || ptr->getQuantifier() != E || ptr->getPath() != F || (*qf)[0]->isTemporal()) | |
147 | 493 | while(PNGen.next(working_marking)){ | 491 | { |
148 | 494 | if(first) pre(); | 492 | PetriEngine::SuccessorGenerator PNGen(*net); |
149 | 495 | first = false; | 493 | dowork<PetriEngine::SuccessorGenerator>(PNGen, first, pre, foreach); |
150 | 496 | if(!foreach(working_marking)) | 494 | } |
151 | 497 | { | 495 | else |
152 | 498 | break; | 496 | { |
153 | 499 | } | 497 | _redgen.setQuery(ptr); |
154 | 498 | dowork<PetriEngine::ReducingSuccessorGenerator>(_redgen, first, pre, foreach); | ||
155 | 500 | } | 499 | } |
156 | 501 | 500 | ||
157 | 502 | if(!first) post(); | 501 | if(!first) post(); |
158 | 503 | 502 | ||
159 | === modified file 'CTL/PetriNets/OnTheFlyDG.h' | |||
160 | --- CTL/PetriNets/OnTheFlyDG.h 2017-11-26 22:46:37 +0000 | |||
161 | +++ CTL/PetriNets/OnTheFlyDG.h 2018-01-04 10:26:07 +0000 | |||
162 | @@ -12,6 +12,7 @@ | |||
163 | 12 | #include "PetriEngine/Structures/ptrie_map.h" | 12 | #include "PetriEngine/Structures/ptrie_map.h" |
164 | 13 | #include "PetriEngine/Structures/AlignedEncoder.h" | 13 | #include "PetriEngine/Structures/AlignedEncoder.h" |
165 | 14 | #include "PetriEngine/Structures/linked_bucket.h" | 14 | #include "PetriEngine/Structures/linked_bucket.h" |
166 | 15 | #include "PetriEngine/ReducingSuccessorGenerator.h" | ||
167 | 15 | 16 | ||
168 | 16 | namespace PetriNets { | 17 | namespace PetriNets { |
169 | 17 | class OnTheFlyDG : public DependencyGraph::BasicDependencyGraph | 18 | class OnTheFlyDG : public DependencyGraph::BasicDependencyGraph |
170 | @@ -20,7 +21,7 @@ | |||
171 | 20 | using Condition = PetriEngine::PQL::Condition; | 21 | using Condition = PetriEngine::PQL::Condition; |
172 | 21 | using Condition_ptr = PetriEngine::PQL::Condition_ptr; | 22 | using Condition_ptr = PetriEngine::PQL::Condition_ptr; |
173 | 22 | using Marking = PetriEngine::Structures::State; | 23 | using Marking = PetriEngine::Structures::State; |
175 | 23 | OnTheFlyDG(PetriEngine::PetriNet *t_net); | 24 | OnTheFlyDG(PetriEngine::PetriNet *t_net, bool partial_order); |
176 | 24 | 25 | ||
177 | 25 | virtual ~OnTheFlyDG(); | 26 | virtual ~OnTheFlyDG(); |
178 | 26 | 27 | ||
179 | @@ -57,7 +58,6 @@ | |||
180 | 57 | uint32_t n_places = 0; | 58 | uint32_t n_places = 0; |
181 | 58 | size_t _markingCount = 0; | 59 | size_t _markingCount = 0; |
182 | 59 | size_t _configurationCount = 0; | 60 | size_t _configurationCount = 0; |
183 | 60 | |||
184 | 61 | //used after query is set | 61 | //used after query is set |
185 | 62 | Condition_ptr query = nullptr; | 62 | Condition_ptr query = nullptr; |
186 | 63 | 63 | ||
187 | @@ -66,10 +66,27 @@ | |||
188 | 66 | { | 66 | { |
189 | 67 | return fastEval(query.get(), unfolded); | 67 | return fastEval(query.get(), unfolded); |
190 | 68 | } | 68 | } |
192 | 69 | void nextStates(Marking& t_marking, | 69 | void nextStates(Marking& t_marking, Condition*, |
193 | 70 | std::function<void ()> pre, | 70 | std::function<void ()> pre, |
194 | 71 | std::function<bool (Marking&)> foreach, | 71 | std::function<bool (Marking&)> foreach, |
195 | 72 | std::function<void ()> post); | 72 | std::function<void ()> post); |
196 | 73 | template<typename T> | ||
197 | 74 | void dowork(T& gen, bool& first, | ||
198 | 75 | std::function<void ()>& pre, | ||
199 | 76 | std::function<bool (Marking&)>& foreach) | ||
200 | 77 | { | ||
201 | 78 | gen.prepare(&query_marking); | ||
202 | 79 | |||
203 | 80 | while(gen.next(working_marking)){ | ||
204 | 81 | if(first) pre(); | ||
205 | 82 | first = false; | ||
206 | 83 | if(!foreach(working_marking)) | ||
207 | 84 | { | ||
208 | 85 | gen.reset(); | ||
209 | 86 | break; | ||
210 | 87 | } | ||
211 | 88 | } | ||
212 | 89 | } | ||
213 | 73 | PetriConfig *createConfiguration(size_t marking, size_t own, Condition* query); | 90 | PetriConfig *createConfiguration(size_t marking, size_t own, Condition* query); |
214 | 74 | PetriConfig *createConfiguration(size_t marking, size_t own, const Condition_ptr& query) | 91 | PetriConfig *createConfiguration(size_t marking, size_t own, const Condition_ptr& query) |
215 | 75 | { | 92 | { |
216 | @@ -86,7 +103,12 @@ | |||
217 | 86 | 103 | ||
218 | 87 | // Problem with linked bucket and complex constructor | 104 | // Problem with linked bucket and complex constructor |
219 | 88 | linked_bucket_t<char[sizeof(PetriConfig)], 1024*1024>* conf_alloc = nullptr; | 105 | linked_bucket_t<char[sizeof(PetriConfig)], 1024*1024>* conf_alloc = nullptr; |
221 | 89 | 106 | ||
222 | 107 | PetriEngine::ReducingSuccessorGenerator _redgen; | ||
223 | 108 | bool _partial_order = false; | ||
224 | 109 | |||
225 | 90 | }; | 110 | }; |
226 | 111 | |||
227 | 112 | |||
228 | 91 | } | 113 | } |
229 | 92 | #endif // ONTHEFLYDG_H | 114 | #endif // ONTHEFLYDG_H |
230 | 93 | 115 | ||
231 | === modified file 'PetriEngine/PQL/Expressions.cpp' | |||
232 | --- PetriEngine/PQL/Expressions.cpp 2017-12-14 08:59:40 +0000 | |||
233 | +++ PetriEngine/PQL/Expressions.cpp 2018-01-04 10:26:07 +0000 | |||
234 | @@ -2997,11 +2997,13 @@ | |||
235 | 2997 | } | 2997 | } |
236 | 2998 | 2998 | ||
237 | 2999 | void SimpleQuantifierCondition::findInteresting(ReducingSuccessorGenerator& generator, bool negated) const{ | 2999 | void SimpleQuantifierCondition::findInteresting(ReducingSuccessorGenerator& generator, bool negated) const{ |
239 | 3000 | // Not implemented | 3000 | _cond->findInteresting(generator, negated); |
240 | 3001 | } | 3001 | } |
241 | 3002 | 3002 | ||
242 | 3003 | void UntilCondition::findInteresting(ReducingSuccessorGenerator& generator, bool negated) const{ | 3003 | void UntilCondition::findInteresting(ReducingSuccessorGenerator& generator, bool negated) const{ |
244 | 3004 | // Not implemented | 3004 | _cond1->findInteresting(generator, negated); |
245 | 3005 | _cond1->findInteresting(generator, !negated); | ||
246 | 3006 | _cond2->findInteresting(generator, negated); | ||
247 | 3005 | } | 3007 | } |
248 | 3006 | 3008 | ||
249 | 3007 | void AndCondition::findInteresting(ReducingSuccessorGenerator& generator, bool negated) const { | 3009 | void AndCondition::findInteresting(ReducingSuccessorGenerator& generator, bool negated) const { |
250 | 3008 | 3010 | ||
251 | === modified file 'PetriEngine/PQL/Expressions.h' | |||
252 | --- PetriEngine/PQL/Expressions.h 2017-12-13 14:17:08 +0000 | |||
253 | +++ PetriEngine/PQL/Expressions.h 2018-01-04 10:26:07 +0000 | |||
254 | @@ -254,6 +254,7 @@ | |||
255 | 254 | bool isUpperBound() override; | 254 | bool isUpperBound() override; |
256 | 255 | void findInteresting(ReducingSuccessorGenerator& generator, bool negated) const override; | 255 | void findInteresting(ReducingSuccessorGenerator& generator, bool negated) const override; |
257 | 256 | virtual const Condition_ptr& operator[] (size_t i) const override { return _cond;} | 256 | virtual const Condition_ptr& operator[] (size_t i) const override { return _cond;} |
258 | 257 | virtual bool containsNext() const override { return _cond->containsNext(); } | ||
259 | 257 | private: | 258 | private: |
260 | 258 | virtual std::string op() const = 0; | 259 | virtual std::string op() const = 0; |
261 | 259 | 260 | ||
262 | @@ -272,7 +273,7 @@ | |||
263 | 272 | Quantifier getQuantifier() const override { return Quantifier::E; } | 273 | Quantifier getQuantifier() const override { return Quantifier::E; } |
264 | 273 | Path getPath() const override { return Path::X; } | 274 | Path getPath() const override { return Path::X; } |
265 | 274 | uint32_t distance(DistanceContext& context) const override; | 275 | uint32_t distance(DistanceContext& context) const override; |
267 | 275 | 276 | bool containsNext() const override { return true; } | |
268 | 276 | private: | 277 | private: |
269 | 277 | std::string op() const override; | 278 | std::string op() const override; |
270 | 278 | }; | 279 | }; |
271 | @@ -324,6 +325,7 @@ | |||
272 | 324 | Quantifier getQuantifier() const override { return Quantifier::A; } | 325 | Quantifier getQuantifier() const override { return Quantifier::A; } |
273 | 325 | Path getPath() const override { return Path::X; } | 326 | Path getPath() const override { return Path::X; } |
274 | 326 | uint32_t distance(DistanceContext& context) const override; | 327 | uint32_t distance(DistanceContext& context) const override; |
275 | 328 | bool containsNext() const override { return true; } | ||
276 | 327 | private: | 329 | private: |
277 | 328 | std::string op() const override; | 330 | std::string op() const override; |
278 | 329 | }; | 331 | }; |
279 | @@ -385,7 +387,7 @@ | |||
280 | 385 | { if(i == 0) return _cond1; return _cond2;} | 387 | { if(i == 0) return _cond1; return _cond2;} |
281 | 386 | Path getPath() const override | 388 | Path getPath() const override |
282 | 387 | { return Path::U; } | 389 | { return Path::U; } |
284 | 388 | 390 | bool containsNext() const override { return _cond1->containsNext() || _cond2->containsNext(); } | |
285 | 389 | private: | 391 | private: |
286 | 390 | virtual std::string op() const = 0; | 392 | virtual std::string op() const = 0; |
287 | 391 | 393 | ||
288 | @@ -463,6 +465,9 @@ | |||
289 | 463 | { return _compiled->getQueryType(); } | 465 | { return _compiled->getQueryType(); } |
290 | 464 | int formulaSize() const override | 466 | int formulaSize() const override |
291 | 465 | { return _compiled->formulaSize(); } | 467 | { return _compiled->formulaSize(); } |
292 | 468 | bool containsNext() const override | ||
293 | 469 | { return false; } | ||
294 | 470 | |||
295 | 466 | private: | 471 | private: |
296 | 467 | std::string _name; | 472 | std::string _name; |
297 | 468 | Condition_ptr _compiled; | 473 | Condition_ptr _compiled; |
298 | @@ -503,6 +508,8 @@ | |||
299 | 503 | auto end() const { return _conds.end(); } | 508 | auto end() const { return _conds.end(); } |
300 | 504 | bool empty() const { return _conds.size() == 0; } | 509 | bool empty() const { return _conds.size() == 0; } |
301 | 505 | bool singular() const { return _conds.size() == 1; } | 510 | bool singular() const { return _conds.size() == 1; } |
302 | 511 | bool containsNext() const override | ||
303 | 512 | { return std::any_of(begin(), end(), [](auto& a){return a->containsNext();}); } | ||
304 | 506 | protected: | 513 | protected: |
305 | 507 | LogicalCondition() {}; | 514 | LogicalCondition() {}; |
306 | 508 | Retval simplifyOr(SimplificationContext& context) const; | 515 | Retval simplifyOr(SimplificationContext& context) const; |
307 | @@ -632,6 +639,8 @@ | |||
308 | 632 | (_constraints[0]._lower == 0 || | 639 | (_constraints[0]._lower == 0 || |
309 | 633 | _constraints[0]._upper == std::numeric_limits<uint32_t>::max()); | 640 | _constraints[0]._upper == std::numeric_limits<uint32_t>::max()); |
310 | 634 | }; | 641 | }; |
311 | 642 | bool containsNext() const override { return false;} | ||
312 | 643 | |||
313 | 635 | private: | 644 | private: |
314 | 636 | std::vector<cons_t> _constraints; | 645 | std::vector<cons_t> _constraints; |
315 | 637 | bool _negated = false; | 646 | bool _negated = false; |
316 | @@ -665,6 +674,7 @@ | |||
317 | 665 | if(id == 0) return _expr1; | 674 | if(id == 0) return _expr1; |
318 | 666 | else return _expr2; | 675 | else return _expr2; |
319 | 667 | } | 676 | } |
320 | 677 | bool containsNext() const override { return false; } | ||
321 | 668 | protected: | 678 | protected: |
322 | 669 | uint32_t _distance(DistanceContext& c, | 679 | uint32_t _distance(DistanceContext& c, |
323 | 670 | std::function<uint32_t(uint32_t, uint32_t, bool)> d) const | 680 | std::function<uint32_t(uint32_t, uint32_t, bool)> d) const |
324 | @@ -825,6 +835,7 @@ | |||
325 | 825 | CTLType getQueryType() const override { return CTLType::LOPERATOR; } | 835 | CTLType getQueryType() const override { return CTLType::LOPERATOR; } |
326 | 826 | const Condition_ptr& operator[](size_t i) const { return _cond; }; | 836 | const Condition_ptr& operator[](size_t i) const { return _cond; }; |
327 | 827 | virtual bool isTemporal() const override { return _temporal;} | 837 | virtual bool isTemporal() const override { return _temporal;} |
328 | 838 | bool containsNext() const override { return _cond->containsNext(); } | ||
329 | 828 | 839 | ||
330 | 829 | private: | 840 | private: |
331 | 830 | Condition_ptr _cond; | 841 | Condition_ptr _cond; |
332 | @@ -864,6 +875,7 @@ | |||
333 | 864 | Quantifier getQuantifier() const override { return Quantifier::EMPTY; } | 875 | Quantifier getQuantifier() const override { return Quantifier::EMPTY; } |
334 | 865 | Path getPath() const override { return Path::pError; } | 876 | Path getPath() const override { return Path::pError; } |
335 | 866 | CTLType getQueryType() const override { return CTLType::EVAL; } | 877 | CTLType getQueryType() const override { return CTLType::EVAL; } |
336 | 878 | bool containsNext() const override { return false; } | ||
337 | 867 | private: | 879 | private: |
338 | 868 | const bool _value; | 880 | const bool _value; |
339 | 869 | }; | 881 | }; |
340 | @@ -894,6 +906,7 @@ | |||
341 | 894 | Quantifier getQuantifier() const override { return Quantifier::EMPTY; } | 906 | Quantifier getQuantifier() const override { return Quantifier::EMPTY; } |
342 | 895 | Path getPath() const override { return Path::pError; } | 907 | Path getPath() const override { return Path::pError; } |
343 | 896 | CTLType getQueryType() const override { return CTLType::EVAL; } | 908 | CTLType getQueryType() const override { return CTLType::EVAL; } |
344 | 909 | bool containsNext() const override { return false; } | ||
345 | 897 | }; | 910 | }; |
346 | 898 | 911 | ||
347 | 899 | } | 912 | } |
348 | 900 | 913 | ||
349 | === modified file 'PetriEngine/PQL/PQL.h' | |||
350 | --- PetriEngine/PQL/PQL.h 2017-12-11 08:24:36 +0000 | |||
351 | +++ PetriEngine/PQL/PQL.h 2018-01-04 10:26:07 +0000 | |||
352 | @@ -289,7 +289,7 @@ | |||
353 | 289 | virtual Path getPath() const = 0; | 289 | virtual Path getPath() const = 0; |
354 | 290 | static std::shared_ptr<Condition> | 290 | static std::shared_ptr<Condition> |
355 | 291 | initialMarkingRW(std::function<std::shared_ptr<Condition> ()> func, negstat_t& stats, const EvaluationContext& context, bool nested, bool negated); | 291 | initialMarkingRW(std::function<std::shared_ptr<Condition> ()> func, negstat_t& stats, const EvaluationContext& context, bool nested, bool negated); |
357 | 292 | 292 | virtual bool containsNext() const = 0; | |
358 | 293 | protected: | 293 | protected: |
359 | 294 | //Value for checking if condition is trivially true or false. | 294 | //Value for checking if condition is trivially true or false. |
360 | 295 | //0 is undecided (default), 1 is true, 2 is false. | 295 | //0 is undecided (default), 1 is true, 2 is false. |
361 | 296 | 296 | ||
362 | === modified file 'PetriEngine/PetriNetBuilder.cpp' | |||
363 | --- PetriEngine/PetriNetBuilder.cpp 2017-12-08 12:21:38 +0000 | |||
364 | +++ PetriEngine/PetriNetBuilder.cpp 2018-01-04 10:26:07 +0000 | |||
365 | @@ -395,7 +395,8 @@ | |||
366 | 395 | QueryPlaceAnalysisContext placecontext(getPlaceNames(), getTransitionNames(), net); | 395 | QueryPlaceAnalysisContext placecontext(getPlaceNames(), getTransitionNames(), net); |
367 | 396 | for(uint32_t i = 0; i < queries.size(); ++i) | 396 | for(uint32_t i = 0; i < queries.size(); ++i) |
368 | 397 | { | 397 | { |
370 | 398 | if(results[i] == Reachability::ResultPrinter::Unknown) | 398 | if(results[i] == Reachability::ResultPrinter::Unknown || |
371 | 399 | results[i] == Reachability::ResultPrinter::CTL ) | ||
372 | 399 | { | 400 | { |
373 | 400 | queries[i]->analyze(placecontext); | 401 | queries[i]->analyze(placecontext); |
374 | 401 | } | 402 | } |
375 | 402 | 403 | ||
376 | === modified file 'PetriEngine/PetriNetBuilder.h' | |||
377 | --- PetriEngine/PetriNetBuilder.h 2017-12-08 13:28:43 +0000 | |||
378 | +++ PetriEngine/PetriNetBuilder.h 2018-01-04 10:26:07 +0000 | |||
379 | @@ -112,6 +112,10 @@ | |||
380 | 112 | return reducer.RuleE(); | 112 | return reducer.RuleE(); |
381 | 113 | } | 113 | } |
382 | 114 | 114 | ||
383 | 115 | size_t RuleF() const { | ||
384 | 116 | return reducer.RuleF(); | ||
385 | 117 | } | ||
386 | 118 | |||
387 | 115 | Reducer* getReducer() { return &reducer; } | 119 | Reducer* getReducer() { return &reducer; } |
388 | 116 | 120 | ||
389 | 117 | std::vector<std::pair<std::string, uint32_t>> orphanPlaces() const { | 121 | std::vector<std::pair<std::string, uint32_t>> orphanPlaces() const { |
390 | 118 | 122 | ||
391 | === modified file 'PetriEngine/Reducer.cpp' | |||
392 | --- PetriEngine/Reducer.cpp 2017-12-08 13:34:25 +0000 | |||
393 | +++ PetriEngine/Reducer.cpp 2018-01-04 10:26:07 +0000 | |||
394 | @@ -10,11 +10,12 @@ | |||
395 | 10 | #include "PetriNetBuilder.h" | 10 | #include "PetriNetBuilder.h" |
396 | 11 | #include <PetriParse/PNMLParser.h> | 11 | #include <PetriParse/PNMLParser.h> |
397 | 12 | #include <queue> | 12 | #include <queue> |
398 | 13 | #include <set> | ||
399 | 13 | 14 | ||
400 | 14 | namespace PetriEngine { | 15 | namespace PetriEngine { |
401 | 15 | 16 | ||
402 | 16 | Reducer::Reducer(PetriNetBuilder* p) | 17 | Reducer::Reducer(PetriNetBuilder* p) |
404 | 17 | : _removedTransitions(0), _removedPlaces(0), _ruleA(0), _ruleB(0), _ruleC(0), _ruleD(0), _ruleE(0), parent(p) { | 18 | : _removedTransitions(0), _removedPlaces(0), _ruleA(0), _ruleB(0), _ruleC(0), _ruleD(0), _ruleE(0), _ruleF(0), parent(p) { |
405 | 18 | } | 19 | } |
406 | 19 | 20 | ||
407 | 20 | Reducer::~Reducer() { | 21 | Reducer::~Reducer() { |
408 | @@ -180,12 +181,14 @@ | |||
409 | 180 | assert(!t.skip || (t.pre.size() == 0 && t.post.size() == 0)); | 181 | assert(!t.skip || (t.pre.size() == 0 && t.post.size() == 0)); |
410 | 181 | for(Arc& a : t.pre) | 182 | for(Arc& a : t.pre) |
411 | 182 | { | 183 | { |
412 | 184 | assert(a.weight > 0); | ||
413 | 183 | Place& p = parent->_places[a.place]; | 185 | Place& p = parent->_places[a.place]; |
414 | 184 | assert(!p.skip); | 186 | assert(!p.skip); |
415 | 185 | assert(std::find(p.consumers.begin(), p.consumers.end(), i) != p.consumers.end()); | 187 | assert(std::find(p.consumers.begin(), p.consumers.end(), i) != p.consumers.end()); |
416 | 186 | } | 188 | } |
417 | 187 | for(Arc& a : t.post) | 189 | for(Arc& a : t.post) |
418 | 188 | { | 190 | { |
419 | 191 | assert(a.weight > 0); | ||
420 | 189 | Place& p = parent->_places[a.place]; | 192 | Place& p = parent->_places[a.place]; |
421 | 190 | assert(!p.skip); | 193 | assert(!p.skip); |
422 | 191 | assert(std::find(p.producers.begin(), p.producers.end(), i) != p.producers.end()); | 194 | assert(std::find(p.producers.begin(), p.producers.end(), i) != p.producers.end()); |
423 | @@ -239,14 +242,10 @@ | |||
424 | 239 | 242 | ||
425 | 240 | // A2. we have more/less than one arc in pre or post | 243 | // A2. we have more/less than one arc in pre or post |
426 | 241 | // checked first to avoid out-of-bounds when looking up indexes. | 244 | // checked first to avoid out-of-bounds when looking up indexes. |
428 | 242 | if(trans.pre.size() != 1 || trans.post.size() != 1) continue; | 245 | if(trans.pre.size() != 1) continue; |
429 | 243 | 246 | ||
430 | 244 | uint32_t pPre = trans.pre[0].place; | 247 | uint32_t pPre = trans.pre[0].place; |
436 | 245 | uint32_t pPost = trans.post[0].place; | 248 | |
432 | 246 | |||
433 | 247 | // A1. continue if source and destination are the same | ||
434 | 248 | if (pPre == pPost) continue; | ||
435 | 249 | |||
437 | 250 | // A2. Check that pPre goes only to t | 249 | // A2. Check that pPre goes only to t |
438 | 251 | if(parent->_places[pPre].consumers.size() != 1) continue; | 250 | if(parent->_places[pPre].consumers.size() != 1) continue; |
439 | 252 | 251 | ||
440 | @@ -255,10 +254,21 @@ | |||
441 | 255 | if(trans.pre[0].weight != 1 || trans.post[0].weight < 1) continue; | 254 | if(trans.pre[0].weight != 1 || trans.post[0].weight < 1) continue; |
442 | 256 | 255 | ||
443 | 257 | // A4. Do inhibitor check, neither T, pPre or pPost can be involved with any inhibitor | 256 | // A4. Do inhibitor check, neither T, pPre or pPost can be involved with any inhibitor |
446 | 258 | if(parent->_places[pPre].inhib || parent->_places[pPost].inhib || trans.inhib) continue; | 257 | if(parent->_places[pPre].inhib|| trans.inhib) continue; |
447 | 259 | 258 | ||
448 | 260 | // A5. dont mess with query! | 259 | // A5. dont mess with query! |
450 | 261 | if(placeInQuery[pPre] > 0 || placeInQuery[pPost]) continue; | 260 | if(placeInQuery[pPre] > 0) continue; |
451 | 261 | // check A1, A4 and A5 for post | ||
452 | 262 | bool ok = true; | ||
453 | 263 | for(auto& pPost : trans.post) | ||
454 | 264 | { | ||
455 | 265 | if(parent->_places[pPost.place].inhib || pPre == pPost.place || placeInQuery[pPost.place] > 0) | ||
456 | 266 | { | ||
457 | 267 | ok = false; | ||
458 | 268 | break; | ||
459 | 269 | } | ||
460 | 270 | } | ||
461 | 271 | if(!ok) continue; | ||
462 | 262 | 272 | ||
463 | 263 | continueReductions = true; | 273 | continueReductions = true; |
464 | 264 | _ruleA++; | 274 | _ruleA++; |
465 | @@ -280,40 +290,45 @@ | |||
466 | 280 | } | 290 | } |
467 | 281 | } | 291 | } |
468 | 282 | 292 | ||
473 | 283 | size_t weight = trans.post[0].weight; | 293 | for(auto& pPost : trans.post) |
474 | 284 | 294 | { | |
475 | 285 | // UA2. move the token for the initial marking, makes things simpler. | 295 | // UA2. move the token for the initial marking, makes things simpler. |
476 | 286 | parent->initialMarking[pPost] += (parent->initialMarking[pPre] * weight); | 296 | parent->initialMarking[pPost.place] += (parent->initialMarking[pPre] * pPost.weight); |
477 | 297 | } | ||
478 | 287 | parent->initialMarking[pPre] = 0; | 298 | parent->initialMarking[pPre] = 0; |
479 | 288 | 299 | ||
480 | 289 | // Remove transition t and the place that has no tokens in m0 | 300 | // Remove transition t and the place that has no tokens in m0 |
481 | 290 | // UA1. remove transition | 301 | // UA1. remove transition |
482 | 302 | auto toMove = trans.post; | ||
483 | 291 | skipTransition(t); | 303 | skipTransition(t); |
484 | 292 | assert(pPost != pPre); | ||
485 | 293 | 304 | ||
486 | 294 | // UA2. update arcs | 305 | // UA2. update arcs |
487 | 295 | for(auto& _t : parent->_places[pPre].producers) | 306 | for(auto& _t : parent->_places[pPre].producers) |
488 | 296 | { | 307 | { |
489 | 297 | assert(pPre != pPost); | ||
490 | 298 | assert(_t != t); | 308 | assert(_t != t); |
491 | 299 | // move output-arcs to post. | 309 | // move output-arcs to post. |
509 | 300 | Transition& trans = getTransition(_t); | 310 | Transition& src = getTransition(_t); |
510 | 301 | auto source = getOutArc(trans, pPre); | 311 | auto source = *getOutArc(src, pPre); |
511 | 302 | assert(source != trans.pre.end()); | 312 | for(auto& pPost : toMove) |
512 | 303 | auto dest = getOutArc(trans, pPost); | 313 | { |
513 | 304 | if(dest == trans.post.end()) | 314 | Arc a; |
514 | 305 | { | 315 | a.place = pPost.place; |
515 | 306 | source->place = pPost; | 316 | a.weight = source.weight * pPost.weight; |
516 | 307 | source->weight *= weight; | 317 | assert(a.weight > 0); |
517 | 308 | parent->_places[pPost].producers.push_back(_t); | 318 | a.inhib = false; |
518 | 309 | 319 | auto dest = std::lower_bound(src.post.begin(), src.post.end(), a); | |
519 | 310 | std::sort(trans.post.begin(), trans.post.end()); | 320 | if(dest == src.post.end() || dest->place != pPost.place) |
520 | 311 | std::sort( parent->_places[pPost].producers.begin(), | 321 | { |
521 | 312 | parent->_places[pPost].producers.end()); | 322 | dest = src.post.insert(dest, a); |
522 | 313 | } | 323 | auto& prod = parent->_places[pPost.place].producers; |
523 | 314 | else | 324 | auto lb = std::lower_bound(prod.begin(), prod.end(), _t); |
524 | 315 | { | 325 | prod.insert(lb, _t); |
525 | 316 | dest->weight += (source->weight * weight); | 326 | } |
526 | 327 | else | ||
527 | 328 | { | ||
528 | 329 | dest->weight += (source.weight * pPost.weight); | ||
529 | 330 | } | ||
530 | 331 | assert(dest->weight > 0); | ||
531 | 317 | } | 332 | } |
532 | 318 | } | 333 | } |
533 | 319 | // UA1. remove place | 334 | // UA1. remove place |
534 | @@ -714,7 +729,8 @@ | |||
535 | 714 | if(placeInQuery[p] > 0) continue; | 729 | if(placeInQuery[p] > 0) continue; |
536 | 715 | if(place.producers.size() > place.consumers.size()) continue; | 730 | if(place.producers.size() > place.consumers.size()) continue; |
537 | 716 | 731 | ||
539 | 717 | bool ok = true; | 732 | std::set<uint32_t> notenabled; |
540 | 733 | bool ok = true; | ||
541 | 718 | for(uint cons : place.consumers) | 734 | for(uint cons : place.consumers) |
542 | 719 | { | 735 | { |
543 | 720 | Transition& t = getTransition(cons); | 736 | Transition& t = getTransition(cons); |
544 | @@ -723,12 +739,21 @@ | |||
545 | 723 | ok = false; | 739 | ok = false; |
546 | 724 | break; | 740 | break; |
547 | 725 | } | 741 | } |
548 | 742 | else | ||
549 | 743 | { | ||
550 | 744 | notenabled.insert(cons); | ||
551 | 745 | } | ||
552 | 726 | } | 746 | } |
553 | 727 | 747 | ||
554 | 728 | if(!ok) continue; | 748 | if(!ok) continue; |
556 | 729 | 749 | ||
557 | 730 | for(uint prod : place.producers) | 750 | for(uint prod : place.producers) |
558 | 731 | { | 751 | { |
559 | 752 | if(notenabled.count(prod) == 0) | ||
560 | 753 | { | ||
561 | 754 | ok = false; | ||
562 | 755 | break; | ||
563 | 756 | } | ||
564 | 732 | // check that producing arcs originate from transition also | 757 | // check that producing arcs originate from transition also |
565 | 733 | // consuming. If so, we know it will never fire. | 758 | // consuming. If so, we know it will never fire. |
566 | 734 | Transition& t = getTransition(prod); | 759 | Transition& t = getTransition(prod); |
567 | @@ -741,24 +766,63 @@ | |||
568 | 741 | } | 766 | } |
569 | 742 | 767 | ||
570 | 743 | if(!ok) continue; | 768 | if(!ok) continue; |
571 | 769 | |||
572 | 770 | _ruleE++; | ||
573 | 771 | continueReductions = true; | ||
574 | 744 | 772 | ||
575 | 745 | parent->initialMarking[p] = 0; | 773 | parent->initialMarking[p] = 0; |
576 | 746 | 774 | ||
580 | 747 | auto torem = place.consumers; | 775 | bool skipplace = notenabled.size() == place.consumers.size(); |
581 | 748 | for(uint cons : torem) | 776 | for(uint cons : notenabled) |
579 | 749 | { | ||
582 | 750 | skipTransition(cons); | 777 | skipTransition(cons); |
583 | 778 | |||
584 | 779 | if(skipplace) | ||
585 | 780 | skipPlace(p); | ||
586 | 781 | |||
587 | 782 | } | ||
588 | 783 | assert(consistent()); | ||
589 | 784 | return continueReductions; | ||
590 | 785 | } | ||
591 | 786 | |||
592 | 787 | bool Reducer::ReducebyRuleF(uint32_t* placeInQuery) { | ||
593 | 788 | bool continueReductions = false; | ||
594 | 789 | const size_t numberofplaces = parent->numberOfPlaces(); | ||
595 | 790 | for(uint32_t p = 0; p < numberofplaces; ++p) | ||
596 | 791 | { | ||
597 | 792 | if(hasTimedout()) return false; | ||
598 | 793 | Place& place = parent->_places[p]; | ||
599 | 794 | if(place.skip) continue; | ||
600 | 795 | if(place.inhib) continue; | ||
601 | 796 | if(placeInQuery[p] > 0) continue; | ||
602 | 797 | if(place.consumers.size() > 0) continue; | ||
603 | 798 | |||
604 | 799 | ++_ruleF; | ||
605 | 800 | continueReductions = true; | ||
606 | 801 | skipPlace(p); | ||
607 | 802 | std::vector<uint32_t> torem; | ||
608 | 803 | for(auto& t : place.producers) | ||
609 | 804 | { | ||
610 | 805 | auto& trans = parent->_transitions[t]; | ||
611 | 806 | if(trans.post.size() != 0) | ||
612 | 807 | continue; | ||
613 | 808 | bool ok = true; | ||
614 | 809 | for(auto& a : trans.pre) | ||
615 | 810 | { | ||
616 | 811 | if(placeInQuery[a.place] > 0) | ||
617 | 812 | { | ||
618 | 813 | ok = false; | ||
619 | 814 | } | ||
620 | 815 | } | ||
621 | 816 | if(ok) torem.push_back(t); | ||
622 | 751 | } | 817 | } |
627 | 752 | 818 | ||
628 | 753 | skipPlace(p); | 819 | for(auto t : torem) |
629 | 754 | _ruleE++; | 820 | skipTransition(t); |
630 | 755 | continueReductions = true; | 821 | assert(consistent()); |
631 | 756 | } | 822 | } |
632 | 757 | assert(consistent()); | ||
633 | 758 | return continueReductions; | 823 | return continueReductions; |
634 | 759 | } | 824 | } |
635 | 760 | 825 | ||
636 | 761 | |||
637 | 762 | void Reducer::Reduce(QueryPlaceAnalysisContext& context, int enablereduction, bool reconstructTrace, int timeout) { | 826 | void Reducer::Reduce(QueryPlaceAnalysisContext& context, int enablereduction, bool reconstructTrace, int timeout) { |
638 | 763 | this->_timeout = timeout; | 827 | this->_timeout = timeout; |
639 | 764 | _timer = std::chrono::high_resolution_clock::now(); | 828 | _timer = std::chrono::high_resolution_clock::now(); |
640 | @@ -773,11 +837,12 @@ | |||
641 | 773 | changed |= ReducebyRuleA(context.getQueryPlaceCount()); | 837 | changed |= ReducebyRuleA(context.getQueryPlaceCount()); |
642 | 774 | changed |= ReducebyRuleB(context.getQueryPlaceCount()); | 838 | changed |= ReducebyRuleB(context.getQueryPlaceCount()); |
643 | 775 | changed |= ReducebyRuleE(context.getQueryPlaceCount()); | 839 | changed |= ReducebyRuleE(context.getQueryPlaceCount()); |
644 | 840 | changed |= ReducebyRuleF(context.getQueryPlaceCount()); | ||
645 | 776 | } while(changed && !hasTimedout()); | 841 | } while(changed && !hasTimedout()); |
646 | 777 | // RuleC and RuleD are expensive, so wait with those till nothing else changes | 842 | // RuleC and RuleD are expensive, so wait with those till nothing else changes |
647 | 778 | changed |= ReducebyRuleD(context.getQueryPlaceCount()); | 843 | changed |= ReducebyRuleD(context.getQueryPlaceCount()); |
648 | 779 | changed |= ReducebyRuleC(context.getQueryPlaceCount()); | 844 | changed |= ReducebyRuleC(context.getQueryPlaceCount()); |
650 | 780 | } while(changed); | 845 | } while(!hasTimedout() && changed); |
651 | 781 | 846 | ||
652 | 782 | } else if (enablereduction == 2) { // for k-boundedness checking only rules A and D are applicable | 847 | } else if (enablereduction == 2) { // for k-boundedness checking only rules A and D are applicable |
653 | 783 | while ( ( | 848 | while ( ( |
654 | 784 | 849 | ||
655 | === modified file 'PetriEngine/Reducer.h' | |||
656 | --- PetriEngine/Reducer.h 2017-12-13 14:17:08 +0000 | |||
657 | +++ PetriEngine/Reducer.h 2018-01-04 10:26:07 +0000 | |||
658 | @@ -114,7 +114,11 @@ | |||
659 | 114 | size_t RuleE() const { | 114 | size_t RuleE() const { |
660 | 115 | return _ruleE; | 115 | return _ruleE; |
661 | 116 | } | 116 | } |
663 | 117 | 117 | ||
664 | 118 | size_t RuleF() const { | ||
665 | 119 | return _ruleF; | ||
666 | 120 | } | ||
667 | 121 | |||
668 | 118 | void postFire(std::ostream&, const std::string& transition); | 122 | void postFire(std::ostream&, const std::string& transition); |
669 | 119 | void extraConsume(std::ostream&, const std::string& transition); | 123 | void extraConsume(std::ostream&, const std::string& transition); |
670 | 120 | void initFire(std::ostream&); | 124 | void initFire(std::ostream&); |
671 | @@ -122,7 +126,7 @@ | |||
672 | 122 | private: | 126 | private: |
673 | 123 | size_t _removedTransitions; | 127 | size_t _removedTransitions; |
674 | 124 | size_t _removedPlaces; | 128 | size_t _removedPlaces; |
676 | 125 | size_t _ruleA, _ruleB, _ruleC, _ruleD, _ruleE; | 129 | size_t _ruleA, _ruleB, _ruleC, _ruleD, _ruleE, _ruleF; |
677 | 126 | PetriNetBuilder* parent; | 130 | PetriNetBuilder* parent; |
678 | 127 | bool reconstructTrace = false; | 131 | bool reconstructTrace = false; |
679 | 128 | std::chrono::high_resolution_clock::time_point _timer; | 132 | std::chrono::high_resolution_clock::time_point _timer; |
680 | @@ -134,6 +138,7 @@ | |||
681 | 134 | bool ReducebyRuleC(uint32_t* placeInQuery); | 138 | bool ReducebyRuleC(uint32_t* placeInQuery); |
682 | 135 | bool ReducebyRuleD(uint32_t* placeInQuery); | 139 | bool ReducebyRuleD(uint32_t* placeInQuery); |
683 | 136 | bool ReducebyRuleE(uint32_t* placeInQuery); | 140 | bool ReducebyRuleE(uint32_t* placeInQuery); |
684 | 141 | bool ReducebyRuleF(uint32_t* placeInQuery); | ||
685 | 137 | 142 | ||
686 | 138 | std::string getTransitionName(uint32_t transition); | 143 | std::string getTransitionName(uint32_t transition); |
687 | 139 | std::string getPlaceName(uint32_t place); | 144 | std::string getPlaceName(uint32_t place); |
688 | 140 | 145 | ||
689 | === modified file 'PetriEngine/ReducingSuccessorGenerator.cpp' | |||
690 | --- PetriEngine/ReducingSuccessorGenerator.cpp 2017-12-05 15:13:40 +0000 | |||
691 | +++ PetriEngine/ReducingSuccessorGenerator.cpp 2018-01-04 10:26:07 +0000 | |||
692 | @@ -18,7 +18,9 @@ | |||
693 | 18 | } | 18 | } |
694 | 19 | 19 | ||
695 | 20 | ReducingSuccessorGenerator::ReducingSuccessorGenerator(const PetriNet& net, std::vector<std::shared_ptr<PQL::Condition> >& queries) : ReducingSuccessorGenerator(net) { | 20 | ReducingSuccessorGenerator::ReducingSuccessorGenerator(const PetriNet& net, std::vector<std::shared_ptr<PQL::Condition> >& queries) : ReducingSuccessorGenerator(net) { |
697 | 21 | _queries = queries; | 21 | _queries.reserve(queries.size()); |
698 | 22 | for(auto& q : queries) | ||
699 | 23 | _queries.push_back(q.get()); | ||
700 | 22 | } | 24 | } |
701 | 23 | 25 | ||
702 | 24 | ReducingSuccessorGenerator::~ReducingSuccessorGenerator() { | 26 | ReducingSuccessorGenerator::~ReducingSuccessorGenerator() { |
703 | @@ -182,6 +184,12 @@ | |||
704 | 182 | void ReducingSuccessorGenerator::prepare(const Structures::State* state) { | 184 | void ReducingSuccessorGenerator::prepare(const Structures::State* state) { |
705 | 183 | _parent = state; | 185 | _parent = state; |
706 | 184 | constructEnabled(); | 186 | constructEnabled(); |
707 | 187 | if(_ordering.size() == 0) return; | ||
708 | 188 | if(_ordering.size() == 1) | ||
709 | 189 | { | ||
710 | 190 | _stubborn[_ordering.front()] = true; | ||
711 | 191 | return; | ||
712 | 192 | } | ||
713 | 185 | for (auto &q : _queries) { | 193 | for (auto &q : _queries) { |
714 | 186 | q->evalAndSet(PQL::EvaluationContext((*_parent).marking(), &_net)); | 194 | q->evalAndSet(PQL::EvaluationContext((*_parent).marking(), &_net)); |
715 | 187 | q->findInteresting(*this, false); | 195 | q->findInteresting(*this, false); |
716 | 188 | 196 | ||
717 | === modified file 'PetriEngine/ReducingSuccessorGenerator.h' | |||
718 | --- PetriEngine/ReducingSuccessorGenerator.h 2017-05-10 11:10:00 +0000 | |||
719 | +++ PetriEngine/ReducingSuccessorGenerator.h 2018-01-04 10:26:07 +0000 | |||
720 | @@ -29,6 +29,9 @@ | |||
721 | 29 | { | 29 | { |
722 | 30 | return _current; | 30 | return _current; |
723 | 31 | } | 31 | } |
724 | 32 | void setQuery(PQL::Condition* ptr) { _queries.clear(); _queries = {ptr};} | ||
725 | 33 | void reset(); | ||
726 | 34 | |||
727 | 32 | private: | 35 | private: |
728 | 33 | bool *_enabled, *_stubborn; | 36 | bool *_enabled, *_stubborn; |
729 | 34 | std::unique_ptr<place_t[]> _places; | 37 | std::unique_ptr<place_t[]> _places; |
730 | @@ -39,8 +42,7 @@ | |||
731 | 39 | bool _netContainsInhibitorArcs; | 42 | bool _netContainsInhibitorArcs; |
732 | 40 | std::vector<std::vector<uint32_t>> _inhibpost; | 43 | std::vector<std::vector<uint32_t>> _inhibpost; |
733 | 41 | 44 | ||
736 | 42 | std::vector<std::shared_ptr<PQL::Condition> > _queries; | 45 | std::vector<PQL::Condition* > _queries; |
735 | 43 | void reset(); | ||
737 | 44 | void constructEnabled(); | 46 | void constructEnabled(); |
738 | 45 | void constructPrePost(); | 47 | void constructPrePost(); |
739 | 46 | void constructDependency(); | 48 | void constructDependency(); |
740 | 47 | 49 | ||
741 | === modified file 'PetriEngine/Structures/light_deque.h' | |||
742 | --- PetriEngine/Structures/light_deque.h 2017-03-05 16:08:26 +0000 | |||
743 | +++ PetriEngine/Structures/light_deque.h 2018-01-04 10:26:07 +0000 | |||
744 | @@ -48,6 +48,11 @@ | |||
745 | 48 | return _front == _back; | 48 | return _front == _back; |
746 | 49 | } | 49 | } |
747 | 50 | 50 | ||
748 | 51 | size_t size() | ||
749 | 52 | { | ||
750 | 53 | return _back - _front; | ||
751 | 54 | } | ||
752 | 55 | |||
753 | 51 | T front() | 56 | T front() |
754 | 52 | { | 57 | { |
755 | 53 | return _data.get()[_front]; | 58 | return _data.get()[_front]; |
756 | 54 | 59 | ||
757 | === modified file 'PetriEngine/SuccessorGenerator.h' | |||
758 | --- PetriEngine/SuccessorGenerator.h 2017-12-05 02:09:55 +0000 | |||
759 | +++ PetriEngine/SuccessorGenerator.h 2018-01-04 10:26:07 +0000 | |||
760 | @@ -35,6 +35,8 @@ | |||
761 | 35 | return _parent->marking(); | 35 | return _parent->marking(); |
762 | 36 | } | 36 | } |
763 | 37 | 37 | ||
764 | 38 | void reset(); | ||
765 | 39 | |||
766 | 38 | protected: | 40 | protected: |
767 | 39 | /** | 41 | /** |
768 | 40 | * Checks if the conditions are met for fireing t, if write != NULL, | 42 | * Checks if the conditions are met for fireing t, if write != NULL, |
769 | @@ -63,7 +65,6 @@ | |||
770 | 63 | const Structures::State* _parent; | 65 | const Structures::State* _parent; |
771 | 64 | uint32_t _suc_pcounter; | 66 | uint32_t _suc_pcounter; |
772 | 65 | uint32_t _suc_tcounter; | 67 | uint32_t _suc_tcounter; |
773 | 66 | void reset(); | ||
774 | 67 | 68 | ||
775 | 68 | friend class ReducingSuccessorGenerator; | 69 | friend class ReducingSuccessorGenerator; |
776 | 69 | }; | 70 | }; |
777 | 70 | 71 | ||
778 | === modified file 'VerifyPN.cpp' | |||
779 | --- VerifyPN.cpp 2017-12-12 10:13:45 +0000 | |||
780 | +++ VerifyPN.cpp 2018-01-04 10:26:07 +0000 | |||
781 | @@ -478,7 +478,8 @@ | |||
782 | 478 | << "Applications of rule B: " << builder.RuleB() << std::endl | 478 | << "Applications of rule B: " << builder.RuleB() << std::endl |
783 | 479 | << "Applications of rule C: " << builder.RuleC() << std::endl | 479 | << "Applications of rule C: " << builder.RuleC() << std::endl |
784 | 480 | << "Applications of rule D: " << builder.RuleD() << std::endl | 480 | << "Applications of rule D: " << builder.RuleD() << std::endl |
786 | 481 | << "Applications of rule E: " << builder.RuleE() << std::endl; | 481 | << "Applications of rule E: " << builder.RuleE() << std::endl |
787 | 482 | << "Applications of rule F: " << builder.RuleF() << std::endl; | ||
788 | 482 | } | 483 | } |
789 | 483 | } | 484 | } |
790 | 484 | } | 485 | } |
791 | @@ -656,7 +657,26 @@ | |||
792 | 656 | 657 | ||
793 | 657 | if(alldone) return SuccessCode; | 658 | if(alldone) return SuccessCode; |
794 | 658 | } | 659 | } |
796 | 659 | 660 | ||
797 | 661 | //--------------------- Apply Net Reduction ---------------// | ||
798 | 662 | |||
799 | 663 | if ( (options.enablereduction == 1 || options.enablereduction == 2) | ||
800 | 664 | && std::all_of(queries.begin(), queries.end(), [](auto& a){ return !a->containsNext(); })) { | ||
801 | 665 | // Compute how many times each place appears in the query | ||
802 | 666 | builder.startTimer(); | ||
803 | 667 | builder.reduce(queries, results, options.enablereduction, options.trace, nullptr, options.reductionTimeout); | ||
804 | 668 | printer.setReducer(builder.getReducer()); | ||
805 | 669 | } | ||
806 | 670 | |||
807 | 671 | printStats(builder, options); | ||
808 | 672 | |||
809 | 673 | auto net = std::unique_ptr<PetriNet>(builder.makePetriNet()); | ||
810 | 674 | |||
811 | 675 | for(auto& q : queries) | ||
812 | 676 | { | ||
813 | 677 | q->indexPlaces(builder.getPlaceNames()); | ||
814 | 678 | } | ||
815 | 679 | |||
816 | 660 | //----------------------- Verify CTL queries -----------------------// | 680 | //----------------------- Verify CTL queries -----------------------// |
817 | 661 | std::vector<size_t> ctl_ids; | 681 | std::vector<size_t> ctl_ids; |
818 | 662 | for(size_t i = 0; i < queries.size(); ++i) | 682 | for(size_t i = 0; i < queries.size(); ++i) |
819 | @@ -670,24 +690,25 @@ | |||
820 | 670 | if (ctl_ids.size() > 0) { | 690 | if (ctl_ids.size() > 0) { |
821 | 671 | options.isctl=true; | 691 | options.isctl=true; |
822 | 672 | PetriEngine::Reachability::Strategy reachabilityStrategy=options.strategy; | 692 | PetriEngine::Reachability::Strategy reachabilityStrategy=options.strategy; |
824 | 673 | std::unique_ptr<PetriNet> ctlnet(builder.makePetriNet()); | 693 | |
825 | 674 | // Assign indexes | 694 | // Assign indexes |
827 | 675 | if(queries.size() == 0 || contextAnalysis(builder, ctlnet.get(), queries) != ContinueCode) return ErrorCode; | 695 | if(queries.size() == 0 || contextAnalysis(builder, net.get(), queries) != ContinueCode) return ErrorCode; |
828 | 676 | if(options.strategy == DEFAULT) options.strategy = PetriEngine::Reachability::DFS; | 696 | if(options.strategy == DEFAULT) options.strategy = PetriEngine::Reachability::DFS; |
829 | 677 | if(options.strategy != PetriEngine::Reachability::DFS){ | 697 | if(options.strategy != PetriEngine::Reachability::DFS){ |
830 | 678 | fprintf(stdout, "Search strategy was changed to DFS as the CTL engine is called.\n"); | 698 | fprintf(stdout, "Search strategy was changed to DFS as the CTL engine is called.\n"); |
831 | 679 | options.strategy = PetriEngine::Reachability::DFS; | 699 | options.strategy = PetriEngine::Reachability::DFS; |
832 | 680 | } | 700 | } |
834 | 681 | v = CTLMain(ctlnet.get(), | 701 | v = CTLMain(net.get(), |
835 | 682 | options.ctlalgorithm, | 702 | options.ctlalgorithm, |
836 | 683 | options.strategy, | 703 | options.strategy, |
837 | 684 | options.gamemode, | 704 | options.gamemode, |
838 | 685 | options.printstatistics, | 705 | options.printstatistics, |
839 | 686 | true, | 706 | true, |
840 | 707 | options.stubbornreduction, | ||
841 | 687 | querynames, | 708 | querynames, |
842 | 688 | queries, | 709 | queries, |
843 | 689 | ctl_ids); | 710 | ctl_ids); |
845 | 690 | 711 | ||
846 | 691 | if (std::find(results.begin(), results.end(), ResultPrinter::Unknown) == results.end()) { | 712 | if (std::find(results.begin(), results.end(), ResultPrinter::Unknown) == results.end()) { |
847 | 692 | return v; | 713 | return v; |
848 | 693 | } | 714 | } |
849 | @@ -695,24 +716,6 @@ | |||
850 | 695 | options.strategy=reachabilityStrategy; | 716 | options.strategy=reachabilityStrategy; |
851 | 696 | } | 717 | } |
852 | 697 | options.isctl=false; | 718 | options.isctl=false; |
853 | 698 | //--------------------- Apply Net Reduction ---------------// | ||
854 | 699 | |||
855 | 700 | if (options.enablereduction == 1 || options.enablereduction == 2) { | ||
856 | 701 | // Compute how many times each place appears in the query | ||
857 | 702 | builder.startTimer(); | ||
858 | 703 | std::unique_ptr<PetriNet> net(builder.makePetriNet(false)); | ||
859 | 704 | builder.reduce(queries, results, options.enablereduction, options.trace, net.get(), options.reductionTimeout); | ||
860 | 705 | printer.setReducer(builder.getReducer()); | ||
861 | 706 | } | ||
862 | 707 | |||
863 | 708 | printStats(builder, options); | ||
864 | 709 | |||
865 | 710 | std::unique_ptr<PetriNet> net(builder.makePetriNet()); | ||
866 | 711 | |||
867 | 712 | for(auto& q : queries) | ||
868 | 713 | { | ||
869 | 714 | q->indexPlaces(builder.getPlaceNames()); | ||
870 | 715 | } | ||
871 | 716 | 719 | ||
872 | 717 | //----------------------- Siphon Trap ------------------------// | 720 | //----------------------- Siphon Trap ------------------------// |
873 | 718 | 721 |
The switch that disables partial order reduction should be active also
for CTL verification for EF and AG leafs.