diff --git a/src/ltlast/multop.cc b/src/ltlast/multop.cc index 0f6093725..ed0d19d83 100644 --- a/src/ltlast/multop.cc +++ b/src/ltlast/multop.cc @@ -109,6 +109,8 @@ namespace spot { case And: return "And"; + case AndNLM: + return "AndNLM"; case Or: return "Or"; case Concat: @@ -171,6 +173,7 @@ namespace spot std::sort(v->begin(), v->end(), formula_ptr_less_than()); formula* neutral; + formula* neutral2; formula* abs; formula* abs2; formula* weak_abs; @@ -178,24 +181,35 @@ namespace spot { case And: neutral = constant::true_instance(); + neutral2 = 0; abs = constant::false_instance(); abs2 = 0; weak_abs = constant::empty_word_instance(); break; + case AndNLM: + neutral = constant::true_instance(); + neutral2 = constant::empty_word_instance(); + abs = constant::false_instance(); + abs2 = 0; + weak_abs = 0; + break; case Or: neutral = constant::false_instance(); + neutral2 = 0; abs = constant::true_instance(); abs2 = 0; weak_abs = 0; break; case Concat: neutral = constant::empty_word_instance(); + neutral2 = 0; abs = constant::false_instance(); abs2 = 0; weak_abs = 0; break; case Fusion: neutral = constant::true_instance(); + neutral2 = 0; abs = constant::false_instance(); abs2 = constant::empty_word_instance(); weak_abs = 0; @@ -203,6 +217,7 @@ namespace spot default: neutral = 0; + neutral2 = 0; abs = 0; abs2 = 0; weak_abs = 0; @@ -218,7 +233,7 @@ namespace spot bool weak_abs_seen = false; while (i != v->end()) { - if ((*i == neutral) || (*i == last)) + if ((*i == neutral) || (*i == neutral2) || (*i == last)) { (*i)->destroy(); i = v->erase(i); diff --git a/src/ltlast/multop.hh b/src/ltlast/multop.hh index e9fa0f88b..1f5f9a4d7 100644 --- a/src/ltlast/multop.hh +++ b/src/ltlast/multop.hh @@ -41,7 +41,7 @@ namespace spot class multop : public ref_formula { public: - enum type { Or, And, Concat, Fusion }; + enum type { Or, And, AndNLM, Concat, Fusion }; /// List of formulae. typedef std::vector vec; @@ -80,15 +80,24 @@ namespace spot /// are also taken care of. The following rewriting are performed /// (the left patterns are rewritten as shown on the right): /// - /// - Concat(Exps1...,[*0],Exps2...) = Concat(Exps1...,Exps2...) - /// - Concat(Exps1...,0,Exps2...) = 0 - /// - Concat(Exp) = Exp /// - And(Exps1...,1,Exps2...) = And(Exps1...,Exps2...) /// - And(Exps1...,0,Exps2...) = 0 + /// - And(Exps1...,[*0],Exps2...) = [*0] if no Expi is 0. /// - And(Exp) = Exp + /// - AndNLM(Exps1...,1,Exps2...) = AndNLM(Exps1...,Exps2...) + /// - AndNLM(Exps1...,0,Exps2...) = 0 + /// - AndNLM(Exps1...,[*0],Exps2...) = AndNLM(Exps1...,Exps2...) + /// - AndNLM(Exp) = Exp /// - Or(Exps1...,1,Exps2...) = 1 /// - Or(Exps1...,0,Exps2...) = And(Exps1...,Exps2...) /// - Or(Exp) = Exp + /// - Concat(Exps1...,[*0],Exps2...) = Concat(Exps1...,Exps2...) + /// - Concat(Exps1...,0,Exps2...) = 0 + /// - Concat(Exp) = Exp + /// - Fusion(Exps1...,1,Exps2...) = Concat(Exps1...,Exps2...) + /// - Fusion(Exps1...,0,Exps2...) = 0 + /// - Fusion(Exps1...,[*0],Exps2...) = 0 + /// - Fusion(Exp) = Exp static formula* instance(type op, vec* v); virtual void accept(visitor& v); diff --git a/src/ltlparse/ltlparse.yy b/src/ltlparse/ltlparse.yy index 27fd40305..cfd20f356 100644 --- a/src/ltlparse/ltlparse.yy +++ b/src/ltlparse/ltlparse.yy @@ -78,7 +78,8 @@ using namespace spot::ltl; %token START_RATEXP "RATEXP start marker" %token PAR_OPEN "opening parenthesis" PAR_CLOSE "closing parenthesis" %token BRACE_OPEN "opening brace" BRACE_CLOSE "closing brace" -%token OP_OR "or operator" OP_XOR "xor operator" OP_AND "and operator" +%token OP_OR "or operator" OP_XOR "xor operator" +%token OP_AND "and operator" OP_SHORT_AND "short and operator" %token OP_IMPLIES "implication operator" OP_EQUIV "equivalent operator" %token OP_U "until operator" OP_R "release operator" %token OP_W "weak until operator" OP_M "strong release operator" @@ -103,7 +104,7 @@ using namespace spot::ltl; %left OP_IMPLIES OP_EQUIV %left OP_OR %left OP_XOR -%left OP_AND +%left OP_AND OP_SHORT_AND /* LTL operators. */ %left OP_U OP_R OP_M OP_W @@ -257,7 +258,13 @@ rationalexp: booleanatom | rationalexp OP_AND rationalexp { $$ = multop::instance(multop::And, $1, $3); } | rationalexp OP_AND error - { missing_right_binop($$, $1, @2, "and operator"); } + { missing_right_binop($$, $1, @2, + "length-matching and operator"); } + | rationalexp OP_SHORT_AND rationalexp + { $$ = multop::instance(multop::AndNLM, $1, $3); } + | rationalexp OP_SHORT_AND error + { missing_right_binop($$, $1, @2, + "non-length-matching and operator"); } | rationalexp OP_OR rationalexp { $$ = multop::instance(multop::Or, $1, $3); } | rationalexp OP_OR error @@ -318,6 +325,10 @@ subformula: booleanatom { $$ = multop::instance(multop::And, $1, $3); } | subformula OP_AND error { missing_right_binop($$, $1, @2, "and operator"); } + | subformula OP_SHORT_AND subformula + { $$ = multop::instance(multop::And, $1, $3); } + | subformula OP_SHORT_AND error + { missing_right_binop($$, $1, @2, "and operator"); } | subformula OP_OR subformula { $$ = multop::instance(multop::Or, $1, $3); } | subformula OP_OR error diff --git a/src/ltlparse/ltlscan.ll b/src/ltlparse/ltlscan.ll index 36049f001..5f90c0864 100644 --- a/src/ltlparse/ltlscan.ll +++ b/src/ltlparse/ltlscan.ll @@ -97,7 +97,8 @@ flex_set_buffer(const char* buf, int start_tok) /\, \/, and xor are from LBTT. --> and <--> come from Goal. */ "||"|"|"|"+"|"\\/" BEGIN(0); return token::OP_OR; -"&&"|"&"|"/\\" BEGIN(0); return token::OP_AND; +"&&"|"/\\" BEGIN(0); return token::OP_AND; +"&" BEGIN(0); return token::OP_SHORT_AND; "^"|"xor" BEGIN(0); return token::OP_XOR; "=>"|"->"|"-->" BEGIN(0); return token::OP_IMPLIES; "<=>"|"<->"|"<-->" BEGIN(0); return token::OP_EQUIV; diff --git a/src/ltlvisit/basicreduce.cc b/src/ltlvisit/basicreduce.cc index 58f91f9d0..d1762fb45 100644 --- a/src/ltlvisit/basicreduce.cc +++ b/src/ltlvisit/basicreduce.cc @@ -786,6 +786,7 @@ namespace spot break; case multop::Concat: + case multop::AndNLM: case multop::Fusion: std::copy(res->begin(), res->end(), tmpOther->end()); break; diff --git a/src/ltlvisit/consterm.cc b/src/ltlvisit/consterm.cc index afe78a93b..864442c6a 100644 --- a/src/ltlvisit/consterm.cc +++ b/src/ltlvisit/consterm.cc @@ -122,6 +122,7 @@ namespace spot return; break; case multop::And: + case multop::AndNLM: case multop::Concat: result_ &= r; if (!result_) diff --git a/src/ltlvisit/contain.cc b/src/ltlvisit/contain.cc index eda34ca8c..d8d87c82f 100644 --- a/src/ltlvisit/contain.cc +++ b/src/ltlvisit/contain.cc @@ -357,6 +357,7 @@ namespace spot break; case multop::Concat: case multop::Fusion: + case multop::AndNLM: break; } if (changed) diff --git a/src/ltlvisit/mark.cc b/src/ltlvisit/mark.cc index d265a0c1a..c4b858cf9 100644 --- a/src/ltlvisit/mark.cc +++ b/src/ltlvisit/mark.cc @@ -203,6 +203,7 @@ namespace spot res->push_back(recurse(mo->nth(i))); break; case multop::And: + case multop::AndNLM: { typedef std::set > pset; pset Epairs, EMpairs; diff --git a/src/ltlvisit/nenoform.cc b/src/ltlvisit/nenoform.cc index 6a5f79fcb..a77c73abf 100644 --- a/src/ltlvisit/nenoform.cc +++ b/src/ltlvisit/nenoform.cc @@ -233,6 +233,7 @@ namespace spot break; case multop::Concat: case multop::Fusion: + case multop::AndNLM: break; } multop::vec* res = new multop::vec; @@ -249,12 +250,12 @@ namespace spot } case multop::Concat: case multop::Fusion: + case multop::AndNLM: { for (unsigned i = 0; i < mos; ++i) res->push_back(recurse_(mo->nth(i), false)); result_ = multop::instance(op, res); - if (negated_) - result_ = unop::instance(unop::Not, result_); + assert(!negated_); } } } diff --git a/src/ltlvisit/syntimpl.cc b/src/ltlvisit/syntimpl.cc index 8cda46119..248751ed7 100644 --- a/src/ltlvisit/syntimpl.cc +++ b/src/ltlvisit/syntimpl.cc @@ -205,6 +205,7 @@ namespace spot break; case multop::Concat: case multop::Fusion: + case multop::AndNLM: break; } } @@ -462,6 +463,7 @@ namespace spot break; case multop::Concat: case multop::Fusion: + case multop::AndNLM: break; } } diff --git a/src/ltlvisit/tostring.cc b/src/ltlvisit/tostring.cc index 9e7f008c0..cfe51f5c6 100644 --- a/src/ltlvisit/tostring.cc +++ b/src/ltlvisit/tostring.cc @@ -62,7 +62,8 @@ namespace spot { public: to_string_visitor(std::ostream& os, bool full_parent = false) - : os_(os), top_level_(true), full_parent_(full_parent) + : os_(os), top_level_(true), + full_parent_(full_parent), in_ratexp_(false) { } @@ -71,6 +72,18 @@ namespace spot { } + void + openp() const + { + os_ << (in_ratexp_ ? "{" : "("); + } + + void + closep() const + { + os_ << (in_ratexp_ ? "}" : ")"); + } + void visit(const atomic_prop* ap) { @@ -93,31 +106,30 @@ namespace spot visit(const constant* c) { if (full_parent_) - os_ << "("; + openp(); os_ << c->val_name(); if (full_parent_) - os_ << ")"; + closep(); } void visit(const binop* bo) { bool top_level = top_level_; + top_level_ = false; if (!top_level) - os_ << "("; + openp(); switch (bo->op()) { case binop::UConcat: case binop::EConcat: case binop::EConcatMarked: - os_ << "{ "; + os_ << "{"; + in_ratexp_ = true; top_level_ = true; - bo->first()->accept(*this); - top_level_ = false; - break; + // fall through default: - top_level_ = false; bo->first()->accept(*this); break; } @@ -146,19 +158,25 @@ namespace spot os_ << " M "; break; case binop::UConcat: - os_ << " }[]-> "; + os_ << "} []-> "; + in_ratexp_ = false; + top_level_ = top_level; break; case binop::EConcat: - os_ << " }<>-> "; + os_ << "} <>-> "; + in_ratexp_ = false; + top_level_ = false; break; case binop::EConcatMarked: - os_ << " }<>+> "; + os_ << "} <>+> "; + in_ratexp_ = false; + top_level_ = false; break; } bo->second()->accept(*this); if (!top_level) - os_ << ")"; + closep(); } void @@ -175,7 +193,7 @@ namespace spot need_parent = false; // These will be printed by each subformula if (!top_level) - os_ << "("; + openp(); } switch (uo->op()) @@ -199,13 +217,16 @@ namespace spot break; case unop::Closure: os_ << "{"; + in_ratexp_ = true; top_level_ = true; break; case unop::NegClosure: os_ << "!{"; + in_ratexp_ = true; + top_level_ = true; break; case unop::Star: - // 1* is OK, no need to print (1)*. + // 1* is OK, no need to print {1}*. need_parent = false; // Do not output anything yet, star is a postfix operator. break; @@ -213,10 +234,10 @@ namespace spot top_level_ = false; if (need_parent || full_parent_) - os_ << "("; + openp(); uo->child()->accept(*this); - if (need_parent) - os_ << ")"; + if (need_parent || full_parent_) + closep(); switch (uo->op()) { @@ -226,6 +247,7 @@ namespace spot case unop::Closure: case unop::NegClosure: os_ << "}"; + in_ratexp_ = false; top_level_ = false; break; default: @@ -233,7 +255,7 @@ namespace spot } if (full_parent_ && !top_level) - os_ << ")"; + closep(); } void @@ -264,7 +286,7 @@ namespace spot bool top_level = top_level_; top_level_ = false; if (!top_level) - os_ << "("; + openp(); unsigned max = mo->size(); mo->nth(0)->accept(*this); const char* ch = " "; @@ -274,6 +296,9 @@ namespace spot ch = " | "; break; case multop::And: + ch = in_ratexp_ ? " && " : " & "; + break; + case multop::AndNLM: ch = " & "; break; case multop::Concat: @@ -290,12 +315,13 @@ namespace spot mo->nth(n)->accept(*this); } if (!top_level) - os_ << ")"; + closep(); } protected: std::ostream& os_; bool top_level_; bool full_parent_; + bool in_ratexp_; }; class to_spin_string_visitor : public to_string_visitor @@ -317,7 +343,7 @@ namespace spot bool top_level = top_level_; top_level_ = false; if (!top_level) - os_ << "("; + openp(); switch (bo->op()) { @@ -361,17 +387,26 @@ namespace spot break; case binop::UConcat: bo->first()->accept(*this); - os_ << " []-> "; + os_ << "} []-> "; + top_level_ = false; bo->second()->accept(*this); break; case binop::EConcat: + in_ratexp_ = true; + top_level_ = true; + os_ << "{"; bo->first()->accept(*this); - os_ << " <>-> "; + os_ << "} <>-> "; + top_level_ = false; bo->second()->accept(*this); break; case binop::EConcatMarked: + in_ratexp_ = true; + top_level_ = true; + os_ << "{"; bo->first()->accept(*this); - os_ << " <>+> "; + os_ << "} <>+> "; + top_level_ = false; bo->second()->accept(*this); break; /* W and M are not supported by Spin */ @@ -388,7 +423,7 @@ namespace spot } if (!top_level) - os_ << ")"; + closep(); } void @@ -396,7 +431,7 @@ namespace spot { bool top_level = top_level_; if (full_parent_ && !top_level) - os_ << "("; + openp(); bool need_parent = false; top_level_ = false; @@ -426,23 +461,24 @@ namespace spot case unop::Closure: os_ << "{"; top_level_ = true; + in_ratexp_ = true; break; case unop::NegClosure: os_ << "!{"; top_level_ = true; + in_ratexp_ = true; break; case unop::Star: // Do not output anything yet, star is a postfix operator. + need_parent = false; break; } if (need_parent) - os_ << "("; + openp(); uo->child()->accept(*this); if (need_parent) - os_ << ")"; - if (uo->op() == unop::Star) - os_ << "*"; + closep(); switch (uo->op()) { @@ -452,6 +488,7 @@ namespace spot case unop::Closure: case unop::NegClosure: os_ << "}"; + in_ratexp_ = false; top_level_ = false; break; default: @@ -459,29 +496,7 @@ namespace spot } if (full_parent_ && !top_level) - os_ << ")"; - } - - void - visit(const automatop* ao) - { - // Warning: this string isn't parsable because the automaton - // operators used may not be defined. - bool top_level = top_level_; - top_level_ = false; - if (!top_level) - os_ << "("; - os_ << ao->get_nfa()->get_name() << "("; - unsigned max = ao->size(); - ao->nth(0)->accept(*this); - for (unsigned n = 1; n < max; ++n) - { - os_ << ","; - ao->nth(n)->accept(*this); - } - os_ << ")"; - if (!top_level) - os_ << ")"; + closep(); } void @@ -490,7 +505,7 @@ namespace spot bool top_level = top_level_; top_level_ = false; if (!top_level) - os_ << "("; + openp(); unsigned max = mo->size(); mo->nth(0)->accept(*this); const char* ch = " "; @@ -502,6 +517,9 @@ namespace spot case multop::And: ch = " && "; break; + case multop::AndNLM: + ch = " & "; + break; case multop::Concat: ch = ";"; break; @@ -516,7 +534,7 @@ namespace spot mo->nth(n)->accept(*this); } if (!top_level) - os_ << ")"; + closep(); } }; diff --git a/src/tgba/formula2bdd.cc b/src/tgba/formula2bdd.cc index 09181e285..8c0eb945c 100644 --- a/src/tgba/formula2bdd.cc +++ b/src/tgba/formula2bdd.cc @@ -145,6 +145,7 @@ namespace spot break; case multop::Concat: case multop::Fusion: + case multop::AndNLM: assert(!"unsupported operator"); } assert(op != -1); diff --git a/src/tgbaalgos/eltl2tgba_lacim.cc b/src/tgbaalgos/eltl2tgba_lacim.cc index 80c23b967..e00cae023 100644 --- a/src/tgbaalgos/eltl2tgba_lacim.cc +++ b/src/tgbaalgos/eltl2tgba_lacim.cc @@ -162,6 +162,7 @@ namespace spot break; case multop::Concat: case multop::Fusion: + case multop::AndNLM: assert(!"unsupported operator"); } assert(op != -1); diff --git a/src/tgbaalgos/ltl2taa.cc b/src/tgbaalgos/ltl2taa.cc index c06e81fe9..bf8175bf5 100644 --- a/src/tgbaalgos/ltl2taa.cc +++ b/src/tgbaalgos/ltl2taa.cc @@ -326,6 +326,7 @@ namespace spot return; case multop::Concat: case multop::Fusion: + case multop::AndNLM: assert(!"unsupported operator"); return; } diff --git a/src/tgbaalgos/ltl2tgba_fm.cc b/src/tgbaalgos/ltl2tgba_fm.cc index 94ee54a80..54d8c808c 100644 --- a/src/tgbaalgos/ltl2tgba_fm.cc +++ b/src/tgbaalgos/ltl2tgba_fm.cc @@ -158,7 +158,7 @@ namespace spot } formula* - conj_bdd_to_formula(bdd b) const + conj_bdd_to_formula(bdd b, multop::type op = multop::And) const { if (b == bddfalse) return constant::false_instance(); @@ -181,7 +181,7 @@ namespace spot assert(b != bddfalse); v->push_back(res); } - return multop::instance(multop::And, v); + return multop::instance(op, v); } formula* @@ -297,12 +297,8 @@ namespace spot class ratexp_trad_visitor: public const_visitor { public: - ratexp_trad_visitor(translate_dict& dict, - bool empty_word_is_true, - formula* to_concat = 0) - : dict_(dict), - empty_word_is_true_(empty_word_is_true), - to_concat_(to_concat) + ratexp_trad_visitor(translate_dict& dict, formula* to_concat = 0) + : dict_(dict), to_concat_(to_concat) { } @@ -332,7 +328,7 @@ namespace spot if (to_concat_ && to_concat_ != constant::empty_word_instance()) return recurse(to_concat_); - return empty_word_is_true_ ? bddtrue : bddfalse; + return bddfalse; } void @@ -408,25 +404,82 @@ namespace spot void visit(const multop* node) { - switch (node->op()) + multop::type op = node->op(); + switch (op) { + case multop::AndNLM: case multop::And: { - res_ = bddtrue; unsigned s = node->size(); + + if (op == multop::AndNLM) + { + multop::vec* final = new multop::vec; + multop::vec* non_final = new multop::vec; + + for (unsigned n = 0; n < s; ++n) + { + const formula* f = node->nth(n); + if (constant_term_as_bool(f)) + final->push_back(f->clone()); + else + non_final->push_back(f->clone()); + } + + if (non_final->empty()) + { + delete non_final; + // (a* & b*);c = (a*|b*);c + formula* f = multop::instance(multop::Or, final); + res_ = recurse_and_concat(f); + f->destroy(); + break; + } + if (!final->empty()) + { + // let F_i be final formulae + // N_i be non final formula + // (F_1 & ... & F_n & N_1 & ... & N_m) + // = (F_1 | ... | F_n);[*] && (N_1 & ... & N_m) + // | (F_1 | ... | F_n) && (N_1 & ... & N_m);[*] + formula* f = multop::instance(multop::Or, final); + formula* n = multop::instance(multop::AndNLM, non_final); + formula* t = unop::instance(unop::Star, + constant::true_instance()); + formula* ft = multop::instance(multop::Concat, + f->clone(), t->clone()); + formula* nt = multop::instance(multop::Concat, + n->clone(), t); + formula* ftn = multop::instance(multop::And, ft, n); + formula* fnt = multop::instance(multop::And, f, nt); + formula* all = multop::instance(multop::Or, ftn, fnt); + res_ = recurse_and_concat(all); + all->destroy(); + break; + } + // No final formula. + // Apply same rule as &&, until we reach a point where + // we have final formulae. + delete final; + for (unsigned n = 0; n < s; ++n) + (*non_final)[n]->destroy(); + delete non_final; + } + + res_ = bddtrue; for (unsigned n = 0; n < s; ++n) - { - bdd res = recurse(node->nth(n)); - // trace_ltl_bdd(dict_, res); - res_ &= res; - } + { + bdd res = recurse(node->nth(n)); + // trace_ltl_bdd(dict_, res); + res_ &= res; + } //std::cerr << "Pre-Concat:" << std::endl; //trace_ltl_bdd(dict_, res_); if (to_concat_) { - // If we have translated (a* & b*) in (a* & b*);c, we + // If we have translated (a* && b*) in (a* && b*);c, we // have to append ";c" to all destinations. minato_isop isop(res_); @@ -436,7 +489,8 @@ namespace spot { bdd label = bdd_exist(cube, dict_.next_set); bdd dest_bdd = bdd_existcomp(cube, dict_.next_set); - formula* dest = dict_.conj_bdd_to_formula(dest_bdd); + formula* dest = + dict_.conj_bdd_to_formula(dest_bdd, op); formula* dest2; int x; if (dest == constant::empty_word_instance()) @@ -458,6 +512,8 @@ namespace spot } } } + if (constant_term_as_bool(node)) + res_ |= now_to_concat(); break; } @@ -465,12 +521,8 @@ namespace spot { res_ = bddfalse; unsigned s = node->size(); - if (to_concat_) - for (unsigned n = 0; n < s; ++n) - res_ |= recurse(node->nth(n), to_concat_->clone()); - else - for (unsigned n = 0; n < s; ++n) - res_ |= recurse(node->nth(n)); + for (unsigned n = 0; n < s; ++n) + res_ |= recurse_and_concat(node->nth(n)); break; } case multop::Concat: @@ -520,9 +572,7 @@ namespace spot // can also exit if tail is satisfied. if (!tail_computed) { - tail_bdd = recurse(tail, - to_concat_ ? - to_concat_->clone() : 0); + tail_bdd = recurse_and_concat(tail); tail_computed = true; } res_ |= label & tail_bdd; @@ -556,16 +606,20 @@ namespace spot bdd recurse(const formula* f, formula* to_concat = 0) { - ratexp_trad_visitor v(dict_, empty_word_is_true_, to_concat); + ratexp_trad_visitor v(dict_, to_concat); f->accept(v); return v.result(); } + bdd + recurse_and_concat(const formula* f) + { + return recurse(f, to_concat_ ? to_concat_->clone() : 0); + } private: translate_dict& dict_; bdd res_; - bool empty_word_is_true_; formula* to_concat_; }; @@ -697,11 +751,18 @@ namespace spot case unop::Closure: { rat_seen_ = true; - ratexp_trad_visitor v(dict_, true); + if (constant_term_as_bool(node->child())) + { + res_ = bddtrue; + return; + } + + ratexp_trad_visitor v(dict_); node->child()->accept(v); bdd f1 = v.result(); res_ = bddfalse; + if (exprop_) { bdd var_set = bdd_existcomp(bdd_support(f1), dict_.var_set); @@ -766,7 +827,14 @@ namespace spot { rat_seen_ = true; has_marked_ = true; - ratexp_trad_visitor v(dict_, true); + + if (constant_term_as_bool(node->child())) + { + res_ = bddfalse; + return; + } + + ratexp_trad_visitor v(dict_); node->child()->accept(v); bdd f1 = v.result(); @@ -893,7 +961,7 @@ namespace spot // Recognize f2 on transitions going to destinations // that accept the empty word. bdd f2 = recurse(node->second()); - ratexp_trad_visitor v(dict_, false); + ratexp_trad_visitor v(dict_); node->first()->accept(v); bdd f1 = v.result(); res_ = bddfalse; @@ -968,7 +1036,7 @@ namespace spot // word should recognize f2, and the automaton for f1 // should be understood as universal. bdd f2 = recurse(node->second()); - ratexp_trad_visitor v(dict_, false); + ratexp_trad_visitor v(dict_); node->first()->accept(v); bdd f1 = v.result(); res_ = bddtrue; @@ -1067,6 +1135,7 @@ namespace spot } case multop::Concat: case multop::Fusion: + case multop::AndNLM: assert(!"Not an LTL operator"); break; } diff --git a/src/tgbaalgos/ltl2tgba_lacim.cc b/src/tgbaalgos/ltl2tgba_lacim.cc index 2b629b877..c2cc4c06c 100644 --- a/src/tgbaalgos/ltl2tgba_lacim.cc +++ b/src/tgbaalgos/ltl2tgba_lacim.cc @@ -260,6 +260,7 @@ namespace spot break; case multop::Concat: case multop::Fusion: + case multop::AndNLM: assert(!"unsupported operator"); } assert(op != -1); diff --git a/src/tgbatest/ltl2tgba.test b/src/tgbatest/ltl2tgba.test index a481a4773..d073675dd 100755 --- a/src/tgbatest/ltl2tgba.test +++ b/src/tgbatest/ltl2tgba.test @@ -76,6 +76,10 @@ check_psl '{a;b}' check_psl '{(a;b)*}' check_psl 'G{(a;b)*}' check_psl '{a*}[]->{b*}' +check_psl '{a*&b}' +check_psl '{a*&b*}' +check_psl '{((c;b*) & d);e}' +check_psl '{(a* & (c;b*) & d);e}' # Example from "Beyond Hardware Verification" by Glazberg, Moulin, Orni, # Ruah, Zarpas (2007). check_psl '{1[*];req;ack;1}[]->{start;busy[*];done}'