Merge lp:~tapaal-ltl/verifypn/traceable-tarjan into lp:~tapaal-ltl/verifypn/ltl-model-checker

Proposed by Nikolaj Jensen Ulrik
Status: Merged
Merged at revision: 257
Proposed branch: lp:~tapaal-ltl/verifypn/traceable-tarjan
Merge into: lp:~tapaal-ltl/verifypn/ltl-model-checker
Diff against target: 735 lines (+265/-124) (has conflicts)
12 files modified
include/LTL/Algorithm/ModelChecker.h (+15/-2)
include/LTL/Algorithm/NestedDepthFirstSearch.h (+4/-5)
include/LTL/Algorithm/TarjanModelChecker.h (+43/-10)
include/LTL/AlgorithmTypes.h (+41/-0)
include/LTL/LTL.h (+1/-17)
include/PetriEngine/options.h (+9/-3)
src/CMakeLists.txt (+1/-1)
src/LTL/Algorithm/ModelChecker.cpp (+44/-6)
src/LTL/Algorithm/NestedDepthFirstSearch.cpp (+30/-30)
src/LTL/Algorithm/TarjanModelChecker.cpp (+53/-41)
src/PetriEngine/Reachability/ResultPrinter.cpp (+1/-1)
src/VerifyPN.cpp (+23/-8)
Text conflict in include/LTL/Algorithm/TarjanModelChecker.h
Text conflict in src/LTL/Algorithm/NestedDepthFirstSearch.cpp
To merge this branch: bzr merge lp:~tapaal-ltl/verifypn/traceable-tarjan
Reviewer Review Type Date Requested Status
Simon Virenfeldt Approve
Review via email: mp+398592@code.launchpad.net

Description of the change

Trace printing in Tarjan's algorithm

To post a comment you must log in.
Revision history for this message
Simon Virenfeldt (simwir) wrote :

Kun en lille addition til docstring.

review: Approve
256. By Nikolaj Jensen Ulrik

Hotfix and docstring

257. By Nikolaj Jensen Ulrik

TAPAAL compatible trace format, correct NDFS traces

258. By Nikolaj Jensen Ulrik

Add trace levels for internal usage

259. By Simon Virenfeldt

Added some additional newlines

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/LTL/Algorithm/ModelChecker.h'
2--- include/LTL/Algorithm/ModelChecker.h 2021-02-01 11:17:38 +0000
3+++ include/LTL/Algorithm/ModelChecker.h 2021-03-04 10:04:52 +0000
4@@ -21,24 +21,37 @@
5 #include "PetriEngine/PQL/PQL.h"
6 #include "LTL/ProductSuccessorGenerator.h"
7 #include "LTL/Algorithm/ProductPrinter.h"
8+#include "PetriEngine/options.h"
9
10 namespace LTL {
11+
12 class ModelChecker {
13 public:
14- ModelChecker(const PetriEngine::PetriNet& net, PetriEngine::PQL::Condition_ptr, const bool shortcircuitweak);
15+ ModelChecker(const PetriEngine::PetriNet &net, PetriEngine::PQL::Condition_ptr, const bool shortcircuitweak,
16+ TraceLevel level = TraceLevel::Transitions);
17+
18 virtual bool isSatisfied() = 0;
19-
20+
21 virtual ~ModelChecker() = default;
22+
23 [[nodiscard]] bool isweak() const { return is_weak; }
24+
25+
26 protected:
27 std::unique_ptr<ProductSuccessorGenerator> successorGenerator;
28 const PetriEngine::PetriNet &net;
29 PetriEngine::PQL::Condition_ptr formula;
30+ TraceLevel traceLevel;
31
32 size_t _discovered = 0;
33 const bool shortcircuitweak;
34 bool weakskip = false;
35 bool is_weak = false;
36+ int maxTransName;
37+
38+ std::ostream &printTransition(size_t transition, LTL::Structures::ProductState &state, std::ostream &os);
39+
40+ void printLoop(std::ostream &os);
41 };
42 }
43
44
45=== modified file 'include/LTL/Algorithm/NestedDepthFirstSearch.h'
46--- include/LTL/Algorithm/NestedDepthFirstSearch.h 2021-03-02 12:06:17 +0000
47+++ include/LTL/Algorithm/NestedDepthFirstSearch.h 2021-03-04 10:04:52 +0000
48@@ -50,8 +50,8 @@
49 template <typename W>
50 class NestedDepthFirstSearch : public ModelChecker {
51 public:
52- NestedDepthFirstSearch(const PetriNet &net, PetriEngine::PQL::Condition_ptr ptr, const bool shortcircuitweak)
53- : ModelChecker(net, ptr, shortcircuitweak), factory{net, successorGenerator->initial_buchi_state()},
54+ NestedDepthFirstSearch(const PetriNet &net, PetriEngine::PQL::Condition_ptr ptr, const bool shortcircuitweak, TraceLevel level = TraceLevel::Full)
55+ : ModelChecker(net, ptr, shortcircuitweak, level), factory{net, successorGenerator->initial_buchi_state()},
56 states(net, 0, (int)net.numberOfPlaces() + 1) {}
57
58 bool isSatisfied() override;
59@@ -73,14 +73,13 @@
60 bool violation = false;
61
62 //Used for printing the trace
63- std::stack<size_t> nested_transitions;
64+ std::stack<std::pair<size_t, size_t>> nested_transitions;
65
66 void dfs();
67
68 void ndfs(State &state);
69- void printTrace(stack<size_t> &transitions);
70+ void printTrace(std::stack<std::pair<size_t, size_t>> &transitions, std::ostream &os = std::cout);
71
72- ostream & printTransition(size_t transition, uint indent, ostream &os = std::cerr);
73 static constexpr bool SaveTrace = std::is_same_v<W, PetriEngine::Structures::TracableStateSet>;
74 };
75 extern template class NestedDepthFirstSearch<PetriEngine::Structures::StateSet>;
76
77=== modified file 'include/LTL/Algorithm/TarjanModelChecker.h'
78--- include/LTL/Algorithm/TarjanModelChecker.h 2021-03-02 12:06:17 +0000
79+++ include/LTL/Algorithm/TarjanModelChecker.h 2021-03-04 10:04:52 +0000
80@@ -28,6 +28,7 @@
81
82 namespace LTL {
83
84+<<<<<<< TREE
85 /**
86 * Implements on-the-fly version of Tarjan's algorithm suitable for LTL model checking.
87 * The idea is to detect some reachable strongly connected component containing an accepting state,
88@@ -40,11 +41,27 @@
89 * </p>
90 */
91 template <bool SaveTrace>
92+=======
93+ /**
94+ * Implements on-the-fly version of Tarjan's algorithm suitable for LTL model checking.
95+ * The idea is to detect some reachable strongly connected component containing an accepting state,
96+ * which constitutes a counter-example.
97+ * For more details see
98+ * Jaco Geldenhuys & Antti Valmari,
99+ * More efficient on-the-fly LTL verification with Tarjan's algorithm,
100+ * https://doi.org/10.1016/j.tcs.2005.07.004
101+ *
102+ * @tparam SaveTrace whether to save and print counter-examples when possible.
103+ */
104+ template<bool SaveTrace>
105+>>>>>>> MERGE-SOURCE
106 class TarjanModelChecker : public ModelChecker {
107 public:
108- TarjanModelChecker(const PetriEngine::PetriNet &net, const Condition_ptr &cond, const bool shortcircuitweak)
109- : ModelChecker(net, cond, shortcircuitweak), factory(net, successorGenerator->initial_buchi_state()),
110- seen(net, 0, (int) net.numberOfPlaces() + 1) {
111+ TarjanModelChecker(const PetriEngine::PetriNet &net, const Condition_ptr &cond, const bool shortcircuitweak,
112+ TraceLevel level = TraceLevel::Full)
113+ : ModelChecker(net, cond, shortcircuitweak, level), factory(net, successorGenerator->initial_buchi_state()),
114+ seen(net, 0, (int) net.numberOfPlaces() + 1)
115+ {
116 chash.fill(std::numeric_limits<idx_t>::max());
117 }
118
119@@ -58,7 +75,9 @@
120
121 LTL::Structures::ProductStateFactory factory;
122
123- PetriEngine::Structures::StateSet seen;
124+ using StateSet = std::conditional_t<SaveTrace, PetriEngine::Structures::TracableStateSet, PetriEngine::Structures::StateSet>;
125+
126+ StateSet seen;
127 std::unordered_set<idx_t> store;
128
129 // rudimentary hash table of state IDs. chash[hash(state)] is the top index in cstack
130@@ -66,7 +85,8 @@
131 std::array<idx_t, HashSz> chash;
132 static_assert(sizeof(chash) == (1U << 27U));
133
134- static inline idx_t hash(idx_t id) {
135+ static inline idx_t hash(idx_t id)
136+ {
137 return id % HashSz;
138 }
139
140@@ -86,21 +106,27 @@
141 };
142
143 using CEntry = std::conditional_t<SaveTrace,
144- TracableCEntry,
145- PlainCEntry>;
146+ TracableCEntry,
147+ PlainCEntry>;
148+
149
150 struct DEntry {
151 idx_t pos; // position in cstack.
152 successor_info sucinfo;
153 };
154
155+<<<<<<< TREE
156 // master list of state information.
157+=======
158+>>>>>>> MERGE-SOURCE
159 std::vector<CEntry> cstack;
160 // depth-first search stack, contains current search path.
161 std::stack<DEntry> dstack;
162 // cstack positions of accepting states in current search path, for quick access.
163 std::stack<idx_t> astack;
164 bool violation = false;
165+ size_t loopstate = std::numeric_limits<size_t>::max();
166+ size_t looptrans = std::numeric_limits<size_t>::max();
167
168 void push(State &state);
169
170@@ -108,12 +134,19 @@
171
172 void update(idx_t to);
173
174- bool nexttrans(State &state, State& parent, DEntry &delem);
175+ bool nexttrans(State &state, State &parent, DEntry &delem);
176
177 void popCStack();
178+
179+ void printTrace(std::stack<DEntry> &&dstack, std::ostream &os = std::cout);
180+
181 };
182-extern template class TarjanModelChecker<true>;
183-extern template class TarjanModelChecker<false>;
184+
185+ extern template
186+ class TarjanModelChecker<true>;
187+
188+ extern template
189+ class TarjanModelChecker<false>;
190 }
191
192 #endif //VERIFYPN_TARJANMODELCHECKER_H
193
194=== added file 'include/LTL/AlgorithmTypes.h'
195--- include/LTL/AlgorithmTypes.h 1970-01-01 00:00:00 +0000
196+++ include/LTL/AlgorithmTypes.h 2021-03-04 10:04:52 +0000
197@@ -0,0 +1,41 @@
198+/* Copyright (C) 2021 Nikolaj J. Ulrik <nikolaj@njulrik.dk>,
199+ * Simon M. Virenfeldt <simon@simwir.dk>
200+ *
201+ * This program is free software: you can redistribute it and/or modify
202+ * it under the terms of the GNU General Public License as published by
203+ * the Free Software Foundation, either version 3 of the License, or
204+ * (at your option) any later version.
205+ *
206+ * This program is distributed in the hope that it will be useful,
207+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
208+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
209+ * GNU General Public License for more details.
210+ *
211+ * You should have received a copy of the GNU General Public License
212+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
213+ */
214+
215+#ifndef VERIFYPN_ALGORITHMTYPES_H
216+#define VERIFYPN_ALGORITHMTYPES_H
217+
218+namespace LTL {
219+ enum class Algorithm {
220+ NDFS, RandomNDFS, Tarjan, None=-1
221+ };
222+ inline auto to_string(Algorithm alg) {
223+ switch (alg) {
224+ case Algorithm::NDFS:
225+ return "NDFS";
226+ case Algorithm::RandomNDFS:
227+ return "RNDFS";
228+ case Algorithm::Tarjan:
229+ return "TARJAN";
230+ case Algorithm::None:
231+ default:
232+ std::cerr << "to_string: Invalid LTL Algorithm " << static_cast<int>(alg) << '\n';
233+ assert(false);
234+ }
235+ }
236+}
237+
238+#endif //VERIFYPN_ALGORITHMTYPES_H
239
240=== modified file 'include/LTL/LTL.h'
241--- include/LTL/LTL.h 2021-02-01 11:17:38 +0000
242+++ include/LTL/LTL.h 2021-03-04 10:04:52 +0000
243@@ -26,23 +26,7 @@
244 #include "LTL/LTLToBuchi.h"
245
246 namespace LTL {
247- enum class Algorithm {
248- NDFS, RandomNDFS, Tarjan, None=-1
249- };
250- inline auto to_string(Algorithm alg) {
251- switch (alg) {
252- case Algorithm::NDFS:
253- return "NDFS";
254- case Algorithm::RandomNDFS:
255- return "RNDFS";
256- case Algorithm::Tarjan:
257- return "TARJAN";
258- case Algorithm::None:
259- default:
260- std::cerr << "to_string: Invalid LTL Algorithm " << static_cast<int>(alg) << '\n';
261- assert(false);
262- }
263- }
264+
265
266 std::pair<Condition_ptr, bool> to_ltl(const Condition_ptr &formula);
267 }
268
269=== modified file 'include/PetriEngine/options.h'
270--- include/PetriEngine/options.h 2021-01-08 09:12:40 +0000
271+++ include/PetriEngine/options.h 2021-03-04 10:04:52 +0000
272@@ -9,13 +9,19 @@
273
274 #include "Reachability/ReachabilitySearch.h"
275 #include "../CTL/Algorithm/AlgorithmTypes.h"
276-#include "../LTL/LTL.h"
277+#include "../LTL/AlgorithmTypes.h"
278
279
280 enum class TemporalLogic {
281 CTL, LTL
282 };
283
284+enum class TraceLevel {
285+ None,
286+ Transitions,
287+ Full
288+};
289+
290 struct options_t {
291 // bool outputtrace = false;
292 int kbound = 0;
293@@ -29,7 +35,7 @@
294 bool printstatistics = true;
295 std::set<size_t> querynumbers;
296 PetriEngine::Reachability::Strategy strategy = PetriEngine::Reachability::DEFAULT;
297- bool trace = false;
298+ TraceLevel trace = TraceLevel::None;
299 bool use_query_reductions = true;
300 int queryReductionTimeout = 30, lpsolveTimeout = 10;
301 uint32_t siphontrapTimeout = 0;
302@@ -78,7 +84,7 @@
303 optionsOut = "\nSearch=OverApprox";
304 }
305
306- if (trace) {
307+ if (trace != TraceLevel::None) {
308 optionsOut += ",Trace=ENABLED";
309 } else {
310 optionsOut += ",Trace=DISABLED";
311
312=== modified file 'src/CMakeLists.txt'
313--- src/CMakeLists.txt 2021-02-01 11:17:38 +0000
314+++ src/CMakeLists.txt 2021-03-04 10:04:52 +0000
315@@ -5,7 +5,7 @@
316 add_subdirectory(PetriParse)
317 add_subdirectory(PetriEngine)
318
319-add_executable(verifypn-${ARCH_TYPE} VerifyPN.cpp)
320+add_executable(verifypn-${ARCH_TYPE} VerifyPN.cpp ../include/LTL/AlgorithmTypes.h)
321 add_dependencies(verifypn-${ARCH_TYPE} glpk-ext spot-ext)
322
323 target_link_libraries(verifypn-${ARCH_TYPE} PRIVATE CTL LTL PetriEngine PetriParse glpk spot)
324
325=== modified file 'src/LTL/Algorithm/LTLToBuchi.cpp'
326=== modified file 'src/LTL/Algorithm/ModelChecker.cpp'
327--- src/LTL/Algorithm/ModelChecker.cpp 2021-02-01 11:17:38 +0000
328+++ src/LTL/Algorithm/ModelChecker.cpp 2021-03-04 10:04:52 +0000
329@@ -18,16 +18,54 @@
330 #include "LTL/Algorithm/ModelChecker.h"
331
332 #include <utility>
333+#include <iomanip>
334
335 namespace LTL {
336- ModelChecker::ModelChecker(const PetriEngine::PetriNet& net, PetriEngine::PQL::Condition_ptr condition, const bool shortcircuitweak)
337- : net(net), formula(condition), shortcircuitweak(shortcircuitweak)
338+ ModelChecker::ModelChecker(const PetriEngine::PetriNet &net, PetriEngine::PQL::Condition_ptr condition,
339+ const bool shortcircuitweak, TraceLevel level)
340+ : net(net), formula(condition), traceLevel(level), shortcircuitweak(shortcircuitweak)
341 {
342
343 successorGenerator = std::make_unique<ProductSuccessorGenerator>(net, condition);
344- //TODO Create successor generator from net and condition
345-
346- //LTL::ProductPrinter::printProduct(*successorGenerator, std::cout, net, condition);
347- }
348+
349+ maxTransName = std::max_element(std::begin(net.transitionNames()), std::end(net.transitionNames()),
350+ [](auto &a, auto &b) { return a.size() < b.size(); })->size();
351+
352+ }
353+
354+ static constexpr auto indent = " ";
355+ static constexpr auto tokenIndent = " ";
356+
357+ void ModelChecker::printLoop(std::ostream &os)
358+ {
359+ os << indent << "<loop/>\n";
360+ }
361+
362+ std::ostream &
363+ ModelChecker::printTransition(size_t transition, LTL::Structures::ProductState &state, std::ostream &os)
364+ {
365+ if (transition >= std::numeric_limits<ptrie::uint>::max() - 1) {
366+ os << indent << "<deadlock/>";
367+ return os;
368+ }
369+ std::string tname = net.transitionNames()[transition];
370+ if (traceLevel == TraceLevel::Full) {
371+ os << indent << "<transition id=\"" << tname << "\">\n";
372+ for (size_t i = 0; i < net.numberOfPlaces(); ++i) {
373+ for (size_t j = 0; j < state.marking()[i]; ++j) {
374+ os << tokenIndent << R"(<token age="0" place=")" << net.placeNames()[i] << "\"/>\n";
375+ }
376+ }
377+#ifndef NDEBUG
378+ os << '\n' << tokenIndent << "<buchi state=\"" << state.getBuchiState() << "\"/>\n";
379+#endif
380+ os << indent << "</transition>";
381+ } else {
382+ os << indent << "<transition id=" << std::setw(maxTransName + 1) << std::quoted(tname) << "\tbuchisucc=\""
383+ << state.getBuchiState() << "\"/>";
384+ }
385+ return os;
386+ }
387+
388 }
389
390
391=== modified file 'src/LTL/Algorithm/NestedDepthFirstSearch.cpp'
392--- src/LTL/Algorithm/NestedDepthFirstSearch.cpp 2021-03-02 12:06:17 +0000
393+++ src/LTL/Algorithm/NestedDepthFirstSearch.cpp 2021-03-04 10:04:52 +0000
394@@ -19,14 +19,16 @@
395
396 namespace LTL {
397 template<typename W>
398- bool NestedDepthFirstSearch<W>::isSatisfied() {
399+ bool NestedDepthFirstSearch<W>::isSatisfied()
400+ {
401 is_weak = successorGenerator->is_weak() && shortcircuitweak;
402 dfs();
403 return !violation;
404 }
405
406 template<typename W>
407- void NestedDepthFirstSearch<W>::dfs() {
408+ void NestedDepthFirstSearch<W>::dfs()
409+ {
410 std::stack<size_t> call_stack;
411 std::stack<StackEntry> todo;
412
413@@ -59,13 +61,13 @@
414 ndfs(curState);
415 if (violation) {
416 if constexpr (SaveTrace) {
417- std::stack<size_t> transitions;
418+ std::stack<std::pair<size_t, size_t>> transitions;
419 size_t next = top.id;
420 states.decode(working, next);
421 while (!successorGenerator->isInitialState(working)) {
422 auto[parent, transition] = states.getHistory(next);
423+ transitions.push(std::make_pair(next, transition));
424 next = parent;
425- transitions.push(transition);
426 states.decode(working, next);
427 }
428 printTrace(transitions);
429@@ -90,7 +92,8 @@
430 }
431
432 template<typename W>
433- void NestedDepthFirstSearch<W>::ndfs(State &state) {
434+ void NestedDepthFirstSearch<W>::ndfs(State &state)
435+ {
436 std::stack<StackEntry> todo;
437
438 State working = factory.newState();
439@@ -115,22 +118,22 @@
440 violation = true;
441 if constexpr (SaveTrace) {
442 auto[_, stateid] = states.add(working);
443+ auto seedId = stateid;
444 states.setHistory2(stateid, successorGenerator->fired());
445 size_t next = stateid;
446+<<<<<<< TREE
447 ptrie::uint trans = 0;
448 // SuccessorGenerator returns tcount - 1, but resets tcount to UINT_MAX when done,
449 // hence loop until transition >= UINT_MAX - 1.
450 while (trans < std::numeric_limits<ptrie::uint>::max() - 1) {
451+=======
452+ // follow trace until back at seed state.
453+ do {
454+>>>>>>> MERGE-SOURCE
455 auto[state, transition] = states.getHistory2(next);
456- if (transition >= std::numeric_limits<ptrie::uint>::max() - 1) {
457- auto[_, transition] = states.getHistory(next);
458- nested_transitions.push(transition);
459- break;
460- }
461+ nested_transitions.push(std::make_pair(next, transition));
462 next = state;
463- trans = transition;
464- nested_transitions.push(transition);
465- }
466+ } while (next != seedId);
467 }
468 return;
469 }
470@@ -151,29 +154,26 @@
471 }
472
473 template<typename W>
474- ostream &NestedDepthFirstSearch<W>::printTransition(size_t transition, uint indent, ostream &os) {
475- if (transition == std::numeric_limits<ptrie::uint>::max() - 1) {
476- os << std::string(indent, '\t') << "<deadlock/>";
477- return os;
478- }
479- std::string tname = states.net().transitionNames()[transition];
480- os << std::string(indent, '\t') << "<transition id=\"" << tname << "\" index=\"" << transition << "\"/>";
481- return os;
482- }
483-
484- template<typename W>
485- void NestedDepthFirstSearch<W>::printTrace(std::stack<size_t> &transitions) {
486- std::cerr << "Trace:\n<trace>\n";
487+ void NestedDepthFirstSearch<W>::printTrace(std::stack<std::pair<size_t, size_t>> &transitions, std::ostream &os)
488+ {
489+ State state = factory.newState();
490+ os << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
491+ "<trace>\n";
492 while (!transitions.empty()) {
493- printTransition(transitions.top(), 1) << std::endl;
494+ auto [stateid, transition] = transitions.top();
495+ states.decode(state, stateid);
496+ printTransition(transition, state, os) << std::endl;
497 transitions.pop();
498 }
499- std::cerr << "\t<loop>" << std::endl;
500+ printLoop(os);
501 while (!nested_transitions.empty()) {
502- printTransition(nested_transitions.top(), 2) << std::endl;
503+ auto [stateid, transition] = nested_transitions.top();
504+ states.decode(state, stateid);
505+
506+ printTransition(transition, state, os) << std::endl;
507 nested_transitions.pop();
508 }
509- std::cerr << "\t</loop>" << std::endl << "</trace>" << std::endl;
510+ os << std::endl << "</trace>" << std::endl;
511 }
512
513
514
515=== modified file 'src/LTL/Algorithm/TarjanModelChecker.cpp'
516--- src/LTL/Algorithm/TarjanModelChecker.cpp 2021-03-02 12:06:17 +0000
517+++ src/LTL/Algorithm/TarjanModelChecker.cpp 2021-03-04 10:04:52 +0000
518@@ -47,7 +47,12 @@
519 pop();
520 continue;
521 }
522- const idx_t stateid = seen.add(working).second;
523+ auto[isnew, stateid] = seen.add(working);
524+ if constexpr (SaveTrace) {
525+ if (isnew) {
526+ seen.setHistory(stateid, successorGenerator->fired());
527+ }
528+ }
529 dtop.sucinfo.last_state = stateid;
530
531 // lookup successor in 'hash' table
532@@ -68,46 +73,13 @@
533 if constexpr (SaveTrace) {
534 // print counter-example if it exists.
535 if (violation) {
536- State next = factory.newState();
537- std::cerr << "Printing trace: " << std::endl;
538- std::vector<DEntry> rev;
539- auto sz = dstack.size();
540- // dump stack to vector to allow iteration
541- for (idx_t i = 0; i < sz; ++i) {
542- rev.push_back(dstack.top());
543+ std::stack<DEntry> revstack;
544+ while (!dstack.empty()) {
545+ revstack.push(std::move(dstack.top()));
546 dstack.pop();
547 }
548- idx_t pos = 0;
549- // print dstack in-order. rev[0] is dstack.top(), so loop vector in reverse
550- for (int i = rev.size() - 1; i >= 0; --i) {
551- pos = rev[i].pos;
552- seen.decode(parent, cstack[pos].stateid);
553- _dump_state(parent);
554- cstack[pos].lowlink = std::numeric_limits<idx_t>::max();
555- if (i > 0) {
556- // print transition to next state
557- seen.decode(next, cstack[rev[i - 1].pos].stateid);
558- successorGenerator->prepare(&parent);
559- while (successorGenerator->next(working)) {
560- if (working == next) {
561- std::cerr << net.transitionNames()[successorGenerator->last_transition()]
562- << std::endl;
563- break;
564- }
565- }
566- }
567- }
568-
569- // follow lowsource until back in dstack
570- pos = cstack[pos].lowsource;
571- if (cstack[pos].lowlink != std::numeric_limits<idx_t>::max()) {
572- std::cerr << "Printing looping part\n";
573- }
574- while (cstack[pos].lowlink != std::numeric_limits<idx_t>::max()) {
575- seen.decode(parent, cstack[pos].stateid);
576- _dump_state(parent);
577- pos = cstack[pos].lowsource;
578- }
579+ printTrace(std::move(revstack));
580+ return false;
581 }
582 }
583 }
584@@ -176,7 +148,10 @@
585 // either way update the component ID of the state we came from.
586 cstack[from].lowlink = cstack[to].lowlink;
587 if constexpr (SaveTrace) {
588- cstack[from].lowsource = to;
589+ loopstate = cstack[to].stateid;
590+ looptrans = successorGenerator->fired();
591+ cstack[from].lowsource = cstack[to].lowlink;
592+
593 }
594 }
595 }
596@@ -192,9 +167,46 @@
597 return res;
598 }
599
600+
601+ template<bool SaveTrace>
602+ void TarjanModelChecker<SaveTrace>::printTrace(std::stack<DEntry> &&dstack, std::ostream &os)
603+ {
604+ if constexpr (!SaveTrace) {
605+ return;
606+ } else {
607+ State state = factory.newState();
608+ dstack.pop();
609+ os << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
610+ "<trace>\n";
611+ unsigned long p;
612+ // print (reverted) dstack
613+ while (!dstack.empty()) {
614+ p = dstack.top().pos;
615+ auto stateid = cstack[p].stateid;
616+ auto[parent, tid] = seen.getHistory(stateid);
617+ seen.decode(state, stateid);
618+ printTransition(tid, state, os) << '\n';
619+ cstack[p].lowlink = std::numeric_limits<idx_t>::max();
620+ dstack.pop();
621+ }
622+ printLoop(os);
623+ // follow previously found back edges via lowsource until back in dstack.
624+ p = cstack[p].lowsource;
625+ while (cstack[p].lowlink != std::numeric_limits<idx_t>::max()) {
626+ auto[parent, tid] = seen.getHistory(cstack[p].stateid);
627+ seen.decode(state, cstack[p].stateid);
628+ printTransition(tid, state, os) << '\n';
629+ p = cstack[p].lowsource;
630+ }
631+ printTransition(looptrans, state, os) << '\n';
632+
633+ os << "</trace>" << std::endl;
634+ }
635+ }
636+
637 template
638 class TarjanModelChecker<true>;
639
640 template
641 class TarjanModelChecker<false>;
642-}
643\ No newline at end of file
644+}
645
646=== modified file 'src/PetriEngine/Reachability/ResultPrinter.cpp'
647--- src/PetriEngine/Reachability/ResultPrinter.cpp 2020-04-23 15:26:52 +0000
648+++ src/PetriEngine/Reachability/ResultPrinter.cpp 2021-03-04 10:04:52 +0000
649@@ -132,7 +132,7 @@
650 if(options->cpnOverApprox)
651 std::cout << "\nSolved using CPN Approximation\n" << std::endl;
652
653- if(showTrace && options->trace)
654+ if(showTrace && options->trace != TraceLevel::None)
655 {
656 if(stateset == nullptr)
657 {
658
659=== modified file 'src/VerifyPN.cpp'
660--- src/VerifyPN.cpp 2021-03-03 08:34:27 +0000
661+++ src/VerifyPN.cpp 2021-03-04 10:04:52 +0000
662@@ -169,7 +169,22 @@
663 } else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--no-statistics") == 0) {
664 options.printstatistics = false;
665 } else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--trace") == 0) {
666- options.trace = true;
667+ if (argc > i + 1) {
668+ if (strcmp("1", argv[i+1]) == 0) {
669+ options.trace = TraceLevel::Transitions;
670+ }
671+ else if (strcmp("2", argv[i+1]) == 0) {
672+ options.trace = TraceLevel::Full;
673+ }
674+ else {
675+ options.trace = TraceLevel::Full;
676+ continue;
677+ }
678+ ++i;
679+ }
680+ else {
681+ options.trace = TraceLevel::Full;
682+ }
683 } else if (strcmp(argv[i], "-x") == 0 || strcmp(argv[i], "--xml-queries") == 0) {
684 if (i == argc - 1) {
685 fprintf(stderr, "Missing number after \"%s\"\n\n", argv[i]);
686@@ -1122,7 +1137,7 @@
687 if (options.enablereduction > 0) {
688 // Compute how many times each place appears in the query
689 builder.startTimer();
690- builder.reduce(queries, results, options.enablereduction, options.trace, nullptr, options.reductionTimeout, options.reductions);
691+ builder.reduce(queries, results, options.enablereduction, options.trace != TraceLevel::None, nullptr, options.reductionTimeout, options.reductions);
692 printer.setReducer(builder.getReducer());
693 }
694
695@@ -1199,9 +1214,9 @@
696 std::unique_ptr<LTL::ModelChecker> modelChecker;
697 switch (options.ltlalgorithm) {
698 case LTL::Algorithm::NDFS:
699- if (options.trace)
700+ if (options.trace != TraceLevel::None)
701 modelChecker = std::make_unique<LTL::NestedDepthFirstSearch<PetriEngine::Structures::TracableStateSet>>
702- (*net, negated_formula, options.ltluseweak);
703+ (*net, negated_formula, options.ltluseweak, options.trace);
704 else
705 modelChecker = std::make_unique<LTL::NestedDepthFirstSearch<PetriEngine::Structures::StateSet>>
706 (*net, negated_formula, options.ltluseweak);
707@@ -1209,8 +1224,8 @@
708 case LTL::Algorithm::RandomNDFS:
709 modelChecker = std::make_unique<LTL::RandomNDFS>(*net, negated_formula);
710 case LTL::Algorithm::Tarjan:
711- if (options.trace)
712- modelChecker = std::make_unique<LTL::TarjanModelChecker<true>>(*net, negated_formula, options.ltluseweak);
713+ if (options.trace != TraceLevel::None)
714+ modelChecker = std::make_unique<LTL::TarjanModelChecker<true>>(*net, negated_formula, options.ltluseweak, options.trace);
715 else
716 modelChecker = std::make_unique<LTL::TarjanModelChecker<false>>(*net, negated_formula, options.ltluseweak);
717 break;
718@@ -1266,7 +1281,7 @@
719 //Reachability search
720 strategy.reachable(queries, results,
721 options.printstatistics,
722- options.trace);
723+ options.trace != TraceLevel::None);
724 }
725 else
726 {
727@@ -1281,7 +1296,7 @@
728 options.stubbornreduction,
729 options.statespaceexploration,
730 options.printstatistics,
731- options.trace);
732+ options.trace != TraceLevel::None);
733 }
734
735 return SuccessCode;

Subscribers

People subscribed via source and target branches

to all changes: