Merge lp:~verifydtapn-contributers/verifydtapn/workflowForTrunk into lp:verifydtapn

Proposed by Mathias Grund Sørensen
Status: Merged
Approved by: Jiri Srba
Approved revision: 337
Merged at revision: 289
Proposed branch: lp:~verifydtapn-contributers/verifydtapn/workflowForTrunk
Merge into: lp:verifydtapn
Diff against target: 1355 lines (+1009/-26)
21 files modified
src/Core/ArgsParser.cpp (+28/-1)
src/Core/ArgsParser.hpp (+1/-1)
src/Core/QueryParser/AST.hpp (+1/-0)
src/Core/TAPN/TimedPlace.hpp (+1/-0)
src/Core/VerificationOptions.hpp (+18/-3)
src/DiscreteVerification/DataStructures/NonStrictMarking.hpp (+19/-4)
src/DiscreteVerification/DataStructures/NonStrictMarkingBase.cpp (+2/-4)
src/DiscreteVerification/DataStructures/PWList.cpp (+14/-1)
src/DiscreteVerification/DataStructures/PWList.hpp (+25/-6)
src/DiscreteVerification/DataStructures/WaitingList.hpp (+66/-0)
src/DiscreteVerification/DataStructures/WorkflowPWList.hpp (+150/-0)
src/DiscreteVerification/DiscreteVerification.cpp (+45/-3)
src/DiscreteVerification/DiscreteVerification.hpp (+2/-0)
src/DiscreteVerification/SearchStrategies/SearchFactory.h (+4/-1)
src/DiscreteVerification/SearchStrategies/SearchStrategies.hpp (+1/-0)
src/DiscreteVerification/SearchStrategies/WorkflowMinFirst.hpp (+42/-0)
src/DiscreteVerification/VerificationTypes/WorkflowSoundness.cpp (+206/-0)
src/DiscreteVerification/VerificationTypes/WorkflowSoundness.hpp (+180/-0)
src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.cpp (+119/-0)
src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.hpp (+83/-0)
src/compile-mac-32-64.sh (+2/-2)
To merge this branch: bzr merge lp:~verifydtapn-contributers/verifydtapn/workflowForTrunk
Reviewer Review Type Date Requested Status
Peter Gjøl Jensen Approve
Jakob Taankvist Approve
Jiri Srba Approve
Review via email: mp+191910@code.launchpad.net

Description of the change

Adds workflow soundness and strong soundness verification.

To post a comment you must log in.
Revision history for this message
Jiri Srba (srba) wrote :

Tested and works as it should. Just make sure that the normal verification (EG, AG, EG, AF) is
not influenced in any way.

review: Approve
Revision history for this message
Peter Gjøl Jensen (peter-gjoel) wrote :

Line 701-702, why this change in access-level?
Is it reasonable to just ignore unused options, and give no warnings? (timedarts, ptries)?

The implementation of "getUnpassed" in the PW-list seems like a very inefficient waiting-list-ish thing.
"getCoveredMarking" also seems very inefficient, maybe a special hash-function would solve this problem (use only place/token-count as seed of the hash).
Also, why are these in the PWList implementation and not in WorkflowPWList?

line 984-991 and 999-1005, please make a variable instead of constantly casting to WorkflowSoundnessMetaData, it makes the code unreadable.
I am not entirely sure, but I think you need a delete marking at line 1323 (you don't add it to the PW-list and you don't use it anywhere else) - there is a delete in the original reachabilitysearch-addtoPW.

I agree with Jiri that the changes do not affect the normal verification.

review: Needs Information
Revision history for this message
Jiri Srba (srba) wrote :

Agree, timedarts and Ptrie should give a error (warning). Btw. we hope Peter that
you will be able to add Ptrie to this at some point. This should not be too difficult, correct?

The other remarks make also good sense to me, Mathias, can you take a look please?

The only thing I am not sure about is the hashing on token-count. I am not sure how
this can help with discovery of covered markings on the passed/waiting list?

Revision history for this message
Mathias Grund Sørensen (mathias.grund) wrote :

> Line 701-702, why this change in access-level?
> Is it reasonable to just ignore unused options, and give no warnings?
> (timedarts, ptries)?

Yes, I will add a warning in this case.

> The implementation of "getUnpassed" in the PW-list seems like a very
> inefficient waiting-list-ish thing.

Yes, this is not very elaborate, but it will only be run once ever, so the overhead of doing something elaborate would most likely outweigh the benefit IMO.

> "getCoveredMarking" also seems very inefficient, maybe a special hash-function
> would solve this problem (use only place/token-count as seed of the hash).

Yes, this appears very simple. A more elaborate method which hashes on submarkings is used as an alternative in method checkForCoveringMarking, but it turns out the naive linear sweep is generally faster (due to growth in number of sub markings w.r.t. marking size).

But yes, I considered some kind of clever hashing, but due to time constraints I didn't have time come up with one. In any ways, I am not sure this will be as easy as it sounds. And also, I am not sure you will be able to get better performance than the method hashing on submarkings anyways, but you are welcome to see if you can come up with something clever.

Anyways, I will change this so that both methods are on WorkflowPWList to keep the logic together and use a flag for which one to use.

> Also, why are these in the PWList implementation and not in WorkflowPWList?

Yes, these could be moved to WorkflowPWList, I just made them in PWList in case I needed them for strong soundness (which uses normal PWList), but I didn't so I'll just move them.

> line 984-991 and 999-1005, please make a variable instead of constantly
> casting to WorkflowSoundnessMetaData, it makes the code unreadable.

OK, will do.

> I am not entirely sure, but I think you need a delete marking at line 1323
> (you don't add it to the PW-list and you don't use it anywhere else) - there
> is a delete in the original reachabilitysearch-addtoPW.

No, it shouldn't as the marking is looked up in the passed storage and this code is only executed if there is a match, thus a delete would delete it from the passed storage. However, I think the marking used to call AddToPW could be delete on line 1292 if there is a match is found.

> I agree with Jiri that the changes do not affect the normal verification.

Good. I'll implement the comments tomorrow and you can have another look.

Revision history for this message
Mathias Grund Sørensen (mathias.grund) wrote :

I have implemented Peters comments now. I also found a bug in the covering check so apparently both types of checks would be run if there was no match due to missing return (woops...) - this should increase performance on the examples where covering check was slow.

You are welcome to take a look again to see how it looks.

The change in access modifier was due to a problem I had with overriding something, but I got it to work correctly, so I have reverted it to protected.

Revision history for this message
Jiri Srba (srba) wrote :

I just tested and all works fine. Peter and Jakob, please, take a quick look so that we can merge it to trunk.

review: Approve
Revision history for this message
Jakob Taankvist (jakob-taankvist) wrote :

I just had a quick look i think it looks good, however to avoid code redundancy shouldn't the lookup function (line 308) be used in all the addToPassed functions? And do we really need this many addToPassed functions (don't they all do the same)?

review: Needs Information
332. By Mathias Grund Sørensen

Refactored addToPassed to use the lookup method.

Revision history for this message
Mathias Grund Sørensen (mathias.grund) wrote :

> I just had a quick look i think it looks good, however to avoid code
> redundancy shouldn't the lookup function (line 308) be used in all the
> addToPassed functions?

Yes, this will improve code quality, I have done that now.

> And do we really need this many addToPassed functions
> (don't they all do the same)?

Yes, the workflow algorithm handles metadata manually in the algorithm so the metadata should not be set in the AddToPassed method (this will cause problems as is) - this is the only difference.

I have now implemented all your comments (Jakob and Peter), so please, reconsider your review.

Revision history for this message
Jakob Taankvist (jakob-taankvist) :
review: Approve
Revision history for this message
Peter Gjøl Jensen (peter-gjoel) wrote :

I think that the inheritance of Reachabilitysearch in Workflow is a bit unfortunate. It seems that the only methods really used from this inheritance is "getTrace" and "isDelayPossible", the rest are overwritten. Also, why is the pwList defined as a PWList instead of WorkflowPWList? And is there any reason for the new methods in PWList (they are all unused)?

I suggest to let Workflow inherit from Verification instead, define getTrace and isDelayPossible here, move pwList here also, but change the type to WorkflowPWList. This will allow you to remove the new methods from PWList and maintain a more concise inheritance model.

review: Needs Information
333. By Mathias Grund Sørensen

Changed workflow soundness PWList* to WorkflowPWList*

334. By Mathias Grund Sørensen

Removed workflow.cpp as it contained no implementations.

335. By Mathias Grund Sørensen

Removed unneeded methods for PWListBase.

336. By Mathias Grund Sørensen

Refactored to remove Workflow supertype.

Revision history for this message
Mathias Grund Sørensen (mathias.grund) wrote :

> I think that the inheritance of Reachabilitysearch in Workflow is a bit
> unfortunate. It seems that the only methods really used from this inheritance
> is "getTrace" and "isDelayPossible", the rest are overwritten.

Yes, I agree the current inheritance hierarchy is not ideal. I have simplified it a little by removing the intermediate workflow class, but I think that to make the hierarchy nice, a larger refactoring has to be done, which I suggest is done in a new branch after merging.

I strongly suggest creating a DiscreteVerification class which contains shared methods + variables for all discrete methods (basically what TimeDartVerification does for semi-symbolic algorithms) and then workflow classes can just inherit from this.

Unless you strongly feel that this branch is too messy w.r.t. inheritance hierarchy, I think we should save it for a new branch as it will touch a lot of code.

> Also, why is
> the pwList defined as a PWList instead of WorkflowPWList? And is there any
> reason for the new methods in PWList (they are all unused)?

This has now been changed. Lookup still has to be global, as it is used in strong soundness search, which uses regular PWLists

> I suggest to let Workflow inherit from Verification instead, define getTrace
> and isDelayPossible here, move pwList here also, but change the type to
> WorkflowPWList. This will allow you to remove the new methods from PWList and
> maintain a more concise inheritance model.

I have made some changes to the inheritance model (not exactly those you suggest). Please consider my comment above and let me know if you still think the model should be improved before merging.

337. By Mathias Grund Sørensen

Removed code in comments.

Revision history for this message
Peter Gjøl Jensen (peter-gjoel) wrote :

> This has now been changed. Lookup still has to be global, as it is used in strong soundness search, which uses regular PWLists

No you don't. I just removed it and put it in the workflow-pw-list, it compiles just fine. (also if you search the diff, there is no "new PWList..-" anywhere)

I poked a bit around in the code and ended up doing something like this:
lp:~peter-gjoel/verifydtapn/workflowForTrunk

> Unless you strongly feel that this branch is too messy w.r.t. inheritance hierarchy, I think we should save it for a new branch as it will touch a lot of code.

Agreed. I will approve it for now, and then we can sort out the rest in the new branch.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Core/ArgsParser.cpp'
2--- src/Core/ArgsParser.cpp 2013-05-08 11:22:45 +0000
3+++ src/Core/ArgsParser.cpp 2013-10-27 17:10:01 +0000
4@@ -17,6 +17,7 @@
5 static const std::string XML_TRACE_OPTION = "xml-trace";
6 static const std::string LEGACY = "legacy";
7 static const std::string KEEP_DEAD = "keep-dead-tokens";
8+static const std::string WORKFLOW = "workflow";
9
10 std::ostream& operator<<(std::ostream& out, const Switch& flag) {
11 flag.print(out);
12@@ -162,6 +163,12 @@
13 parsers.push_back(
14 boost::make_shared<Switch > ("x", XML_TRACE_OPTION,
15 "Output trace in xml format for TAPAAL."));
16+
17+ parsers.push_back(
18+ boost::make_shared<SwitchWithArg > ("w", WORKFLOW,
19+ "Workflow mode.\n - 0: Disabled\n - 1: Soundness (and min)\n - 2: Strong Soundness (and max)",
20+ 0));
21+
22 };
23
24 void ArgsParser::printHelp() const {
25@@ -309,6 +316,20 @@
26 }
27
28
29+VerificationOptions::WorkflowMode intToWorkflowTypeEnum(int i) {
30+ switch (i) {
31+ case 0:
32+ return VerificationOptions::NOT_WORKFLOW;
33+ case 1:
34+ return VerificationOptions::WORKFLOW_SOUNDNESS;
35+ case 2:
36+ return VerificationOptions::WORKFLOW_STRONG_SOUNDNESS;
37+ default:
38+ std::cout << "Unknown workflow option specified." << std::endl;
39+ exit(1);
40+ }
41+}
42+
43 VerificationOptions::Trace intToEnum(int i) {
44 switch (i) {
45 case 0:
46@@ -370,8 +391,14 @@
47 assert(map.find(XML_TRACE_OPTION) != map.end());
48 bool xml_trace = boost::lexical_cast<bool>(
49 map.find(XML_TRACE_OPTION)->second);
50+
51+ assert(map.find(WORKFLOW) != map.end());
52+ VerificationOptions::WorkflowMode workflow = intToWorkflowTypeEnum(
53+ tryParseInt(*map.find(WORKFLOW)));
54+
55+
56
57 return VerificationOptions(modelFile, queryFile, search, verification, memoptimization, kbound, trace,
58- xml_trace, max_constant, keep_dead);
59+ xml_trace, max_constant, keep_dead, workflow);
60 }
61 }
62
63=== modified file 'src/Core/ArgsParser.hpp'
64--- src/Core/ArgsParser.hpp 2013-08-13 20:59:28 +0000
65+++ src/Core/ArgsParser.hpp 2013-10-27 17:10:01 +0000
66@@ -80,7 +80,7 @@
67 class ArgsParser {
68 typedef std::vector< boost::shared_ptr<Switch> > parser_vec;
69 public:
70- ArgsParser() : parsers(), version(2,1,0) { initialize(); };
71+ ArgsParser() : parsers(), version(2,2,0) { initialize(); };
72 virtual ~ArgsParser() {};
73
74 VerificationOptions parse(int argc, char* argv[]) const;
75
76=== modified file 'src/Core/QueryParser/AST.hpp'
77--- src/Core/QueryParser/AST.hpp 2013-08-09 21:47:22 +0000
78+++ src/Core/QueryParser/AST.hpp 2013-10-27 17:10:01 +0000
79@@ -218,6 +218,7 @@
80
81 Quantifier getQuantifier() const { return quantifier; }
82 const Expression& getChild() const { return *expr; }
83+ void setQuantifier(Quantifier q){ quantifier = q; }
84 private:
85 Quantifier quantifier;
86 Expression* expr;
87
88=== modified file 'src/Core/TAPN/TimedPlace.hpp'
89--- src/Core/TAPN/TimedPlace.hpp 2013-07-25 21:04:53 +0000
90+++ src/Core/TAPN/TimedPlace.hpp 2013-10-27 17:10:01 +0000
91@@ -62,6 +62,7 @@
92 inline const TransportArc::Vector& getTransportArcs() const { return transportArcs; }
93 inline const InhibitorArc::Vector& getInhibitorArcs() const { return inhibitorArcs; }
94 inline const TimedInputArc::Vector& getInputArcs() const { return inputArcs; }
95+ inline const OutputArc::Vector& getOutputArcs() const { return outputArcs; }
96
97 private: // data
98 PlaceType type;
99
100=== modified file 'src/Core/VerificationOptions.hpp'
101--- src/Core/VerificationOptions.hpp 2013-05-08 11:12:08 +0000
102+++ src/Core/VerificationOptions.hpp 2013-10-27 17:10:01 +0000
103@@ -26,6 +26,10 @@
104 NO_MEMORY_OPTIMIZATION, PTRIE
105 };
106
107+ enum WorkflowMode{
108+ NOT_WORKFLOW, WORKFLOW_SOUNDNESS, WORKFLOW_STRONG_SOUNDNESS
109+ };
110+
111 VerificationOptions() {
112 }
113
114@@ -39,8 +43,8 @@
115 Trace trace,
116 bool xml_trace,
117 bool useGlobalMaxConstants,
118- bool keepDeadTokens
119- ) : inputFile(inputFile),
120+ bool keepDeadTokens,
121+ WorkflowMode workflow) : inputFile(inputFile),
122 queryFile(queryFile),
123 searchType(searchType),
124 verificationType(verificationType),
125@@ -49,7 +53,8 @@
126 trace(trace),
127 xml_trace(xml_trace),
128 useGlobalMaxConstants(useGlobalMaxConstants),
129- keepDeadTokens(keepDeadTokens) {
130+ keepDeadTokens(keepDeadTokens),
131+ workflow(workflow){
132
133 };
134
135@@ -94,6 +99,15 @@
136 inline const bool getKeepDeadTokens() const {
137 return keepDeadTokens;
138 };
139+
140+ inline const WorkflowMode getWorkflowMode() const {
141+ return workflow;
142+ };
143+
144+ inline bool isWorkflow() const{
145+ return workflow != NOT_WORKFLOW;
146+ }
147+
148 private:
149 std::string inputFile;
150 std::string queryFile;
151@@ -105,6 +119,7 @@
152 bool xml_trace;
153 bool useGlobalMaxConstants;
154 bool keepDeadTokens;
155+ WorkflowMode workflow;
156 };
157
158 std::ostream& operator<<(std::ostream& out, const VerificationOptions& options);
159
160=== modified file 'src/DiscreteVerification/DataStructures/NonStrictMarking.hpp'
161--- src/DiscreteVerification/DataStructures/NonStrictMarking.hpp 2013-08-01 21:55:57 +0000
162+++ src/DiscreteVerification/DataStructures/NonStrictMarking.hpp 2013-10-27 17:10:01 +0000
163@@ -18,6 +18,8 @@
164
165 namespace VerifyTAPN {
166 namespace DiscreteVerification {
167+
168+ class NonStrictMarking;
169
170 struct MetaData {
171 public:
172@@ -30,6 +32,20 @@
173 const TAPN::TimedTransition* generatedBy;
174 };
175
176+ struct WorkflowSoundnessMetaData : public MetaData {
177+ public:
178+ WorkflowSoundnessMetaData() : parents(new vector<NonStrictMarking*>), min(INT_MAX) {};
179+ vector<NonStrictMarking*>* parents;
180+ int min;
181+ };
182+
183+ struct WorkflowStrongSoundnessMetaData : public MetaData {
184+ public:
185+ WorkflowStrongSoundnessMetaData() : parents(new vector<NonStrictMarking*>) {};
186+ vector<NonStrictMarking*>* parents;
187+ };
188+
189+
190 // ugly forward declaration
191 template<class MetaData>
192 struct EncodingPointer;
193@@ -42,17 +58,16 @@
194 class NonStrictMarking : public NonStrictMarkingBase{
195 public:
196 NonStrictMarking():NonStrictMarkingBase(), meta(new MetaData()){}
197- NonStrictMarking(const TAPN::TimedArcPetriNet& tapn, const std::vector<int>& v):NonStrictMarkingBase(tapn, v){}
198- NonStrictMarking(const NonStrictMarkingBase& nsm):NonStrictMarkingBase(nsm){
199+ NonStrictMarking(const TAPN::TimedArcPetriNet& tapn, const std::vector<int>& v): NonStrictMarkingBase(tapn, v), meta(NULL){}
200+ NonStrictMarking(const NonStrictMarkingBase& nsm):NonStrictMarkingBase(nsm), meta(NULL){
201
202 }
203- NonStrictMarking(const NonStrictMarking& nsm):NonStrictMarkingBase(nsm){
204+ NonStrictMarking(const NonStrictMarking& nsm):NonStrictMarkingBase(nsm), meta(NULL){
205
206 }
207 public:
208 MetaData* meta;
209 };
210-
211
212 } /* namespace DiscreteVerification */
213 } /* namespace VerifyTAPN */
214
215=== modified file 'src/DiscreteVerification/DataStructures/NonStrictMarkingBase.cpp'
216--- src/DiscreteVerification/DataStructures/NonStrictMarkingBase.cpp 2013-07-26 21:59:47 +0000
217+++ src/DiscreteVerification/DataStructures/NonStrictMarkingBase.cpp 2013-10-27 17:10:01 +0000
218@@ -216,14 +216,12 @@
219 }
220
221 std::ostream& operator<<(std::ostream& out, NonStrictMarkingBase& x) {
222- out << "-";
223 for (PlaceList::iterator iter = x.places.begin(); iter != x.places.end(); iter++) {
224- out << "place " << iter->place->getId() << " has tokens (age, count): ";
225 for (TokenList::iterator it = iter->tokens.begin(); it != iter->tokens.end(); it++) {
226- out << "(" << it->getAge() << ", " << it->getCount() << ") ";
227+ out << "(" << iter->place->getName() << ", "<< it->getAge() << ", " << it->getCount() << ")";
228 }
229 if (iter != x.places.end() - 1) {
230- out << endl;
231+ out << ", ";
232 }
233 }
234
235
236=== modified file 'src/DiscreteVerification/DataStructures/PWList.cpp'
237--- src/DiscreteVerification/DataStructures/PWList.cpp 2013-08-26 14:17:55 +0000
238+++ src/DiscreteVerification/DataStructures/PWList.cpp 2013-10-27 17:10:01 +0000
239@@ -30,11 +30,24 @@
240 }
241 stored++;
242 m.push_back(marking);
243- marking->meta = new MetaData();
244+ marking->meta = new MetaData();
245 waiting_list->add(marking, marking);
246 return true;
247 }
248
249+NonStrictMarking* PWList::addToPassed(NonStrictMarking* marking){
250+ NonStrictMarking* existing = lookup(marking);
251+ if(existing != NULL){
252+ return existing;
253+ }else{
254+ NonStrictMarkingList& m = markings_storage[marking->getHashKey()];
255+ stored++;
256+ m.push_back(marking);
257+ marking->meta = new MetaData();
258+ return marking;
259+ }
260+ }
261+
262 NonStrictMarking* PWList::getNextUnexplored(){
263 return waiting_list->pop();
264 }
265
266=== modified file 'src/DiscreteVerification/DataStructures/PWList.hpp'
267--- src/DiscreteVerification/DataStructures/PWList.hpp 2013-08-10 20:30:06 +0000
268+++ src/DiscreteVerification/DataStructures/PWList.hpp 2013-10-27 17:10:01 +0000
269@@ -17,7 +17,7 @@
270
271 namespace VerifyTAPN {
272 namespace DiscreteVerification {
273-
274+
275 class PWListBase {
276 public:
277 PWListBase() : stored(0), discoveredMarkings(0), maxNumTokensInAnyMarking(-1), isLiveness(false) {};
278@@ -26,16 +26,17 @@
279 int discoveredMarkings;
280 int maxNumTokensInAnyMarking;
281 bool isLiveness;
282-
283+
284 virtual bool hasWaitingStates() = 0;
285 virtual long long size() const = 0;
286 virtual bool add(NonStrictMarking* marking) = 0;
287- virtual NonStrictMarking* getNextUnexplored() = 0;
288+ virtual NonStrictMarking* lookup(NonStrictMarking* marking){ return NULL; }
289+ virtual NonStrictMarking* getNextUnexplored() = 0;
290 virtual long long explored()= 0;
291 virtual ~PWListBase(){};
292- inline void setMaxNumTokensIfGreater(int i){ if(i>maxNumTokensInAnyMarking) maxNumTokensInAnyMarking = i; };
293+ inline void setMaxNumTokensIfGreater(int i){ if(i>maxNumTokensInAnyMarking) maxNumTokensInAnyMarking = i; };
294 };
295-
296+
297 class PWList : public PWListBase {
298 public:
299 typedef std::vector<NonStrictMarking*> NonStrictMarkingList;
300@@ -51,14 +52,32 @@
301 return (waiting_list->size() > 0);
302 };
303
304+ virtual NonStrictMarking* lookup(NonStrictMarking* marking){
305+ NonStrictMarkingList& m = markings_storage[marking->getHashKey()];
306+ for(NonStrictMarkingList::const_iterator iter = m.begin();
307+ iter != m.end();
308+ iter++){
309+ if((*iter)->equals(*marking)){
310+ return *iter;
311+ }
312+ }
313+ return NULL;
314+ }
315+
316+ virtual bool addToWaiting(NonStrictMarking* marking){
317+ waiting_list->add(marking, marking);
318+ return true;
319+ }
320+
321 virtual long long size() const {
322 return stored;
323 };
324
325 virtual long long explored() {return waiting_list->size();};
326-
327+
328 public: // modifiers
329 virtual bool add(NonStrictMarking* marking);
330+ virtual NonStrictMarking* addToPassed(NonStrictMarking* marking);
331 virtual NonStrictMarking* getNextUnexplored();
332
333 public:
334
335=== modified file 'src/DiscreteVerification/DataStructures/WaitingList.hpp'
336--- src/DiscreteVerification/DataStructures/WaitingList.hpp 2013-08-26 14:17:55 +0000
337+++ src/DiscreteVerification/DataStructures/WaitingList.hpp 2013-10-27 17:10:01 +0000
338@@ -127,6 +127,24 @@
339 };
340
341 template <class T>
342+class WorkflowMinFirstWaitingList : public WaitingList<T>{
343+public:
344+ typedef std::priority_queue<WeightedItem<T>, std::vector<WeightedItem<T> >, less<T> > priority_queue;
345+public:
346+ WorkflowMinFirstWaitingList(AST::Query* q) : queue(), query(q) { };
347+ virtual ~WorkflowMinFirstWaitingList();
348+public:
349+ virtual void add(NonStrictMarkingBase* weight, T* payload);
350+ virtual T* peek();
351+ virtual T* pop();
352+ virtual size_t size() { return queue.size(); };
353+private:
354+ int calculateWeight(NonStrictMarking* payload);
355+ priority_queue queue;
356+ AST::Query* query;
357+};
358+
359+template <class T>
360 class RandomStackWaitingList : public StackWaitingList<T>{
361 public:
362 typedef std::priority_queue<WeightedItem<T>, std::vector<WeightedItem<T> >, less<T> > priority_queue;
363@@ -336,6 +354,54 @@
364 }
365
366 template <class T>
367+void WorkflowMinFirstWaitingList<T>::add(NonStrictMarkingBase* weight, T* payload)
368+{
369+ assert(false);
370+ WeightedItem<T> weighted_item;
371+ weighted_item.item = payload;
372+ weighted_item.weight = 0;
373+ queue.push(weighted_item);
374+}
375+
376+template <>
377+inline void WorkflowMinFirstWaitingList<NonStrictMarking>::add(NonStrictMarkingBase* weight, NonStrictMarking* payload)
378+{
379+ WeightedItem<NonStrictMarking> weighted_item;
380+ weighted_item.item = payload;
381+ weighted_item.weight = calculateWeight(payload);
382+ queue.push(weighted_item);
383+}
384+
385+template <class T>
386+T* WorkflowMinFirstWaitingList<T>::pop()
387+{
388+ WeightedItem<T> weighted_item = queue.top();
389+ T* marking = weighted_item.item;
390+ queue.pop();
391+ return marking;
392+}
393+
394+template <class T>
395+T* WorkflowMinFirstWaitingList<T>::peek()
396+{
397+ WeightedItem<T> weighted_item = queue.top();
398+ T* marking = weighted_item.item;
399+ return marking;
400+}
401+
402+template <class T>
403+int WorkflowMinFirstWaitingList<T>::calculateWeight(NonStrictMarking* payload)
404+{
405+ return ((WorkflowSoundnessMetaData*)payload->meta)->min;
406+}
407+
408+template <class T>
409+WorkflowMinFirstWaitingList<T>::~WorkflowMinFirstWaitingList()
410+{
411+}
412+
413+
414+template <class T>
415 void RandomWaitingList<T>::add(NonStrictMarkingBase* weight, T* payload)
416 {
417 WeightedItem<T> weighted_item;
418
419=== added file 'src/DiscreteVerification/DataStructures/WorkflowPWList.hpp'
420--- src/DiscreteVerification/DataStructures/WorkflowPWList.hpp 1970-01-01 00:00:00 +0000
421+++ src/DiscreteVerification/DataStructures/WorkflowPWList.hpp 2013-10-27 17:10:01 +0000
422@@ -0,0 +1,150 @@
423+/*
424+ * PWList.hpp
425+ *
426+ * Created on: 01/03/2012
427+ * Author: MathiasGS
428+ */
429+
430+#ifndef WORKFLOWPWLIST_HPP_
431+#define WORKFLOWPWLIST_HPP_
432+
433+#include "WaitingList.hpp"
434+#include <iostream>
435+#include "google/sparse_hash_map"
436+#include "NonStrictMarking.hpp"
437+#include "NonStrictMarking.hpp"
438+#include "WaitingList.hpp"
439+#include "PWList.hpp"
440+
441+namespace VerifyTAPN {
442+namespace DiscreteVerification {
443+
444+ class WorkflowPWList : public PWList {
445+ public:
446+ NonStrictMarking* getCoveredMarking(NonStrictMarking* marking, bool useLinearSweep){
447+ if(useLinearSweep){
448+ for(HashMap::const_iterator iter = markings_storage.begin(); iter != markings_storage.end(); ++iter){
449+ for(NonStrictMarkingList::const_iterator m_iter = iter->second.begin(); m_iter != iter->second.end(); m_iter++){
450+ if((*m_iter)->size() >= marking->size()){
451+ continue;
452+ }
453+
454+ // Test if m_iter is covered by marking
455+ PlaceList::const_iterator marking_place_iter = marking->getPlaceList().begin();
456+
457+ bool tokensCovered = true;
458+ for(PlaceList::const_iterator m_place_iter = (*m_iter)->getPlaceList().begin(); m_place_iter != (*m_iter)->getPlaceList().end(); ++m_place_iter){
459+ while(marking_place_iter != marking->getPlaceList().end() && marking_place_iter->place != m_place_iter->place){
460+ ++marking_place_iter;
461+ }
462+
463+ if(marking_place_iter == marking->getPlaceList().end()){
464+ tokensCovered = false;
465+ break; // Place not covered in marking
466+ }
467+
468+ TokenList::const_iterator marking_token_iter = marking_place_iter->tokens.begin();
469+ for(TokenList::const_iterator m_token_iter = m_place_iter->tokens.begin(); m_token_iter != m_place_iter->tokens.end(); ++m_token_iter){
470+ while(marking_token_iter != marking_place_iter->tokens.end() && marking_token_iter->getAge() != m_token_iter->getAge()){
471+ ++marking_token_iter;
472+ }
473+
474+ if(marking_token_iter == marking_place_iter->tokens.end() || marking_token_iter->getCount() < m_token_iter->getCount()){
475+ tokensCovered = false;
476+ break;
477+ }
478+ }
479+
480+ if(!tokensCovered) break;
481+ }
482+
483+ if(tokensCovered){
484+ return *m_iter;
485+ }
486+ }
487+ }
488+ }else{
489+ vector<NonStrictMarking*> coveredMarkings;
490+ coveredMarkings.push_back(new NonStrictMarking(*marking));
491+ for(PlaceList::const_iterator p_iter = marking->getPlaceList().begin(); p_iter != marking->getPlaceList().end(); ++p_iter){
492+ for(TokenList::const_iterator t_iter = p_iter->tokens.begin(); t_iter != p_iter->tokens.end(); ++t_iter){
493+ for(int i = 1; i <= t_iter->getCount(); ++i){
494+ vector<NonStrictMarking*> toAdd;
495+ for(vector<NonStrictMarking*>::iterator iter = coveredMarkings.begin(); iter != coveredMarkings.end(); ++iter){
496+ NonStrictMarking* new_marking = new NonStrictMarking(**iter);
497+ for(int ii = i; ii > 0; --ii){
498+ new_marking->removeToken(p_iter->place->getIndex(), t_iter->getAge());
499+ }
500+ toAdd.push_back(new_marking);
501+ }
502+ for(vector<NonStrictMarking*>::iterator iter = toAdd.begin(); iter != toAdd.end(); ++iter){
503+ coveredMarkings.push_back(*iter);
504+ }
505+ }
506+ }
507+ }
508+
509+ bool isFirst = true;
510+ for(vector<NonStrictMarking*>::iterator iter = coveredMarkings.begin(); iter != coveredMarkings.end(); ++iter){
511+ if(isFirst){
512+ isFirst = false;
513+ continue;
514+ }
515+ NonStrictMarking* covered = lookup(*iter);
516+ if(covered != NULL){
517+ return covered;
518+ }
519+ delete *iter;
520+ }
521+ }
522+ return NULL;
523+ }
524+
525+ NonStrictMarking* getUnpassed(){
526+ for(HashMap::iterator hmiter = markings_storage.begin(); hmiter != markings_storage.end(); hmiter++){
527+ for(NonStrictMarkingList::const_iterator iter = hmiter->second.begin();
528+ iter != hmiter->second.end();
529+ iter++){
530+ if(!(*iter)->meta->passed){
531+ return *iter;
532+ }
533+ }
534+ }
535+ return NULL;
536+ }
537+
538+
539+ WorkflowPWList(WaitingList<NonStrictMarking>* w_l) : PWList(w_l, false) {};
540+ bool add(NonStrictMarking* marking){
541+ discoveredMarkings++;
542+ NonStrictMarkingList& m = markings_storage[marking->getHashKey()];
543+ for(NonStrictMarkingList::const_iterator iter = m.begin();
544+ iter != m.end();
545+ iter++){
546+ if((*iter)->equals(*marking)){
547+ return false;
548+ }
549+ }
550+ stored++;
551+ m.push_back(marking);
552+ waiting_list->add(marking, marking);
553+ return true;
554+ }
555+
556+ NonStrictMarking* addToPassed(NonStrictMarking* marking){
557+ NonStrictMarking* existing = lookup(marking);
558+ if(existing != NULL){
559+ return existing;
560+ }else{
561+ NonStrictMarkingList& m = markings_storage[marking->getHashKey()];
562+ stored++;
563+ m.push_back(marking);
564+ return marking;
565+ }
566+ }
567+
568+ };
569+
570+} /* namespace DiscreteVerification */
571+} /* namespace VerifyTAPN */
572+#endif /* PWLIST_HPP_ */
573
574=== modified file 'src/DiscreteVerification/DiscreteVerification.cpp'
575--- src/DiscreteVerification/DiscreteVerification.cpp 2013-08-10 20:30:06 +0000
576+++ src/DiscreteVerification/DiscreteVerification.cpp 2013-10-27 17:10:01 +0000
577@@ -47,7 +47,49 @@
578 std::cout << options << std::endl;
579
580 // Select verification method
581- if (options.getVerificationType() == VerificationOptions::DISCRETE) {
582+ if(options.getWorkflowMode() != VerificationOptions::NOT_WORKFLOW){
583+ if (options.getVerificationType() == VerificationOptions::TIMEDART) {
584+ cout << "Workflow analysis currently only supports discrete exploration (i.e. not TimeDarts)." << endl;
585+ exit(1);
586+ }
587+
588+ if (options.getMemoryOptimization() != VerificationOptions::NO_MEMORY_OPTIMIZATION) {
589+ cout << "Workflow analysis currently does not support any memory optimizations (i.e. no PTries)." << endl;
590+ exit(1);
591+ }
592+ WaitingList<NonStrictMarking>* strategy = getWaitingList<NonStrictMarking > (query, options);
593+ if(options.getWorkflowMode() == VerificationOptions::WORKFLOW_SOUNDNESS){
594+ WorkflowSoundness* verifier = new WorkflowSoundness(tapn, *initialMarking, query, options, strategy);
595+
596+ if(verifier->getModelType() == verifier->NOTTAWFN){
597+ std::cerr << "Model is not a TAWFN!" << std::endl;
598+ return -1;
599+ }else if(verifier->getModelType() == verifier->ETAWFN){
600+ std::cout << "Model is a ETAWFN" << std::endl << std::endl;
601+ }else if(verifier->getModelType() == verifier->MTAWFN){
602+ std::cout << "Model is a MTAWFN" << std::endl << std::endl;
603+ }
604+ VerifyAndPrint(
605+ *verifier,
606+ options,
607+ query);
608+ verifier->printExecutionTime(cout);
609+ verifier->printMessages(cout);
610+ }
611+ else{
612+ // Assumes correct structure of net!
613+ WorkflowStrongSoundnessReachability* verifier = new WorkflowStrongSoundnessReachability(tapn, *initialMarking, query, options, strategy);
614+ VerifyAndPrint(
615+ *verifier,
616+ options,
617+ query);
618+ verifier->printExecutionTime(cout);
619+ }
620+
621+ delete strategy;
622+
623+ }
624+ else if (options.getVerificationType() == VerificationOptions::DISCRETE) {
625
626 if (options.getMemoryOptimization() == VerificationOptions::PTRIE) {
627 //TODO fix initialization
628@@ -137,7 +179,7 @@
629 }
630
631 template<typename T> void VerifyAndPrint(Verification<T>& verifier, VerificationOptions& options, AST::Query* query) {
632- bool result = (query->getQuantifier() == AG || query->getQuantifier() == AF) ? !verifier.verify() : verifier.verify();
633+ bool result = (!options.isWorkflow() && (query->getQuantifier() == AG || query->getQuantifier() == AF)) ? !verifier.verify() : verifier.verify();
634
635 verifier.printStats();
636 verifier.printTransitionStatistics();
637@@ -150,7 +192,7 @@
638 std::cout << verifier.maxUsedTokens() << std::endl;
639
640 if (options.getTrace() == VerificationOptions::SOME_TRACE) {
641- if ((query->getQuantifier() == EF && result) || (query->getQuantifier() == AG && !result) || (query->getQuantifier() == EG && result) || (query->getQuantifier() == AF && !result)) {
642+ if ((query->getQuantifier() == EF && result) || (query->getQuantifier() == AG && !result) || (query->getQuantifier() == EG && result) || (query->getQuantifier() == AF && !result) || (options.isWorkflow())) {
643 verifier.getTrace();
644 } else {
645 std::cout << "A trace could not be generated due to the query result" << std::endl;
646
647=== modified file 'src/DiscreteVerification/DiscreteVerification.hpp'
648--- src/DiscreteVerification/DiscreteVerification.hpp 2013-07-26 21:59:47 +0000
649+++ src/DiscreteVerification/DiscreteVerification.hpp 2013-10-27 17:10:01 +0000
650@@ -23,6 +23,8 @@
651 #include "VerificationTypes/ReachabilitySearch.hpp"
652 #include "VerificationTypes/TimeDartReachabilitySearch.hpp"
653 #include "VerificationTypes/TimeDartLiveness.hpp"
654+#include "VerificationTypes/WorkflowSoundness.hpp"
655+#include "VerificationTypes/WorkflowStrongSoundness.hpp"
656 #include "SearchStrategies/SearchFactory.h"
657 #include "DataStructures/PTrie.h"
658
659
660=== modified file 'src/DiscreteVerification/SearchStrategies/SearchFactory.h'
661--- src/DiscreteVerification/SearchStrategies/SearchFactory.h 2013-05-08 11:43:09 +0000
662+++ src/DiscreteVerification/SearchStrategies/SearchFactory.h 2013-10-27 17:10:01 +0000
663@@ -17,7 +17,10 @@
664 template <class T>
665 WaitingList<T>* getWaitingList(AST::Query* query, VerificationOptions& options){
666 WaitingList<T>* strategy = NULL;
667- if(query->getQuantifier() == EG || query->getQuantifier() == AF){
668+ if(options.getWorkflowMode() == options.WORKFLOW_SOUNDNESS){
669+ WorkflowMinFirst<T> s;
670+ strategy = s.createWaitingList(query);
671+ } else if(query->getQuantifier() == EG || query->getQuantifier() == AF){
672 //Liveness query, force DFS
673 switch(options.getSearchType()){
674 case VerificationOptions::DEPTHFIRST: {
675
676=== modified file 'src/DiscreteVerification/SearchStrategies/SearchStrategies.hpp'
677--- src/DiscreteVerification/SearchStrategies/SearchStrategies.hpp 2012-09-20 14:02:19 +0000
678+++ src/DiscreteVerification/SearchStrategies/SearchStrategies.hpp 2013-10-27 17:10:01 +0000
679@@ -9,5 +9,6 @@
680 #include "NonStrictRandom.hpp"
681 #include "NonStrictDFSHeuristic.hpp"
682 #include "NonStrictDFSRandom.hpp"
683+#include "WorkflowMinFirst.hpp"
684
685 #endif /* TAPN_HPP_ */
686
687=== added file 'src/DiscreteVerification/SearchStrategies/WorkflowMinFirst.hpp'
688--- src/DiscreteVerification/SearchStrategies/WorkflowMinFirst.hpp 1970-01-01 00:00:00 +0000
689+++ src/DiscreteVerification/SearchStrategies/WorkflowMinFirst.hpp 2013-10-27 17:10:01 +0000
690@@ -0,0 +1,42 @@
691+/*
692+ * NonStrictDFS.hpp
693+ *
694+ * Created on: 05/03/2012
695+ * Author: MathiasGS
696+ */
697+
698+#ifndef SMALLESTDELAYFIRST_HPP_
699+#define SMALLESTDELAYFIRST_HPP_
700+
701+#include "../DataStructures/PWList.hpp"
702+#include "../../Core/TAPN/TAPN.hpp"
703+#include "../../Core/QueryParser/AST.hpp"
704+#include "../../Core/VerificationOptions.hpp"
705+
706+#include "../../Core/TAPN/TimedPlace.hpp"
707+#include "../../Core/TAPN/TimedTransition.hpp"
708+#include "../../Core/TAPN/TimedInputArc.hpp"
709+#include "../../Core/TAPN/TransportArc.hpp"
710+#include "../../Core/TAPN/InhibitorArc.hpp"
711+#include "../../Core/TAPN/OutputArc.hpp"
712+
713+#include "../SuccessorGenerator.hpp"
714+
715+#include "../QueryVisitor.hpp"
716+
717+#include <stack>
718+#include "SearchStrategy.hpp"
719+
720+namespace VerifyTAPN {
721+
722+namespace DiscreteVerification {
723+
724+template <class T>
725+class WorkflowMinFirst : public SearchStrategy<T> {
726+public:
727+ virtual WaitingList<T>* createWaitingList(AST::Query* query) const { return new WorkflowMinFirstWaitingList<T>(query); };
728+};
729+
730+}
731+}
732+#endif /* NONSTRICTDFS_HPP_ */
733
734=== added file 'src/DiscreteVerification/VerificationTypes/WorkflowSoundness.cpp'
735--- src/DiscreteVerification/VerificationTypes/WorkflowSoundness.cpp 1970-01-01 00:00:00 +0000
736+++ src/DiscreteVerification/VerificationTypes/WorkflowSoundness.cpp 2013-10-27 17:10:01 +0000
737@@ -0,0 +1,206 @@
738+/*
739+ * NonStrictSearch.cpp
740+ *
741+ * Created on: 26/04/2012
742+ * Author: MathiasGS
743+ */
744+
745+#include "WorkflowSoundness.hpp"
746+
747+namespace VerifyTAPN {
748+namespace DiscreteVerification {
749+
750+WorkflowSoundness::WorkflowSoundness(TAPN::TimedArcPetriNet& tapn, NonStrictMarking& initialMarking, AST::Query* query, VerificationOptions options, WaitingList<NonStrictMarking>* waiting_list)
751+: ReachabilitySearch(tapn, initialMarking, query, options, waiting_list), pwList(new WorkflowPWList(waiting_list)), final_set(new vector<NonStrictMarking*>), min_exec(INT_MAX), linearSweepTreshold(3), coveredMarking(NULL), in(NULL), out(NULL), modelType(calculateModelType()){
752+ for(TimedPlace::Vector::const_iterator iter = tapn.getPlaces().begin(); iter != tapn.getPlaces().end(); iter++){
753+ if((*iter)->getType() == Dead){
754+ (*iter)->setType(Std);
755+ }
756+ }
757+}
758+
759+bool WorkflowSoundness::verify(){
760+ if(addToPW(&initialMarking, NULL)){
761+ return false;
762+ }
763+
764+ // Phase 1
765+ while(pwList->hasWaitingStates()){
766+ NonStrictMarking& next_marking = *pwList->getNextUnexplored();
767+ tmpParent = &next_marking;
768+ bool noDelay = false;
769+ Result res = successorGenerator.generateAndInsertSuccessors(next_marking);
770+ if(res == QUERY_SATISFIED){
771+ return false;
772+ } else if (res == URGENT_ENABLED) {
773+ noDelay = true;
774+ }
775+
776+ // Generate next markings
777+ if(!noDelay && isDelayPossible(next_marking)){
778+ NonStrictMarking* marking = new NonStrictMarking(next_marking);
779+ marking->incrementAge();
780+ marking->setGeneratedBy(NULL);
781+ if(addToPW(marking, &next_marking)){
782+ return false;
783+ }
784+ }
785+ }
786+
787+ // Phase 2
788+ for(vector<NonStrictMarking*>::iterator iter = final_set->begin(); iter != final_set->end(); iter++){
789+ pwList->addToWaiting(*iter);
790+ if(((WorkflowSoundnessMetaData*)(*iter)->meta)->min < min_exec){
791+ min_exec = ((WorkflowSoundnessMetaData*)(*iter)->meta)->min;
792+ lastMarking = (*iter);
793+ }
794+ }
795+
796+ while(pwList->hasWaitingStates()){
797+ NonStrictMarking* next_marking = pwList->getNextUnexplored();
798+ if(next_marking->meta->passed) continue;
799+ next_marking->meta->passed = true;
800+ for(vector<NonStrictMarking*>::iterator iter = ((WorkflowSoundnessMetaData*)next_marking->meta)->parents->begin(); iter != ((WorkflowSoundnessMetaData*)next_marking->meta)->parents->end(); iter++){
801+ pwList->addToWaiting(*iter);
802+ }
803+ }
804+
805+ NonStrictMarking* unpassed = pwList->getUnpassed();
806+ if(unpassed == NULL){
807+ return true;
808+ }else{
809+ lastMarking = unpassed;
810+ return false;
811+ }
812+}
813+
814+bool WorkflowSoundness::addToPW(NonStrictMarking* marking, NonStrictMarking* parent){
815+ marking->cut();
816+
817+ unsigned int size = marking->size();
818+
819+ // Check K-bound
820+ pwList->setMaxNumTokensIfGreater(size);
821+ if(modelType == ETAWFN && size > options.getKBound()) {
822+ lastMarking = marking;
823+ return true; // Terminate false
824+ }
825+
826+ // Map to existing marking if any
827+ NonStrictMarking* lookup = pwList->lookup(marking);
828+ if(lookup != NULL){
829+ delete marking;
830+ marking = lookup;
831+ }else{
832+ marking->meta = new WorkflowSoundnessMetaData();
833+ }
834+
835+ WorkflowSoundnessMetaData* marking_meta_data = ((WorkflowSoundnessMetaData*)marking->meta);
836+
837+ // add to parents_set
838+ if(parent != NULL){
839+ WorkflowSoundnessMetaData* parent_meta_data = ((WorkflowSoundnessMetaData*)parent->meta);
840+ marking_meta_data->parents->push_back(parent);
841+ if(marking->getGeneratedBy() == NULL){
842+ marking_meta_data->min = min(marking_meta_data->min, parent_meta_data->min+1); // Delay
843+ }else{
844+ marking_meta_data->min = min(marking_meta_data->min, parent_meta_data->min); // Transition
845+ }
846+ }else{
847+ marking_meta_data->min = 0;
848+ }
849+
850+
851+
852+ // Test if final place
853+ if(marking->numberOfTokensInPlace(out->getIndex()) > 0){
854+ if(size == 1){
855+ marking = pwList->addToPassed(marking);
856+ marking_meta_data = ((WorkflowSoundnessMetaData*)marking->meta);
857+ marking_meta_data->parents->push_back(parent);
858+ // Set min
859+ marking_meta_data->min = min(marking_meta_data->min, ((WorkflowSoundnessMetaData*)parent->meta)->min); // Transition
860+ final_set->push_back(marking);
861+ }else{
862+ lastMarking = marking;
863+ return true; // Terminate false
864+ }
865+ }else{
866+ // If new marking
867+ if(pwList->add(marking)){
868+ if(parent != NULL && marking->canDeadlock(tapn, 0)){
869+ lastMarking = marking;
870+ return true;
871+ }
872+ if(modelType == MTAWFN && checkForCoveredMarking(marking)){
873+ lastMarking = marking;
874+ return true; // Terminate false
875+ }
876+ }
877+ }
878+
879+ return false;
880+}
881+
882+bool WorkflowSoundness::checkForCoveredMarking(NonStrictMarking* marking){
883+ if(marking->size() <= options.getKBound()){
884+ return false; // Do not run check on small markings (invoke more rarely)
885+ }
886+
887+ NonStrictMarking* covered = pwList->getCoveredMarking(marking, (marking->size() > linearSweepTreshold));
888+ if(covered != NULL){
889+ coveredMarking = covered;
890+ return true;
891+ }
892+
893+ return false;
894+}
895+
896+void WorkflowSoundness::getTrace(NonStrictMarking* base){
897+ stack < NonStrictMarking*> printStack;
898+ NonStrictMarking* next = base;
899+ do{
900+ int min = INT_MAX;
901+ NonStrictMarking* parent = NULL;
902+ for(vector<NonStrictMarking*>::const_iterator iter = ((WorkflowSoundnessMetaData*)next->meta)->parents->begin(); iter != ((WorkflowSoundnessMetaData*)next->meta)->parents->end(); ++iter){
903+ if(((WorkflowSoundnessMetaData*)(*iter)->meta)->min < min){
904+ min = ((WorkflowSoundnessMetaData*)(*iter)->meta)->min;
905+ parent = *iter;
906+ }
907+ }
908+
909+ if(((WorkflowSoundnessMetaData*)next->meta)->inTrace){ break; }
910+ ((WorkflowSoundnessMetaData*)next->meta)->inTrace = true;
911+ printStack.push(next);
912+ next = parent;
913+
914+ }while(((WorkflowSoundnessMetaData*)next->meta)->parents != NULL && !((WorkflowSoundnessMetaData*)next->meta)->parents->empty());
915+
916+ if(printStack.top() != next){
917+ printStack.push(next);
918+ }
919+
920+ stack < NonStrictMarking*> tempStack;
921+ while(!printStack.empty()){
922+ printStack.top()->meta->inTrace = false;
923+ tempStack.push(printStack.top());
924+ printStack.pop();
925+ }
926+
927+ while(!tempStack.empty()){
928+ printStack.push(tempStack.top());
929+ tempStack.pop();
930+ }
931+
932+ if(options.getXmlTrace()){
933+ printXMLTrace(lastMarking, printStack, query, tapn);
934+ } else {
935+ printHumanTrace(lastMarking, printStack, query->getQuantifier());
936+ }
937+}
938+
939+WorkflowSoundness::~WorkflowSoundness() {
940+}
941+
942+} /* namespace DiscreteVerification */
943+} /* namespace VerifyTAPN */
944
945=== added file 'src/DiscreteVerification/VerificationTypes/WorkflowSoundness.hpp'
946--- src/DiscreteVerification/VerificationTypes/WorkflowSoundness.hpp 1970-01-01 00:00:00 +0000
947+++ src/DiscreteVerification/VerificationTypes/WorkflowSoundness.hpp 2013-10-27 17:10:01 +0000
948@@ -0,0 +1,180 @@
949+/*
950+ * NonStrictSearch.hpp
951+ *
952+ * Created on: 26/04/2012
953+ * Author: MathiasGS
954+ */
955+
956+#ifndef WORKFLOWSOUNDNESS_HPP_
957+#define WORKFLOWSOUNDNESS_HPP_
958+
959+#include "../DataStructures/WorkflowPWList.hpp"
960+#include "../../Core/TAPN/TAPN.hpp"
961+#include "../../Core/QueryParser/AST.hpp"
962+#include "../../Core/VerificationOptions.hpp"
963+#include "../../Core/TAPN/TimedPlace.hpp"
964+#include "../../Core/TAPN/TimedTransition.hpp"
965+#include "../../Core/TAPN/TimedInputArc.hpp"
966+#include "../../Core/TAPN/TransportArc.hpp"
967+#include "../../Core/TAPN/InhibitorArc.hpp"
968+#include "../../Core/TAPN/OutputArc.hpp"
969+#include "../SuccessorGenerator.hpp"
970+#include "../QueryVisitor.hpp"
971+#include "../DataStructures/NonStrictMarking.hpp"
972+#include <stack>
973+#include "ReachabilitySearch.hpp"
974+#include "../DataStructures/WaitingList.hpp"
975+
976+namespace VerifyTAPN {
977+namespace DiscreteVerification {
978+
979+class WorkflowSoundness : public ReachabilitySearch{
980+public:
981+ WorkflowSoundness(TAPN::TimedArcPetriNet& tapn, NonStrictMarking& initialMarking, AST::Query* query, VerificationOptions options, WaitingList<NonStrictMarking>* waiting_list);
982+ virtual ~WorkflowSoundness();
983+ bool verify();
984+ void printStats(){
985+ std::cout << " discovered markings:\t" << pwList->discoveredMarkings << std::endl;
986+ std::cout << " explored markings:\t" << pwList->size()-pwList->explored() << std::endl;
987+ std::cout << " stored markings:\t" << pwList->size() << std::endl;
988+ }
989+
990+ inline unsigned int maxUsedTokens(){ return pwList->maxNumTokensInAnyMarking; };
991+protected:
992+ virtual bool addToPW(NonStrictMarking* m){
993+ return addToPW(m, tmpParent);
994+ };
995+ bool addToPW(NonStrictMarking* marking, NonStrictMarking* parent);
996+ bool checkForCoveredMarking(NonStrictMarking* marking);
997+ void getTrace(NonStrictMarking* base);
998+public:
999+ virtual void getTrace(){
1000+ return getTrace(lastMarking);
1001+ }
1002+ void printExecutionTime(ostream& stream){
1003+ stream << "Minimum execution time: " << min_exec << endl;
1004+ }
1005+ void printMessages(ostream& stream){
1006+ if(coveredMarking != NULL){
1007+ stream << "Covered marking: " << *coveredMarking << endl;
1008+ getTrace(coveredMarking);
1009+ }
1010+ }
1011+
1012+ enum ModelType{
1013+ MTAWFN, ETAWFN, NOTTAWFN
1014+ };
1015+
1016+ inline const ModelType getModelType() const{ return modelType; }
1017+
1018+ ModelType calculateModelType(){
1019+ bool isin, isout;
1020+ bool hasInvariant = false;
1021+ for(TimedPlace::Vector::const_iterator iter = tapn.getPlaces().begin(); iter != tapn.getPlaces().end(); iter++){
1022+ isin = isout = true;
1023+ TimedPlace* p = (*iter);
1024+ if(p->getInputArcs().empty() && p->getOutputArcs().empty() && p->getTransportArcs().empty()){
1025+ bool continueOuter = true;
1026+ // Test if really orphan place or if out place
1027+ for(TransportArc::Vector::const_iterator trans_i = tapn.getTransportArcs().begin(); trans_i != tapn.getTransportArcs().end(); ++trans_i){
1028+ if(&((*trans_i)->getDestination()) == p){
1029+ continueOuter = false;
1030+ break;
1031+ }
1032+ }
1033+ if(continueOuter) continue; // Fix orphan places
1034+ }
1035+
1036+ if(!hasInvariant && p->getInvariant() != p->getInvariant().LS_INF){
1037+ hasInvariant = true;
1038+ }
1039+
1040+ if(p->getInputArcs().size() > 0){
1041+ isout = false;
1042+ }
1043+
1044+ if(p->getOutputArcs().size() > 0){
1045+ isin = false;
1046+ }
1047+
1048+ if(isout){
1049+ for(TransportArc::Vector::const_iterator iter = p->getTransportArcs().begin(); iter != p->getTransportArcs().end(); iter++){
1050+ if(&(*iter)->getSource() == p){
1051+ isout = false;
1052+ break;
1053+ }
1054+ }
1055+ }
1056+
1057+ if(isin){
1058+ for(TransportArc::Vector::const_iterator iter = tapn.getTransportArcs().begin(); iter != tapn.getTransportArcs().end(); ++iter){ // TODO maybe transportArcs should contain both incoming and outgoing? Might break something though.
1059+ if(&(*iter)->getDestination() == p){
1060+ isin = false;
1061+ break;
1062+ }
1063+ }
1064+ }
1065+
1066+ if(isin){
1067+ if(in == NULL){
1068+ in = p;
1069+ }else{
1070+ return NOTTAWFN;
1071+ }
1072+ }
1073+
1074+ if(isout){
1075+ if(out == NULL){
1076+ out = p;
1077+ }else{
1078+ return NOTTAWFN;
1079+ }
1080+ }
1081+
1082+ }
1083+
1084+ if(in == NULL || out == NULL || in == out){
1085+ return NOTTAWFN;
1086+ }
1087+
1088+ if(initialMarking.size() != 1 || initialMarking.numberOfTokensInPlace(in->getIndex()) != 1){
1089+ return NOTTAWFN;
1090+ }
1091+
1092+ bool hasUrgent = false;
1093+ bool hasInhibitor = false;
1094+ // All transitions must have preset
1095+ for(TimedTransition::Vector::const_iterator iter = tapn.getTransitions().begin(); iter != tapn.getTransitions().end(); iter++){
1096+ if((*iter)->getPresetSize() == 0 && (*iter)->getNumberOfTransportArcs() == 0){
1097+ return NOTTAWFN;
1098+ }
1099+
1100+ if(!hasUrgent && (*iter)->isUrgent()){
1101+ hasUrgent = true;
1102+ }
1103+
1104+ if(!hasInhibitor && !(*iter)->getInhibitorArcs().empty()){
1105+ hasInhibitor = true;
1106+ }
1107+ }
1108+
1109+ if(hasUrgent || hasInvariant || hasInhibitor){
1110+ return ETAWFN;
1111+ }
1112+
1113+ return MTAWFN;
1114+ }
1115+protected:
1116+ WorkflowPWList* pwList;
1117+ vector<NonStrictMarking*>* final_set;
1118+ int min_exec;
1119+ unsigned int linearSweepTreshold;
1120+ NonStrictMarking* coveredMarking;
1121+ TimedPlace* in;
1122+ TimedPlace* out;
1123+ ModelType modelType;
1124+};
1125+
1126+} /* namespace DiscreteVerification */
1127+} /* namespace VerifyTAPN */
1128+#endif /* NONSTRICTSEARCH_HPP_ */
1129
1130=== added file 'src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.cpp'
1131--- src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.cpp 1970-01-01 00:00:00 +0000
1132+++ src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.cpp 2013-10-27 17:10:01 +0000
1133@@ -0,0 +1,119 @@
1134+/*
1135+ * NonStrictSearch.cpp
1136+ *
1137+ * Created on: 26/04/2012
1138+ * Author: MathiasGS
1139+ */
1140+
1141+#include "WorkflowStrongSoundness.hpp"
1142+
1143+namespace VerifyTAPN {
1144+namespace DiscreteVerification {
1145+
1146+bool WorkflowStrongSoundnessReachability::verify(){
1147+ if(addToPW(&initialMarking, NULL)){
1148+ return true;
1149+ }
1150+
1151+ //Main loop
1152+ while(pwList->hasWaitingStates()){
1153+ NonStrictMarking& next_marking = *pwList->getNextUnexplored();
1154+ tmpParent = &next_marking;
1155+
1156+ bool noDelay = false;
1157+ Result res = successorGenerator.generateAndInsertSuccessors(next_marking);
1158+ if(res == QUERY_SATISFIED){
1159+ return true;
1160+ } else if (res == URGENT_ENABLED) {
1161+ noDelay = true;
1162+ }
1163+
1164+ // Generate next markings
1165+ if(!noDelay && isDelayPossible(next_marking)){
1166+ NonStrictMarking* marking = new NonStrictMarking(next_marking);
1167+ marking->incrementAge();
1168+ marking->setGeneratedBy(NULL);
1169+ if(addToPW(marking, &next_marking)){
1170+ return true;
1171+ }
1172+ }
1173+ }
1174+
1175+ return false;
1176+ }
1177+
1178+ void WorkflowStrongSoundnessReachability::getTrace(){
1179+ std::stack < NonStrictMarking*> printStack;
1180+ NonStrictMarking* next = lastMarking;
1181+ do{
1182+ NonStrictMarking* parent = ((WorkflowStrongSoundnessMetaData*) next->meta)->parents->at(0);
1183+ printStack.push(next);
1184+ next = parent;
1185+
1186+ }while(((WorkflowStrongSoundnessMetaData*)next->meta)->parents != NULL && !((WorkflowStrongSoundnessMetaData*)next->meta)->parents->empty());
1187+
1188+ if(printStack.top() != next){
1189+ printStack.push(next);
1190+ }
1191+
1192+ if(options.getXmlTrace()){
1193+ printXMLTrace(lastMarking, printStack, query, tapn);
1194+ } else {
1195+ printHumanTrace(lastMarking, printStack, query->getQuantifier());
1196+ }
1197+ }
1198+
1199+
1200+ bool WorkflowStrongSoundnessReachability::addToPW(NonStrictMarking* marking, NonStrictMarking* parent){
1201+ marking->cut();
1202+ marking->setParent(parent);
1203+
1204+ unsigned int size = marking->size();
1205+
1206+ pwList->setMaxNumTokensIfGreater(size);
1207+
1208+ if(size > options.getKBound()) {
1209+ delete marking;
1210+ return false;
1211+ }
1212+
1213+ /* Handle max */
1214+ // Map to existing marking if any
1215+ NonStrictMarking* lookup = pwList->lookup(marking);
1216+ if(lookup != NULL){
1217+ marking = lookup;
1218+ }else{
1219+ marking->meta = new WorkflowStrongSoundnessMetaData();
1220+ }
1221+
1222+ WorkflowStrongSoundnessMetaData* meta = (WorkflowStrongSoundnessMetaData*)marking->meta;
1223+
1224+ if(parent != NULL) meta->parents->push_back(parent);
1225+
1226+ if(!marking->getTokenList(timer->getIndex()).empty() &&
1227+ (marking->getTokenList(timer->getIndex()).at(0).getAge() > max_value ||
1228+ (marking->getTokenList(timer->getIndex()).at(0).getAge() == max_value &&
1229+ (!marking->getTokenList(term1->getIndex()).empty() || !marking->getTokenList(term2->getIndex()).empty())))){
1230+ max_value = marking->getTokenList(timer->getIndex()).at(0).getAge();
1231+ lastMarking = marking;
1232+ }
1233+
1234+ // Add to passed
1235+ if(pwList->add(marking)){
1236+ QueryVisitor<NonStrictMarking> checker(*marking, tapn);
1237+ BoolResult context;
1238+
1239+ query->accept(checker, context);
1240+ if(context.value) {
1241+ lastMarking = marking;
1242+ return true;
1243+ } else {
1244+ return false;
1245+ }
1246+ }
1247+
1248+ return false;
1249+ }
1250+
1251+} /* namespace DiscreteVerification */
1252+} /* namespace VerifyTAPN */
1253
1254=== added file 'src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.hpp'
1255--- src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.hpp 1970-01-01 00:00:00 +0000
1256+++ src/DiscreteVerification/VerificationTypes/WorkflowStrongSoundness.hpp 2013-10-27 17:10:01 +0000
1257@@ -0,0 +1,83 @@
1258+/*
1259+ * NonStrictSearch.hpp
1260+ *
1261+ * Created on: 26/04/2012
1262+ * Author: MathiasGS
1263+ */
1264+
1265+#ifndef WORKFLOWSTRONGSOUNDNESS_HPP_
1266+#define WORKFLOWSTRONGSOUNDNESS_HPP_
1267+
1268+#include "ReachabilitySearch.hpp"
1269+#include "../DataStructures/WorkflowPWList.hpp"
1270+#include <stack>
1271+
1272+namespace VerifyTAPN {
1273+namespace DiscreteVerification {
1274+
1275+class WorkflowStrongSoundnessReachability : public ReachabilitySearch{
1276+public:
1277+ WorkflowStrongSoundnessReachability(TAPN::TimedArcPetriNet& tapn, NonStrictMarking& initialMarking, AST::Query* query, VerificationOptions options, WaitingList<NonStrictMarking>* waiting_list)
1278+ : ReachabilitySearch(tapn,initialMarking, query, options, waiting_list), pwList(new WorkflowPWList(waiting_list)), max_value(-1), timer(NULL), term1(NULL), term2(NULL)
1279+ {
1280+ // Disable dead place optimization
1281+ for(TimedPlace::Vector::const_iterator iter = tapn.getPlaces().begin(); iter != tapn.getPlaces().end(); iter++){
1282+ if((*iter)->getType() == Dead){
1283+ (*iter)->setType(Std);
1284+ }
1285+ }
1286+
1287+ // Find timer place and store as out
1288+ for(TimedPlace::Vector::const_iterator iter = tapn.getPlaces().begin(); iter != tapn.getPlaces().end(); ++iter){
1289+ if((*iter)->getInvariant() != (*iter)->getInvariant().LS_INF){
1290+ if(timer == NULL || timer->getInvariant().getBound() < (*iter)->getInvariant().getBound()){
1291+ timer = *iter;
1292+ }
1293+ }
1294+
1295+ if(!(*iter)->getTransportArcs().empty() || !(*iter)->getInputArcs().empty()){
1296+ continue;
1297+ }
1298+
1299+ if(term1 == NULL){
1300+ term1 = *iter;
1301+ }else if(term2 == NULL){
1302+ term2 = *iter;
1303+ }else{
1304+ assert(false);
1305+ }
1306+ }
1307+ };
1308+
1309+ bool verify();
1310+ void getTrace();
1311+
1312+ void printExecutionTime(ostream& stream){
1313+ stream << "Maximum execution time: " << max_value << endl;
1314+ }
1315+
1316+ void printStats(){
1317+ std::cout << " discovered markings:\t" << pwList->discoveredMarkings << std::endl;
1318+ std::cout << " explored markings:\t" << pwList->size()-pwList->explored() << std::endl;
1319+ std::cout << " stored markings:\t" << pwList->size() << std::endl;
1320+ }
1321+
1322+ inline unsigned int maxUsedTokens(){ return pwList->maxNumTokensInAnyMarking; };
1323+
1324+protected:
1325+ virtual bool addToPW(NonStrictMarking* m){
1326+ return addToPW(m, tmpParent);
1327+ };
1328+
1329+ bool addToPW(NonStrictMarking* marking, NonStrictMarking* parent);
1330+protected:
1331+ PWListBase* pwList;
1332+ int max_value;
1333+ TimedPlace* timer;
1334+ TimedPlace* term1;
1335+ TimedPlace* term2;
1336+};
1337+
1338+} /* namespace DiscreteVerification */
1339+} /* namespace VerifyTAPN */
1340+#endif /* NONSTRICTSEARCH_HPP_ */
1341
1342=== modified file 'src/compile-mac-32-64.sh'
1343--- src/compile-mac-32-64.sh 2013-08-28 09:59:17 +0000
1344+++ src/compile-mac-32-64.sh 2013-10-27 17:10:01 +0000
1345@@ -7,9 +7,9 @@
1346
1347 export CPLUS_INCLUDE_PATH=$HOME/dev/boost_1_46_1
1348
1349-inc64="-I$HOME/dev/ia64/include"
1350+inc64="-I$HOME/dev/ia64/include -I/usr/local/include -I/opt/local/include"
1351
1352-inc32="-I$HOME/dev/ia32/include"
1353+inc32="-I$HOME/dev/ia32/include -I/usr/local/include -I/opt/local/include"
1354
1355 compatibility="-mmacosx-version-min=10.6"
1356

Subscribers

People subscribed via source and target branches