23
33
//Note: initial marking is in the markings set, therefore it will be deleted by the for loop
24
34
//TODO: Ensure we don't leak memory here, when code moving is done
28
bool OnTheFlyDG::fastEval(CTLQuery &query, size_t marking, Marking* unfolded)
30
assert(!query.IsTemporal);
31
if (query.GetQuantifier() == AND){
32
return fastEval(*query.GetFirstChild(), marking, unfolded) && fastEval(*query.GetSecondChild(), marking, unfolded);
33
} else if (query.GetQuantifier() == OR){
34
return fastEval(*query.GetFirstChild(), marking, unfolded) || fastEval(*query.GetSecondChild(), marking, unfolded);
35
} else if (query.GetQuantifier() == NEG){
36
bool result = fastEval(*query.GetFirstChild(), marking, unfolded);
39
return evaluateQuery(query, marking, unfolded);
35
size_t s = conf_alloc->size();
36
for(size_t i = 0; i < s; ++i)
38
((PetriConfig*)&(*conf_alloc)[i])->~PetriConfig();
44
void OnTheFlyDG::successors(Configuration *c)
40
std::cout << "NEDGES " << edge_alloc->size() << std::endl;
45
Condition::Result OnTheFlyDG::initialEval()
47
initialConfiguration();
48
EvaluationContext e(query_marking.marking(), net);
49
return query->evaluate(e);
52
Condition::Result OnTheFlyDG::fastEval(Condition* query, Marking* unfolded)
54
EvaluationContext e(unfolded->marking(), net);
55
return query->evaluate(e);
59
std::vector<DependencyGraph::Edge*> OnTheFlyDG::successors(Configuration *c)
61
PetriEngine::PQL::DistanceContext context(net, query_marking.marking());
46
62
PetriConfig *v = static_cast<PetriConfig*>(c);
47
63
trie.unpack(v->marking, encoder.scratchpad().raw());
48
64
encoder.decode(query_marking.marking(), encoder.scratchpad().raw());
49
65
// v->printConfiguration();
51
CTLType query_type = v->query->GetQueryType();
66
std::vector<Edge*> succs;
67
auto query_type = v->query->getQueryType();
52
68
if(query_type == EVAL){
53
70
//assert(false && "Someone told me, this was a bad place to be.");
54
if (evaluateQuery(*v->query, v->marking, &query_marking)){
55
v->successors.push_back(newEdge(*v));
71
if (fastEval(query, &query_marking) == Condition::RTRUE){
72
succs.push_back(newEdge(*v, 0));///*v->query->distance(context))*/0);
58
75
else if (query_type == LOPERATOR){
59
if(v->query->GetQuantifier() == NEG){
60
Configuration* c = createConfiguration(v->marking, *(v->query->GetFirstChild()));
61
Edge* e = newEdge(*v);
76
if(v->query->getQuantifier() == NEG){
77
// no need to try to evaluate here -- this is already transient in other evaluations.
78
auto cond = static_cast<NotCondition*>(v->query);
79
Configuration* c = createConfiguration(v->marking, v->owner, (*cond)[0]);
80
Edge* e = newEdge(*v, /*v->query->distance(context)*/0);
62
81
e->is_negated = true;
63
e->targets.push_back(c);
64
v->successors.push_back(e);
66
else if(v->query->GetQuantifier() == AND){
85
else if(v->query->getQuantifier() == AND){
86
auto cond = static_cast<AndCondition*>(v->query);
67
87
//Check if left is false
68
if(!v->query->GetFirstChild()->IsTemporal){
69
if(!fastEval(*(v->query->GetFirstChild()), v->marking, &query_marking))
70
//query cannot be satisfied, return empty succ set
74
//check if right is false
75
if(!v->query->GetSecondChild()->IsTemporal){
76
if(!fastEval(*(v->query->GetSecondChild()), v->marking, &query_marking))
80
Edge *e = newEdge(*v);
88
std::vector<Condition*> conds;
91
auto res = fastEval(c.get(), &query_marking);
92
if(res == Condition::RFALSE)
96
if(res == Condition::RUNKNOWN)
98
conds.push_back(c.get());
102
Edge *e = newEdge(*v, /*cond->distance(context)*/0);
82
104
//If we get here, then either both propositions are true (shouldn't be possible)
83
105
//Or a temporal operator and a true proposition
84
106
//Or both are temporal
85
if(v->query->GetFirstChild()->IsTemporal){
86
e->targets.push_back(createConfiguration(v->marking, *(v->query->GetFirstChild())));
88
if(v->query->GetSecondChild()->IsTemporal){
89
e->targets.push_back(createConfiguration(v->marking, *(v->query->GetSecondChild())));
91
v->successors.push_back(e);
109
assert(c->isTemporal());
110
e->addTarget(createConfiguration(v->marking, v->owner, c));
93
else if(v->query->GetQuantifier() == OR){
114
else if(v->query->getQuantifier() == OR){
115
auto cond = static_cast<OrCondition*>(v->query);
94
116
//Check if left is true
95
if(!v->query->GetFirstChild()->IsTemporal){
96
if(fastEval(*(v->query->GetFirstChild()), v->marking, &query_marking)){
97
//query is satisfied, return
98
v->successors.push_back(newEdge(*v));
117
std::vector<Condition*> conds;
120
auto res = fastEval(c.get(), &query_marking);
121
if(res == Condition::RTRUE)
123
succs.push_back(newEdge(*v, 0));
103
if(!v->query->GetSecondChild()->IsTemporal){
104
if(fastEval(*(v->query->GetSecondChild()), v->marking, &query_marking)){
105
v->successors.push_back(newEdge(*v));
126
if(res == Condition::RUNKNOWN)
128
conds.push_back(c.get());
110
132
//If we get here, either both propositions are false
111
133
//Or one is false and one is temporal
112
134
//Or both temporal
113
if(v->query->GetFirstChild()->IsTemporal){
114
Edge *e = newEdge(*v);
115
e->targets.push_back(createConfiguration(v->marking, *(v->query->GetFirstChild())));
116
v->successors.push_back(e);
118
if(v->query->GetSecondChild()->IsTemporal){
119
Edge *e = newEdge(*v);
120
e->targets.push_back(createConfiguration(v->marking, *(v->query->GetSecondChild())));
121
v->successors.push_back(e);
137
assert(c->isTemporal());
138
Edge *e = newEdge(*v, /*cond->distance(context)*/0);
139
e->addTarget(createConfiguration(v->marking, v->owner, c));
128
147
else if (query_type == PATHQEURY){
129
if(v->query->GetQuantifier() == A){
130
if (v->query->GetPath() == U){
132
if (!v->query->GetSecondChild()->IsTemporal){
148
if(v->query->getQuantifier() == A){
149
if (v->query->getPath() == U){
150
auto cond = static_cast<AUCondition*>(v->query);
152
auto r1 = fastEval((*cond)[1], &query_marking);
153
if (r1 != Condition::RUNKNOWN){
133
154
//right side is not temporal, eval it right now!
134
bool valid = fastEval(*(v->query->GetSecondChild()), v->marking, &query_marking);
135
if (valid) { //satisfied, no need to go through successors
136
v->successors.push_back(newEdge(*v));
155
if (r1 == Condition::RTRUE) { //satisfied, no need to go through successors
156
succs.push_back(newEdge(*v, 0));
138
158
}//else: It's not valid, no need to add any edge, just add successors
141
161
//right side is temporal, we need to evaluate it as normal
142
Configuration* c = createConfiguration(v->marking, *(v->query->GetSecondChild()));
144
right->targets.push_back(c);
162
Configuration* c = createConfiguration(v->marking, v->owner, (*cond)[1]);
163
right = newEdge(*v, /*(*cond)[1]->distance(context)*/0);
146
166
bool valid = false;
147
167
Configuration *left = NULL;
148
if (!v->query->GetFirstChild()->IsTemporal) {
168
auto r0 = fastEval((*cond)[0], &query_marking);
169
if (r0 != Condition::RUNKNOWN) {
149
170
//left side is not temporal, eval it right now!
150
valid = fastEval(*(v->query->GetFirstChild()), v->marking, &query_marking);
171
valid = r0 == Condition::RTRUE;
152
173
//left side is temporal, include it in the edge
153
left = createConfiguration(v->marking, *(v->query->GetFirstChild()));
174
left = createConfiguration(v->marking, v->owner, (*cond)[0]);
155
176
if (valid || left != NULL) {
156
177
//if left side is guaranteed to be not satisfied, skip successor generation
157
178
Edge* leftEdge = NULL;
158
179
nextStates (query_marking,
159
[&](){ leftEdge = newEdge(*v);},
160
[&](size_t m, Marking&){
161
Configuration* c = createConfiguration(m, *(v->query));
162
leftEdge->targets.push_back(c);
180
[&](){ leftEdge = newEdge(*v, std::numeric_limits<uint32_t>::max());},
182
auto res = fastEval(cond, &mark);
183
if(res == Condition::RTRUE) return true;
184
if(res == Condition::RFALSE)
187
leftEdge->targets.clear();
191
context.setMarking(mark.marking());
192
leftEdge->weight = 0;//std::min(leftEdge->weight, /*cond->distance(context)*/0);
193
Configuration* c = createConfiguration(createMarking(mark), owner(mark, cond), cond);
194
leftEdge->addTarget(c);
168
leftEdge->targets.push_back(left);
202
leftEdge->addTarget(left);
204
succs.push_back(leftEdge);
170
v->successors.push_back(leftEdge);
173
208
} //else: Left side is not temporal and it's false, no way to succeed there...
175
210
if (right != NULL) {
176
v->successors.push_back(right);
211
succs.push_back(right);
179
else if(v->query->GetPath() == F){
214
else if(v->query->getPath() == F){
215
auto cond = static_cast<AFCondition*>(v->query);
180
216
Edge *subquery = NULL;
181
if (!v->query->GetFirstChild()->IsTemporal) {
182
bool valid = fastEval(*(v->query->GetFirstChild()), v->marking, &query_marking);
217
auto r = fastEval((*cond)[0], &query_marking);
218
if (r != Condition::RUNKNOWN) {
219
bool valid = r == Condition::RTRUE;
184
v->successors.push_back(newEdge(*v));
221
succs.push_back(newEdge(*v, 0));
188
subquery = newEdge(*v);
189
Configuration* c = createConfiguration(v->marking, *(v->query->GetFirstChild()));
190
subquery->targets.push_back(c);
225
subquery = newEdge(*v, /*cond->distance(context)*/0);
226
Configuration* c = createConfiguration(v->marking, v->owner, (*cond)[0]);
227
subquery->addTarget(c);
193
230
nextStates(query_marking,
194
[&](){e1 = newEdge(*v);},
195
[&](size_t m, Marking&)
231
[&](){e1 = newEdge(*v, std::numeric_limits<uint32_t>::max());},
197
Configuration* c = createConfiguration(m, *(v->query));
198
e1->targets.push_back(c);
234
auto res = fastEval(cond, &mark);
235
if(res == Condition::RTRUE) return true;
236
if(res == Condition::RFALSE)
247
context.setMarking(mark.marking());
248
e1->weight = 0;//std::min(e1->weight, /*cond->distance(context)*/0);
249
Configuration* c = createConfiguration(createMarking(mark), owner(mark, cond), cond);
203
v->successors.push_back(e1);
207
if (subquery != NULL) {
208
v->successors.push_back(subquery);
211
else if(v->query->GetPath() == X){
213
if (v->query->GetFirstChild()->IsTemporal) { //regular check
214
Edge* e = newEdge(*v);
215
nextStates(query_marking,
217
[&](size_t m, Marking&){
218
Configuration* c = createConfiguration(m, *(v->query->GetFirstChild()));
219
e->targets.push_back(c);
224
v->successors.push_back(e);
226
bool allValid = true;
227
nextStates(query_marking,
229
[&](size_t m, Marking& marking){
230
bool valid = fastEval(*(v->query->GetFirstChild()), m, &marking);
240
v->successors.push_back(newEdge(*v));
245
else if(v->query->GetPath() == G ){
259
if (subquery != nullptr) {
260
succs.push_back(subquery);
263
else if(v->query->getPath() == X){
264
auto cond = static_cast<AXCondition*>(v->query);
265
Edge* e = newEdge(*v, std::numeric_limits<uint32_t>::max());
266
Condition::Result allValid = Condition::RTRUE;
267
nextStates(query_marking,
270
auto res = fastEval((*cond)[0], &mark);
271
if(res != Condition::RUNKNOWN)
273
if (res == Condition::RFALSE) {
274
allValid = Condition::RFALSE;
280
allValid = Condition::RUNKNOWN;
281
context.setMarking(mark.marking());
282
e->weight = 0;//std::min(e->weight, /*cond->distance(context)*/0);
283
Configuration* c = createConfiguration(createMarking(mark), v->owner, (*cond)[0]);
290
if(allValid == Condition::RUNKNOWN)
294
else if(allValid == Condition::RTRUE)
303
else if(v->query->getPath() == G ){
246
304
assert(false && "Path operator G had not been translated - Parse error detected in succ()");
249
307
assert(false && "An unknown error occoured in the successor generator");
251
else if(v->query->GetQuantifier() == E){
252
if (v->query->GetPath() == U){
309
else if(v->query->getQuantifier() == E){
310
if (v->query->getPath() == U){
311
auto cond = static_cast<EUCondition*>(v->query);
253
312
Edge *right = NULL;
254
if (v->query->GetSecondChild()->IsTemporal) {
255
Configuration* c = createConfiguration(v->marking, *(v->query->GetSecondChild()));
257
right->targets.push_back(c);
313
auto r1 = fastEval((*cond)[1], &query_marking);
314
if (r1 == Condition::RUNKNOWN) {
315
Configuration* c = createConfiguration(v->marking, v->owner, (*cond)[1]);
316
right = newEdge(*v, /*(*cond)[1]->distance(context)*/0);
259
bool valid = fastEval(*(v->query->GetSecondChild()), v->marking, &query_marking);
319
bool valid = r1 == Condition::RTRUE;
261
v->successors.push_back(newEdge(*v));
321
succs.push_back(newEdge(*v, 0));
263
323
} // else: right condition is not satisfied, no need to add an edge
268
328
bool valid = false;
269
329
nextStates(query_marking,
271
if (v->query->GetFirstChild()->IsTemporal) {
272
left = createConfiguration(v->marking, *(v->query->GetFirstChild()));
331
auto r0 = fastEval((*cond)[0], &query_marking);
332
if (r0 == Condition::RUNKNOWN) {
333
left = createConfiguration(v->marking, v->owner, (*cond)[0]);
274
valid = fastEval(*(v->query->GetFirstChild()), v->marking, &query_marking);
335
valid = r0 == Condition::RTRUE;
277
[&](size_t m, Marking&){
338
[&](Marking& marking){
278
339
if(left == NULL && !valid) return false;
279
Edge* e = newEdge(*v);
280
Configuration* c1 = createConfiguration(m, *(v->query));
281
e->targets.push_back(c1);
340
auto res = fastEval(cond, &marking);
341
if(res == Condition::RFALSE) return true;
342
if(res == Condition::RTRUE)
344
for(auto s : succs){ --s->refcnt; release(s);};
346
succs.push_back(newEdge(*v, 0));
356
succs.back()->addTarget(left);
361
context.setMarking(marking.marking());
362
Edge* e = newEdge(*v, /*cond->distance(context)*/0);
363
Configuration* c1 = createConfiguration(createMarking(marking), owner(marking, cond), cond);
282
365
if (left != NULL) {
283
e->targets.push_back(left);
285
v->successors.push_back(e);
290
v->successors.push_back(right);
372
if (right != nullptr) {
373
succs.push_back(right);
293
else if(v->query->GetPath() == F){
376
else if(v->query->getPath() == F){
377
auto cond = static_cast<EFCondition*>(v->query);
294
378
Edge *subquery = NULL;
295
if (!v->query->GetFirstChild()->IsTemporal) {
296
bool valid = fastEval(*(v->query->GetFirstChild()), v->marking, &query_marking);
379
auto r = fastEval((*cond)[0], &query_marking);
380
if (r != Condition::RUNKNOWN) {
381
bool valid = r == Condition::RTRUE;
298
v->successors.push_back(newEdge(*v));
383
succs.push_back(newEdge(*v, 0));
302
Configuration* c = createConfiguration(v->marking, *(v->query->GetFirstChild()));
303
subquery = newEdge(*v);
304
subquery->targets.push_back(c);
387
Configuration* c = createConfiguration(v->marking, v->owner, (*cond)[0]);
388
subquery = newEdge(*v, /*cond->distance(context)*/0);
389
subquery->addTarget(c);
307
392
nextStates(query_marking,
309
[&](size_t m, Marking&){
310
Edge* e = newEdge(*v);
311
Configuration* c = createConfiguration(m, *(v->query));
312
e->targets.push_back(c);
313
v->successors.push_back(e);
395
auto res = fastEval(cond, &mark);
396
if(res == Condition::RFALSE) return true;
397
if(res == Condition::RTRUE)
399
for(auto s : succs){ --s->refcnt; release(s);};
401
succs.push_back(newEdge(*v, 0));
410
context.setMarking(mark.marking());
411
Edge* e = newEdge(*v, /*cond->distance(context)*/0);
412
Configuration* c = createConfiguration(createMarking(mark), owner(mark, cond), cond);
319
420
if (subquery != NULL) {
320
v->successors.push_back(subquery);
323
else if(v->query->GetPath() == X){
324
CTLQuery* query = v->query->GetFirstChild();
325
if (query->IsTemporal) { //have to check, no way to skip that
326
nextStates(query_marking,
328
[&](size_t m, Marking& marking) {
329
Edge* e = newEdge(*v);
330
Configuration* c = createConfiguration(m, *query);
331
e->targets.push_back(c);
332
v->successors.push_back(e);
338
nextStates(query_marking,
340
[&](size_t m, Marking& marking) {
341
bool valid = fastEval(*query, m, &marking);
343
v->successors.push_back(newEdge(*v));
345
} //else: It can't hold there, no need to create an edge
352
else if(v->query->GetPath() == G ){
421
succs.push_back(subquery);
424
else if(v->query->getPath() == X){
425
auto cond = static_cast<EXCondition*>(v->query);
426
auto query = (*cond)[0];
427
nextStates(query_marking,
429
[&](Marking& marking) {
430
auto res = fastEval(query, &marking);
431
if(res == Condition::RTRUE)
433
for(auto s : succs){ --s->refcnt; release(s);};
435
succs.push_back(newEdge(*v, 0));
437
} //else: It can't hold there, no need to create an edge
438
else if(res == Condition::RUNKNOWN)
440
context.setMarking(marking.marking());
441
Edge* e = newEdge(*v, /*(*cond)[0]->distance(context)*/0);
442
Configuration* c = createConfiguration(createMarking(marking), v->owner, query);
451
else if(v->query->getPath() == G ){
353
452
assert(false && "Path operator G had not been translated - Parse error detected in succ()");
356
455
assert(false && "An unknown error occoured in the successor generator");
361
bool OnTheFlyDG::evaluateQuery(CTLQuery &query, size_t marking, Marking* unfolded)
363
assert(query.GetQueryType() == EVAL);
364
EvaluateableProposition *proposition = query.GetProposition();
366
if (proposition->GetPropositionType() == FIREABILITY) {
367
for(const auto f : proposition->GetFireset()){
368
// We might be able to optimize this out
369
// by keeping track of the fired transitions
370
// during successor generation
371
if(net->fireable(unfolded->marking(), f)){
377
else if (proposition->GetPropositionType() == CARDINALITY) {
378
int first_param = GetParamValue(proposition->GetFirstParameter(), *unfolded);
379
int second_param = GetParamValue(proposition->GetSecondParameter(), *unfolded);
380
return EvalCardianlity(first_param, proposition->GetLoperator(), second_param);
382
else if (proposition->GetPropositionType() == DEADLOCK) {
383
return net->deadlocked(unfolded->marking());
386
assert(false && "Incorrect query proposition type was attempted evaluated");
390
int OnTheFlyDG::GetParamValue(CardinalityParameter *param, Marking& marking) {
393
for(int place : param->places_i){
394
res = res + marking.marking()[place];
398
else if(param->isArithmetic){
399
if(param->arithmetictype == NON){
400
std::cerr << "Error: Arithmetic param is not assigned a type"<< std::endl;
403
else if(param->arithmetictype == SUM){
404
return GetParamValue(param->arithmA, marking) + GetParamValue(param->arithmB, marking);
406
else if(param->arithmetictype == PRODUCT){
407
return GetParamValue(param->arithmA, marking) * GetParamValue(param->arithmB, marking);
409
else if(param->arithmetictype == DIFF){
410
return GetParamValue(param->arithmA, marking) - GetParamValue(param->arithmB, marking);
416
bool OnTheFlyDG::EvalCardianlity(int a, LoperatorType lop, int b) {
429
std::cerr << "Error: Query unsupported - Attempted to compare " << a << " with " << b << " by an unknown logical operator " << std::endl;
460
assert(false && "Should never happen");
462
if(succs.size() == 1 && succs[0]->targets.size() == 1)
464
((PetriConfig*)succs[0]->targets[0])->owner = v->owner;
434
469
Configuration* OnTheFlyDG::initialConfiguration()
471
if(working_marking.marking() == nullptr)
473
working_marking.setMarking (net->makeInitialMarking());
474
query_marking.setMarking (net->makeInitialMarking());
475
auto o = owner(working_marking, this->query);
476
initial_config = createConfiguration(createMarking(working_marking), o, this->query);
436
478
return initial_config;
439
481
void OnTheFlyDG::nextStates(Marking& t_marking,
440
482
std::function<void ()> pre,
441
std::function<bool (size_t, Marking&)> foreach,
483
std::function<bool (Marking&)> foreach,
442
484
std::function<void ()> post)
463
505
void OnTheFlyDG::cleanUp()
507
while(!recycle.empty())
509
assert(recycle.top()->refcnt == -1);
465
512
// TODO, implement proper cleanup
468
void OnTheFlyDG::setQuery(CTLQuery *query)
516
void OnTheFlyDG::setQuery(const Condition_ptr& query)
471
518
this->query = query;
472
520
delete[] working_marking.marking();
473
521
delete[] query_marking.marking();
474
working_marking.setMarking (net->makeInitialMarking());
475
query_marking.setMarking (net->makeInitialMarking());
476
initial_config = createConfiguration(createMarking(working_marking), *query);
522
working_marking.setMarking(nullptr);
523
query_marking.setMarking(nullptr);
479
int OnTheFlyDG::configurationCount() const
527
size_t OnTheFlyDG::configurationCount() const
481
529
return _configurationCount;
484
int OnTheFlyDG::markingCount() const
532
size_t OnTheFlyDG::markingCount() const
486
534
return _markingCount;
489
PetriConfig *OnTheFlyDG::createConfiguration(size_t t_marking, CTLQuery &t_query)
537
PetriConfig *OnTheFlyDG::createConfiguration(size_t marking, size_t own, Condition* t_query)
491
auto& configs = trie.get_data(t_marking);
539
auto& configs = trie.get_data(marking);
492
540
for(PetriConfig* c : configs){
493
if(c->query == &t_query)
541
if(c->query == t_query)
497
545
_configurationCount++;
498
PetriConfig* newConfig = new PetriConfig();
499
newConfig->marking = t_marking;
500
newConfig->query = &t_query;
546
size_t id = conf_alloc->next(0);
547
char* mem = (*conf_alloc)[id];
548
PetriConfig* newConfig = new (mem) PetriConfig();
549
newConfig->marking = marking;
550
newConfig->query = t_query;
551
newConfig->owner = own;
501
552
configs.push_back(newConfig);
502
553
return newConfig;