Merge lp:~tapaal-ltl/verifypn/ltl-trace-fixes into lp:verifypn
- ltl-trace-fixes
- Merge into new-trunk
Proposed by
Nikolaj Jensen Ulrik
Status: | Merged |
---|---|
Approved by: | Jiri Srba |
Approved revision: | 251 |
Merged at revision: | 247 |
Proposed branch: | lp:~tapaal-ltl/verifypn/ltl-trace-fixes |
Merge into: | lp:verifypn |
Diff against target: |
521 lines (+356/-34) 7 files modified
include/LTL/Algorithm/ModelChecker.h (+13/-2) include/PetriEngine/TraceReplay.h (+69/-0) include/PetriEngine/options.h (+1/-1) src/LTL/CMakeLists.txt (+1/-1) src/PetriEngine/CMakeLists.txt (+1/-1) src/PetriEngine/TraceReplay.cpp (+237/-0) src/VerifyPN.cpp (+34/-29) |
To merge this branch: | bzr merge lp:~tapaal-ltl/verifypn/ltl-trace-fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jiri Srba | Approve | ||
Review via email:
|
Commit message
Description of the change
Fix misunderstanding of trace formats for LTL traces.
To post a comment you must log in.
- 251. By Nikolaj Jensen Ulrik
-
Trace replay now works for non-LTL flows too
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-08-03 14:19:42 +0000 |
3 | +++ include/LTL/Algorithm/ModelChecker.h 2021-08-06 11:23:06 +0000 |
4 | @@ -115,11 +115,22 @@ |
5 | if (traceLevel == TraceLevel::Full) { |
6 | os << ">"; |
7 | os << std::endl; |
8 | - for (size_t i = 0; i < net->numberOfPlaces(); ++i) { |
9 | + auto [fpre, lpre] = net->preset(transition); |
10 | + for(; fpre < lpre; ++fpre) { |
11 | + if (fpre->inhibitor) { |
12 | + assert(state.marking()[fpre->place] < fpre->tokens); |
13 | + continue; |
14 | + } |
15 | + for (size_t i = 0; i < fpre->tokens; ++i) { |
16 | + assert(state.marking()[fpre->place] >= fpre->tokens); |
17 | + os << tokenIndent << R"(<token age="0" place=")" << net->placeNames()[fpre->place] << "\"/>\n"; |
18 | + } |
19 | + } |
20 | + /*for (size_t i = 0; i < net->numberOfPlaces(); ++i) { |
21 | for (size_t j = 0; j < state.marking()[i]; ++j) { |
22 | os << tokenIndent << R"(<token age="0" place=")" << net->placeNames()[i] << "\"/>\n"; |
23 | } |
24 | - } |
25 | + }*/ |
26 | os << indent << "</transition>"; |
27 | } |
28 | else { |
29 | |
30 | === removed file 'include/LTL/Replay.h' |
31 | === added file 'include/PetriEngine/TraceReplay.h' |
32 | --- include/PetriEngine/TraceReplay.h 1970-01-01 00:00:00 +0000 |
33 | +++ include/PetriEngine/TraceReplay.h 2021-08-06 11:23:06 +0000 |
34 | @@ -0,0 +1,69 @@ |
35 | +/* Copyright (C) 2021 Nikolaj J. Ulrik <nikolaj@njulrik.dk>, |
36 | + * Simon M. Virenfeldt <simon@simwir.dk> |
37 | + * |
38 | + * This program is free software: you can redistribute it and/or modify |
39 | + * it under the terms of the GNU General Public License as published by |
40 | + * the Free Software Foundation, either version 3 of the License, or |
41 | + * (at your option) any later version. |
42 | + * |
43 | + * This program is distributed in the hope that it will be useful, |
44 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
45 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
46 | + * GNU General Public License for more details. |
47 | + * |
48 | + * You should have received a copy of the GNU General Public License |
49 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
50 | + */ |
51 | + |
52 | +#ifndef VERIFYPN_TRACEREPLAY_H |
53 | +#define VERIFYPN_TRACEREPLAY_H |
54 | + |
55 | +#include "PetriEngine/PetriNet.h" |
56 | +#include "PetriEngine/options.h" |
57 | +#include "PetriEngine/PQL/PQL.h" |
58 | +#include "PetriEngine/SuccessorGenerator.h" |
59 | + |
60 | +#include <iostream> |
61 | +#include <utility> |
62 | +#include <rapidxml.hpp> |
63 | + |
64 | +namespace PetriEngine { |
65 | + class TraceReplay { |
66 | + public: |
67 | + TraceReplay(std::istream &is, const PetriEngine::PetriNet *net, const options_t &options); |
68 | + |
69 | + struct Token { |
70 | + std::string place; |
71 | + }; |
72 | + |
73 | + struct Transition { |
74 | + explicit Transition(std::string id, int buchi) : id(std::move(id)), buchi_state(buchi) {} |
75 | + |
76 | + std::string id; |
77 | + int buchi_state; |
78 | + std::unordered_map<uint32_t, uint32_t> tokens; |
79 | + }; |
80 | + |
81 | + void parse(std::istream &xml, const PetriEngine::PetriNet *net); |
82 | + |
83 | + bool replay(const PetriEngine::PetriNet *net, const PetriEngine::PQL::Condition_ptr &cond); |
84 | + |
85 | + std::vector<Transition> trace; |
86 | + private: |
87 | + |
88 | + static constexpr auto DEADLOCK_TRANS = "##deadlock"; |
89 | + void parseRoot(const rapidxml::xml_node<> *pNode); |
90 | + |
91 | + Transition parseTransition(const rapidxml::xml_node<char> *pNode); |
92 | + |
93 | + void parseToken(const rapidxml::xml_node<char> *pNode, std::unordered_map<uint32_t, uint32_t> ¤t_marking); |
94 | + |
95 | + size_t loop_idx = std::numeric_limits<size_t>::max(); |
96 | + std::unordered_map<std::string, int> transitions; |
97 | + std::unordered_map<std::string, int> places; |
98 | + bool _play_trace(const PetriEngine::PetriNet *net, PetriEngine::SuccessorGenerator &successorGenerator); |
99 | + const options_t &options; |
100 | + }; |
101 | +} |
102 | + |
103 | +#endif //VERIFYPN_TRACEREPLAY_H |
104 | |
105 | === modified file 'include/PetriEngine/options.h' |
106 | --- include/PetriEngine/options.h 2021-07-22 09:46:13 +0000 |
107 | +++ include/PetriEngine/options.h 2021-08-06 11:23:06 +0000 |
108 | @@ -85,7 +85,7 @@ |
109 | BuchiOptimization buchiOptimization = BuchiOptimization::Low; |
110 | const char* ltlHeuristic = "aut"; |
111 | |
112 | - bool replay = false; |
113 | + bool replay_trace = false; |
114 | std::string replay_file; |
115 | |
116 | |
117 | |
118 | === modified file 'src/LTL/CMakeLists.txt' |
119 | --- src/LTL/CMakeLists.txt 2021-04-29 13:35:13 +0000 |
120 | +++ src/LTL/CMakeLists.txt 2021-08-06 11:23:06 +0000 |
121 | @@ -7,7 +7,7 @@ |
122 | add_subdirectory(Stubborn) |
123 | add_subdirectory(SuccessorGeneration) |
124 | |
125 | -add_library(LTL ${HEADER_FILES} LTLMain.cpp Replay.cpp) |
126 | +add_library(LTL ${HEADER_FILES} LTLMain.cpp) |
127 | |
128 | if (VERIFYPN_Static OR APPLE) |
129 | target_link_libraries(LTL PRIVATE LTL_algorithm LTLStubborn LTL_simplification LTLSuccessorGeneration spot bddx) |
130 | |
131 | === removed file 'src/LTL/Replay.cpp' |
132 | === modified file 'src/PetriEngine/CMakeLists.txt' |
133 | --- src/PetriEngine/CMakeLists.txt 2021-04-29 07:47:52 +0000 |
134 | +++ src/PetriEngine/CMakeLists.txt 2021-08-06 11:23:06 +0000 |
135 | @@ -15,6 +15,6 @@ |
136 | ReducingSuccessorGenerator.cpp |
137 | STSolver.cpp |
138 | SuccessorGenerator.cpp |
139 | -) |
140 | + TraceReplay.cpp ../../include/PetriEngine/TraceReplay.h) |
141 | |
142 | target_link_libraries(PetriEngine PRIVATE Colored Structures Simplification Stubborn Reachability PQL TAR) |
143 | |
144 | === added file 'src/PetriEngine/TraceReplay.cpp' |
145 | --- src/PetriEngine/TraceReplay.cpp 1970-01-01 00:00:00 +0000 |
146 | +++ src/PetriEngine/TraceReplay.cpp 2021-08-06 11:23:06 +0000 |
147 | @@ -0,0 +1,237 @@ |
148 | +/* Copyright (C) 2021 Nikolaj J. Ulrik <nikolaj@njulrik.dk>, |
149 | + * Simon M. Virenfeldt <simon@simwir.dk> |
150 | + * |
151 | + * This program is free software: you can redistribute it and/or modify |
152 | + * it under the terms of the GNU General Public License as published by |
153 | + * the Free Software Foundation, either version 3 of the License, or |
154 | + * (at your option) any later version. |
155 | + * |
156 | + * This program is distributed in the hope that it will be useful, |
157 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
158 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
159 | + * GNU General Public License for more details. |
160 | + * |
161 | + * You should have received a copy of the GNU General Public License |
162 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
163 | + */ |
164 | + |
165 | +#include "PetriEngine/PQL/PQL.h" |
166 | +#include "PetriEngine/PetriNet.h" |
167 | +#include "PetriEngine/TraceReplay.h" |
168 | +#include "PetriEngine/Structures/State.h" |
169 | +#include "PetriEngine/SuccessorGenerator.h" |
170 | +#include "LTL/LTLToBuchi.h" |
171 | + |
172 | +#include <rapidxml.hpp> |
173 | +#include <vector> |
174 | +#include <iostream> |
175 | +#include <cstring> |
176 | + |
177 | + |
178 | +namespace PetriEngine { |
179 | + |
180 | + TraceReplay::TraceReplay(std::istream &is, const PetriEngine::PetriNet *net, const options_t &options) |
181 | + :options(options) { |
182 | + parse(is, net); |
183 | + } |
184 | + |
185 | + void TraceReplay::parse(std::istream &xml, const PetriNet *net) { |
186 | + places.clear(); |
187 | + transitions.clear(); |
188 | + // preallocate reverse lookup for transition and place names. Assume this is always called with the same Petri net. |
189 | + for (int i = 0; i < net->placeNames().size(); ++i) { |
190 | + places[net->placeNames()[i]] = i; |
191 | + } |
192 | + for (int i = 0; i < net->transitionNames().size(); ++i) { |
193 | + transitions[net->transitionNames()[i]] = i; |
194 | + } |
195 | + transitions[DEADLOCK_TRANS] = -1; |
196 | + |
197 | + // TODO can also validate transition names up front. |
198 | + rapidxml::xml_document<> doc; |
199 | + std::vector<char> buffer((std::istreambuf_iterator<char>(xml)), std::istreambuf_iterator<char>()); |
200 | + buffer.push_back('\0'); |
201 | + doc.parse<0>(buffer.data()); |
202 | + rapidxml::xml_node<> *root = doc.first_node(); |
203 | + |
204 | + if (root) { |
205 | + parseRoot(root); |
206 | + } else { |
207 | + std::cerr << "Error getting root node." << std::endl; |
208 | + assert(false); |
209 | + exit(1); |
210 | + } |
211 | + |
212 | + } |
213 | + |
214 | + void TraceReplay::parseRoot(const rapidxml::xml_node<> *pNode) { |
215 | + if (std::strcmp(pNode->name(), "trace") != 0) { |
216 | + std::cerr << "Error: Expected trace node. Got: " << pNode->name() << std::endl; |
217 | + assert(false); |
218 | + exit(1); |
219 | + } |
220 | + for (auto it = pNode->first_node(); it; it = it->next_sibling()) { |
221 | + if (std::strcmp(it->name(), "loop") == 0) loop_idx = trace.size(); |
222 | + else if (std::strcmp(it->name(), "transition") == 0 || std::strcmp(it->name(), "deadlock") == 0) { |
223 | + trace.push_back(parseTransition(it)); |
224 | + } else { |
225 | + std::cerr << "Error: Expected transition or loop node. Got: " << it->name() << std::endl; |
226 | + assert(false); |
227 | + exit(1); |
228 | + } |
229 | + } |
230 | + if (loop_idx == std::numeric_limits<size_t>::max() && options.logic == TemporalLogic::LTL) { |
231 | + std::cerr << "Error: Missing <loop/> statement in trace\n"; |
232 | + exit(1); |
233 | + } |
234 | + } |
235 | + |
236 | + TraceReplay::Transition TraceReplay::parseTransition(const rapidxml::xml_node<char> *pNode) { |
237 | + std::string id; |
238 | + int buchi = -1; |
239 | + for (auto it = pNode->first_attribute(); it; it = it->next_attribute()) { |
240 | + if (std::strcmp(it->name(), "id") == 0) { |
241 | + id = std::string(it->value()); |
242 | + } |
243 | + if (std::strstr(it->name(), "buchi") != nullptr) { |
244 | + // buchi field is sometimes spelled slightly differently, but will always contain 'buchi' |
245 | + buchi = std::stoi(it->value()); |
246 | + } |
247 | + } |
248 | + if (strcmp(pNode->name(), "deadlock") == 0) { |
249 | + id = DEADLOCK_TRANS; |
250 | + } |
251 | + if (id.empty()) { |
252 | + std::cerr << "Error: Transition has no id attribute" << std::endl; |
253 | + assert(false); |
254 | + exit(1); |
255 | + } |
256 | + |
257 | + Transition transition(id, buchi); |
258 | + |
259 | + for (auto it = pNode->first_node(); it; it = it->next_sibling()) { |
260 | + if (std::strcmp(it->name(), "token") != 0) { |
261 | + std::cerr << "Warning: Unexpected transition child. Expected: token, but got: " << it->name() |
262 | + << std::endl; |
263 | + } |
264 | + parseToken(it, transition.tokens); |
265 | + } |
266 | + |
267 | + return transition; |
268 | + } |
269 | + |
270 | + void |
271 | + TraceReplay::parseToken(const rapidxml::xml_node<char> *pNode, |
272 | + std::unordered_map<uint32_t, uint32_t> ¤t_marking) { |
273 | + for (auto it = pNode->first_attribute(); it; it = it->next_attribute()) { |
274 | + if (std::strcmp(it->name(), "place") == 0) { |
275 | + std::string val{it->value()}; |
276 | + if (current_marking.find(places.at(val)) == current_marking.end()) { |
277 | + current_marking[places.at(val)] = 1; |
278 | + } else { |
279 | + ++current_marking[places.at(val)]; |
280 | + } |
281 | + } |
282 | + } |
283 | + } |
284 | + |
285 | + bool TraceReplay::replay(const PetriEngine::PetriNet *net, const PetriEngine::PQL::Condition_ptr &cond) { |
286 | + //spot::print_dot(std::cerr, buchiGenerator.aut._buchi); |
287 | + PetriEngine::Structures::State state; |
288 | + state.setMarking(net->makeInitialMarking()); |
289 | + PetriEngine::SuccessorGenerator successorGenerator(*net); |
290 | + |
291 | + std::cout << "Playing back trace. Length: " << trace.size() << std::endl; |
292 | + if (_play_trace(net, successorGenerator)) { |
293 | + std::cout << "Replay complete. No errors" << std::endl; |
294 | + return true; |
295 | + } |
296 | + return false; |
297 | + } |
298 | + |
299 | + bool |
300 | + TraceReplay::_play_trace(const PetriEngine::PetriNet *net, PetriEngine::SuccessorGenerator &successorGenerator) { |
301 | + PetriEngine::Structures::State state; |
302 | + PetriEngine::Structures::State loopstate; |
303 | + bool looping = false; |
304 | + state.setMarking(net->makeInitialMarking()); |
305 | + loopstate.setMarking(net->makeInitialMarking()); |
306 | + for (int i = 0; i < trace.size(); ++i) { |
307 | + const Transition &transition = trace[i]; |
308 | + // looping part should end up at the state _before_ the <loop/> tag, |
309 | + // hence copy state from previous iteration. |
310 | + if (i == loop_idx) { |
311 | + memcpy(loopstate.marking(), state.marking(), sizeof(uint32_t) * net->numberOfPlaces()); |
312 | + looping = true; |
313 | + } |
314 | + successorGenerator.prepare(&state); |
315 | + auto it = transitions.find(transition.id); |
316 | + if (it == std::end(transitions)) { |
317 | + std::cerr << "Unrecognized transition name " << transition.id << std::endl; |
318 | + assert(false); |
319 | + exit(1); |
320 | + } |
321 | + int tid = it->second; |
322 | + |
323 | + if (tid != -1) { |
324 | + // fire transition |
325 | + if (!successorGenerator.checkPreset(tid)) { |
326 | + std::cerr |
327 | + << "ERROR the provided trace cannot be replayed on the provided model. \nOffending transition: " |
328 | + << transition.id << " at index: " << i << "\n"; |
329 | + return false; |
330 | + } |
331 | + successorGenerator.consumePreset(state, tid); |
332 | + successorGenerator.producePostset(state, tid); |
333 | + } else { |
334 | + // -1 is deadlock, assert deadlocked state. |
335 | + // LTL deadlocks are unambiguously in the Petri net, since Büchi deadlocks won't generate any successor in the first place. |
336 | + assert(i == trace.size() - 1); |
337 | + if (!net->deadlocked(state.marking())) { |
338 | + std::cerr << "ERROR: Trace claimed the net was deadlocked, but there are enabled transitions.\n"; |
339 | + return false; |
340 | + } |
341 | + return true; |
342 | + } |
343 | + |
344 | + if (!transition.tokens.empty()) { |
345 | + auto[finv, linv] = net->preset(transitions.at(transition.id)); |
346 | + for (; finv != linv; ++finv) { |
347 | + if (finv->inhibitor) { |
348 | + |
349 | + } else { |
350 | + auto it = transition.tokens.find(finv->place); |
351 | + if (it == std::end(transition.tokens)) { |
352 | + std::cerr << "ERROR: Pre-place " << net->placeNames()[finv->place] << " of transition " |
353 | + << transition.id << " was not mentioned in trace.\n"; |
354 | + return false; |
355 | + } |
356 | + if (it->second != finv->tokens) { |
357 | + std::cerr << "ERROR: Pre-place " << net->placeNames()[finv->place] << " of transition " |
358 | + << transition.id << "has arc weight " << finv->tokens << " but trace consumes " |
359 | + << it->second << " tokens.\n"; |
360 | + return false; |
361 | + } |
362 | + } |
363 | + } |
364 | + } |
365 | + } |
366 | + |
367 | + bool err = false; |
368 | + if (looping) { |
369 | + for (int i = 0; i < net->numberOfPlaces(); ++i) { |
370 | + if (state.marking()[i] != loopstate.marking()[i]) { |
371 | + if (!err) { |
372 | + std::cerr << "ERROR end state not equal to expected loop state.\n"; |
373 | + err = true; |
374 | + } |
375 | + std::cerr << " " << net->placeNames()[i] << ": expected" << loopstate.marking()[i] << ", actual " |
376 | + << state.marking()[i] << '\n'; |
377 | + } |
378 | + } |
379 | + } |
380 | + |
381 | + return !err; |
382 | + } |
383 | +} |
384 | + |
385 | |
386 | === modified file 'src/VerifyPN.cpp' |
387 | --- src/VerifyPN.cpp 2021-08-03 12:00:44 +0000 |
388 | +++ src/VerifyPN.cpp 2021-08-06 11:23:06 +0000 |
389 | @@ -86,7 +86,7 @@ |
390 | #include "PetriEngine/PQL/Expressions.h" |
391 | #include "PetriEngine/Colored/ColoredPetriNetBuilder.h" |
392 | #include "LTL/LTL.h" |
393 | -#include "LTL/Replay.h" |
394 | +#include "PetriEngine/TraceReplay.h" |
395 | #include "LTL/LTLMain.h" |
396 | |
397 | #include <atomic> |
398 | @@ -393,8 +393,8 @@ |
399 | } |
400 | ++i; |
401 | } |
402 | - else if (strcmp(argv[i], "--replay") == 0) { |
403 | - options.replay = true; |
404 | + else if (strcmp(argv[i], "--trace-replay") == 0) { |
405 | + options.replay_trace = true; |
406 | options.replay_file = std::string(argv[++i]); |
407 | } |
408 | |
409 | @@ -584,9 +584,12 @@ |
410 | " simplification and Büchi construction, but gives worse\n" |
411 | " results since there is less opportunity for optimizations.\n" |
412 | " --noverify Disable verification e.g. for getting unfolded net\n" |
413 | - " --replay <file> Replays an LTL trace output by the --trace option.\n" |
414 | + " --trace-replay <file> Replays a trace as output by the --trace option.\n" |
415 | " The trace is verified against the provided model and query.\n" |
416 | - " --spot-optimization <1,2,3> The optimization level passed to Spot for büchi creation. 1: Low (default), 2: Medium, 3: High\n" |
417 | + " Mainly useful for debugging.\n" |
418 | + " --spot-optimization <1,2,3> The optimization level passed to Spot for Büchi automaton creation.\n" |
419 | + " 1: Low (default), 2: Medium, 3: High\n" |
420 | + " Using optimization levels above 1 may cause exponential blowups and is not recommended.\n" |
421 | "\n" |
422 | "Return Values:\n" |
423 | " 0 Successful, query satisfiable\n" |
424 | @@ -625,17 +628,20 @@ |
425 | return SuccessCode; |
426 | } |
427 | else if (strcmp(argv[i], "--ltl-heur-help") == 0) { |
428 | - printf("Heuristics for LTL model checking are specified using the following grammar:" |
429 | + printf("Heuristics for LTL model checking are specified using the following grammar:\n" |
430 | " heurexp : {'aut' | 'automaton'}\n" |
431 | " | {'dist' | 'distance'}\n" |
432 | - " | {'fc' | 'firecount' | 'fire-count'} INT\n" |
433 | + " | {'fc' | 'firecount' | 'fire-count'} <threshold>?\n" |
434 | " | '(' heurexp ')'\n" |
435 | " | 'sum' <weight>? heurexp <weight?> heurexp\n" |
436 | " | 'sum' '(' <weight>? heurexp ',' <weight>? heurexp ')'\n" |
437 | "Example strings:\n" |
438 | - " - 'aut' - use the automaton heuristic for verification.\n" |
439 | + " - aut - use the automaton heuristic for verification.\n" |
440 | " - sum dist fc 1000 - use the sum of distance heuristic and fire count heuristic with threshold 1000.\n" |
441 | + "Weight for sum and threshold for fire count are optional and integral.\n" |
442 | + "Sum weights default to 1 (thus plain sum), and default fire count threshold is 5000.\n" |
443 | ); |
444 | + return SuccessCode; |
445 | } |
446 | else if (options.modelfile == NULL) { |
447 | options.modelfile = argv[i]; |
448 | @@ -725,8 +731,8 @@ |
449 | } |
450 | } |
451 | |
452 | - if (options.replay && options.logic != TemporalLogic::LTL) { |
453 | - std::cerr << "Argument Error: Trace replay is only supported for LTL model checking." << std::endl; |
454 | + if (false && options.replay_trace && options.logic != TemporalLogic::LTL) { |
455 | + std::cerr << "Argument Error: Trace replay_trace is only supported for LTL model checking." << std::endl; |
456 | return ErrorCode; |
457 | } |
458 | |
459 | @@ -1493,24 +1499,23 @@ |
460 | |
461 | if(alldone) return SuccessCode; |
462 | |
463 | - if (options.replay) { |
464 | + if (options.replay_trace) { |
465 | if (contextAnalysis(cpnBuilder, builder, net.get(), queries) != ContinueCode) { |
466 | std::cerr << "Fatal error assigning indexes" << std::endl; |
467 | exit(1); |
468 | } |
469 | std::ifstream replay_file(options.replay_file, std::ifstream::in); |
470 | - LTL::Replay replay{replay_file, net.get()}; |
471 | - for (int i = 0; i < results.size(); ++i) { |
472 | - if (results[i] == ResultPrinter::LTL) { |
473 | - replay.replay(net.get(), queries[i], options); |
474 | - } |
475 | + PetriEngine::TraceReplay replay{replay_file, net.get(), options}; |
476 | + for (size_t i=0; i < queries.size(); ++i) { |
477 | + if (results[i] == ResultPrinter::Unknown || results[i] == ResultPrinter::CTL || results[i] == ResultPrinter::LTL) |
478 | + replay.replay(net.get(), queries[i]); |
479 | } |
480 | return SuccessCode; |
481 | } |
482 | |
483 | if(options.doVerification){ |
484 | |
485 | - //----------------------- Verify CTL queries -----------------------// |
486 | + //----------------------- Verify CTL queries -----------------------// |
487 | std::vector<size_t> ctl_ids; |
488 | std::vector<size_t> ltl_ids; |
489 | for(size_t i = 0; i < queries.size(); ++i) |
490 | @@ -1522,19 +1527,19 @@ |
491 | else if (results[i] == ResultPrinter::LTL) { |
492 | ltl_ids.push_back(i); |
493 | } |
494 | - } |
495 | + } |
496 | |
497 | - if (options.replay) { |
498 | - if (contextAnalysis(cpnBuilder, builder, net.get(), queries) != ContinueCode) { |
499 | - std::cerr << "Fatal error assigning indexes" << std::endl; |
500 | - exit(1); |
501 | - } |
502 | - std::ifstream replay_file(options.replay_file, std::ifstream::in); |
503 | - LTL::Replay replay{replay_file, net.get()}; |
504 | - for (int i : ltl_ids) { |
505 | - replay.replay(net.get(), queries[i], options); |
506 | - } |
507 | - return SuccessCode; |
508 | + if (options.replay_trace) { |
509 | + if (contextAnalysis(cpnBuilder, builder, net.get(), queries) != ContinueCode) { |
510 | + std::cerr << "Fatal error assigning indexes" << std::endl; |
511 | + exit(1); |
512 | + } |
513 | + std::ifstream replay_file(options.replay_file, std::ifstream::in); |
514 | + PetriEngine::TraceReplay replay{replay_file, net.get(), options}; |
515 | + for (int i : ltl_ids) { |
516 | + replay.replay(net.get(), queries[i]); |
517 | + } |
518 | + return SuccessCode; |
519 | } |
520 | |
521 | if (!ctl_ids.empty()) { |
Only changes the trace behaviour, consistency check is not needed.