From 6ca0b56c6bd4d2878bc38aedb69a552ae425da2f Mon Sep 17 00:00:00 2001 From: Ragusaen Date: Fri, 4 Feb 2022 12:31:25 +0100 Subject: [PATCH 01/41] baked evaluationVisitor into evaluateAndSet visitor --- include/PetriEngine/PQL/Evaluation.h | 5 ++++- src/PetriEngine/PQL/Evaluation.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/PetriEngine/PQL/Evaluation.h b/include/PetriEngine/PQL/Evaluation.h index 06222e1cc..45e64b10e 100644 --- a/include/PetriEngine/PQL/Evaluation.h +++ b/include/PetriEngine/PQL/Evaluation.h @@ -149,9 +149,12 @@ namespace PetriEngine::PQL { class EvaluateAndSetVisitor : public BaseEvaluationVisitor { public: - explicit EvaluateAndSetVisitor(const EvaluationContext& context) : BaseEvaluationVisitor(context) {} + explicit EvaluateAndSetVisitor(const EvaluationContext& context) : BaseEvaluationVisitor(context), + _evaluate_visitor(context) {} private: + EvaluateVisitor _evaluate_visitor; + void _accept(SimpleQuantifierCondition *element) override; void _accept(GCondition *element) override; diff --git a/src/PetriEngine/PQL/Evaluation.cpp b/src/PetriEngine/PQL/Evaluation.cpp index 9c8008795..13cddbe1b 100644 --- a/src/PetriEngine/PQL/Evaluation.cpp +++ b/src/PetriEngine/PQL/Evaluation.cpp @@ -303,7 +303,8 @@ namespace PetriEngine::PQL { } void EvaluateAndSetVisitor::_accept(Expr *element) { - int r = evaluate(element, _context); + element->visit(_evaluate_visitor); + auto r = _evaluate_visitor.get_return_value()._value; element->setEval(r); _return_value = {r}; } @@ -339,7 +340,8 @@ namespace PetriEngine::PQL { } void EvaluateAndSetVisitor::_accept(CompareConjunction *element) { - auto res = evaluate(element, _context); + element->visit(_evaluate_visitor); + auto res = _evaluate_visitor.get_return_value()._result; element->setSatisfied(res); _return_value = {res}; } From c45180f493f76b5b29e483640a7ff859f748abf5 Mon Sep 17 00:00:00 2001 From: Ragusaen Date: Sun, 6 Feb 2022 13:17:57 +0100 Subject: [PATCH 02/41] changed evaluate call --- src/PetriEngine/Synthesis/GameStubbornSet.cpp | 2 +- src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PetriEngine/Synthesis/GameStubbornSet.cpp b/src/PetriEngine/Synthesis/GameStubbornSet.cpp index 842ad3cff..d9d797b71 100644 --- a/src/PetriEngine/Synthesis/GameStubbornSet.cpp +++ b/src/PetriEngine/Synthesis/GameStubbornSet.cpp @@ -372,7 +372,7 @@ namespace PetriEngine { #ifndef NDEBUG PQL::EvaluationContext context(_parent->marking(), &_net); - auto r = _queries[0]->evaluate(context); + auto r = PetriEngine::PQL::evaluate(_queries[0], context); if(iv.result() == IntervalVisitor::TRUE) assert(r != PQL::Condition::RFALSE); if(iv.result() == IntervalVisitor::FALSE) diff --git a/src/main.cpp b/src/main.cpp index 278e59c17..b7b22b6b3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -179,7 +179,7 @@ int main(int argc, const char** argv) { { EvaluationContext context(qm0.get(), qnet.get()); for (size_t i = 0; i < queries.size(); ++i) { - auto r = queries[i]->evaluate(context); + auto r = PetriEngine::PQL::evaluate(queries[i].get(), context); if(r == Condition::RFALSE) { queries[i] = BooleanCondition::FALSE_CONSTANT; From f6c8af7f5dd490de9b66c4a94c9c3e52d4ce1b3e Mon Sep 17 00:00:00 2001 From: Ragusaen Date: Mon, 7 Feb 2022 20:41:21 +0100 Subject: [PATCH 03/41] Removed CTL quantifiers --- include/LTL/LTLValidator.h | 40 -- include/PetriEngine/PQL/CTLVisitor.h | 115 ----- include/PetriEngine/PQL/ContainsVisitor.h | 29 -- include/PetriEngine/PQL/Expressions.h | 94 ---- include/PetriEngine/PQL/MutatingVisitor.h | 32 -- include/PetriEngine/PQL/PlaceUseVisitor.h | 8 - include/PetriEngine/PQL/PredicateCheckers.h | 18 - .../PetriEngine/PQL/PrepareForReachability.h | 33 -- include/PetriEngine/PQL/PushNegation.h | 16 - include/PetriEngine/PQL/QueryPrinter.h | 16 - include/PetriEngine/PQL/Simplifier.h | 27 +- include/PetriEngine/PQL/Visitor.h | 32 -- include/PetriEngine/PQL/XMLPrinter.h | 16 - .../Stubborn/InterestingTransitionVisitor.h | 16 - src/CTL/PetriNets/OnTheFlyDG.cpp | 12 +- src/PetriEngine/PQL/CTLVisitor.cpp | 266 ------------ src/PetriEngine/PQL/Expressions.cpp | 129 ------ src/PetriEngine/PQL/PredicateCheckers.cpp | 28 -- .../PQL/PrepareForReachability.cpp | 95 +---- src/PetriEngine/PQL/QueryPrinter.cpp | 40 -- src/PetriEngine/PQL/Simplifier.cpp | 402 ++++++------------ src/PetriEngine/PQL/XMLPrinter.cpp | 78 ---- src/PetriEngine/Synthesis/SimpleSynthesis.cpp | 4 - src/VerifyPN.cpp | 8 +- 24 files changed, 155 insertions(+), 1399 deletions(-) diff --git a/include/LTL/LTLValidator.h b/include/LTL/LTLValidator.h index f477da2a1..a861e72b2 100644 --- a/include/LTL/LTLValidator.h +++ b/include/LTL/LTLValidator.h @@ -46,46 +46,6 @@ namespace LTL { } }; - void _accept(const PetriEngine::PQL::EFCondition *condition) override { - setBad(); - std::cerr << "found EFCondition" << std::endl; - } - - void _accept(const PetriEngine::PQL::EGCondition *condition) override { - setBad(); - std::cerr << "found EGCondition" << std::endl; - } - - void _accept(const PetriEngine::PQL::AGCondition *condition) override { - setBad(); - std::cerr << "found AGCondition" << std::endl; - } - - void _accept(const PetriEngine::PQL::AFCondition *condition) override { - setBad(); - std::cerr << "found AFCondition" << std::endl; - } - - void _accept(const PetriEngine::PQL::EXCondition *condition) override { - setBad(); - std::cerr << "found EXCondition" << std::endl; - } - - void _accept(const PetriEngine::PQL::AXCondition *condition) override { - setBad(); - std::cerr << "found AXCondition" << std::endl; - } - - void _accept(const PetriEngine::PQL::EUCondition *condition) override { - setBad(); - std::cerr << "found EUCondition" << std::endl; - } - - void _accept(const PetriEngine::PQL::AUCondition *condition) override { - setBad(); - std::cerr << "found AUCondition" << std::endl; - } - void _accept(const PetriEngine::PQL::ACondition *condition) override { setBad(); } diff --git a/include/PetriEngine/PQL/CTLVisitor.h b/include/PetriEngine/PQL/CTLVisitor.h index a8caea1e3..568e98f61 100644 --- a/include/PetriEngine/PQL/CTLVisitor.h +++ b/include/PetriEngine/PQL/CTLVisitor.h @@ -34,22 +34,6 @@ namespace PetriEngine::PQL { void _accept(const ControlCondition *condition) override; - void _accept(const EFCondition *condition) override; - - void _accept(const EGCondition *condition) override; - - void _accept(const AGCondition *condition) override; - - void _accept(const AFCondition *condition) override; - - void _accept(const EXCondition *condition) override; - - void _accept(const AXCondition *condition) override; - - void _accept(const EUCondition *condition) override; - - void _accept(const AUCondition *condition) override; - void _accept(const ACondition *condition) override; void _accept(const ECondition *condition) override; @@ -99,105 +83,6 @@ namespace PetriEngine::PQL { void _accept(const CompareCondition *element); }; - - class AsCTL : public Visitor { - public: - Condition_ptr _ctl_query = nullptr; - Expr_ptr _expression = nullptr; - - protected: - void _accept(const NotCondition *element) override; - - void _accept(const AndCondition *element) override; - - void _accept(const OrCondition *element) override; - - void _accept(const LessThanCondition *element) override; - - void _accept(const LessThanOrEqualCondition *element) override; - - void _accept(const EqualCondition *element) override; - - void _accept(const NotEqualCondition *element) override; - - void _accept(const DeadlockCondition *element) override; - - void _accept(const CompareConjunction *element) override; - - void _accept(const UnfoldedUpperBoundsCondition *element) override; - - void _accept(const ControlCondition* condition) override; - - void _accept(const EFCondition *condition) override; - - void _accept(const EGCondition *condition) override; - - void _accept(const AGCondition *condition) override; - - void _accept(const AFCondition *condition) override; - - void _accept(const EXCondition *condition) override; - - void _accept(const AXCondition *condition) override; - - void _accept(const EUCondition *condition) override; - - void _accept(const AUCondition *condition) override; - - void _accept(const ACondition *condition) override; - - void _accept(const ECondition *condition) override; - - void _accept(const GCondition *condition) override; - - void _accept(const FCondition *condition) override; - - void _accept(const XCondition *condition) override; - - void _accept(const UntilCondition *condition) override; - - void _accept(const UnfoldedFireableCondition *element) override; - - void _accept(const FireableCondition *element) override; - - void _accept(const UpperBoundsCondition *element) override; - - void _accept(const LivenessCondition *element) override; - - void _accept(const KSafeCondition *element) override; - - void _accept(const QuasiLivenessCondition *element) override; - - void _accept(const StableMarkingCondition *element) override; - - void _accept(const BooleanCondition *element) override; - - void _accept(const UnfoldedIdentifierExpr *element) override; - - void _accept(const LiteralExpr *element) override; - - void _accept(const PlusExpr *element) override; - - void _accept(const MultiplyExpr *element) override; - - void _accept(const MinusExpr *element) override; - - void _accept(const SubtractExpr *element) override; - - void _accept(const IdentifierExpr *element) override; - - private: - std::pair compareCondition(const CompareCondition *element); - - template - void _acceptNary(const T *element); - - template - Expr_ptr copy_narry_expr(const T* el); - - template - std::shared_ptr copy_compare_condition(const T *element); - }; } #endif //VERIFYPN_CTLVISITOR_H diff --git a/include/PetriEngine/PQL/ContainsVisitor.h b/include/PetriEngine/PQL/ContainsVisitor.h index e9af2e02c..30570b45e 100644 --- a/include/PetriEngine/PQL/ContainsVisitor.h +++ b/include/PetriEngine/PQL/ContainsVisitor.h @@ -163,35 +163,6 @@ namespace PetriEngine if(found_type(element)) return; (*element)[0]->visit(*this); } - - virtual void _accept(const EFCondition* el) - { handleSimpleQuantifierCondition(el); } - virtual void _accept(const EGCondition* el) - { handleSimpleQuantifierCondition(el); } - virtual void _accept(const AGCondition* el) - { handleSimpleQuantifierCondition(el); } - virtual void _accept(const AFCondition* el) - { handleSimpleQuantifierCondition(el); } - virtual void _accept(const EXCondition* el) - { handleSimpleQuantifierCondition(el); } - virtual void _accept(const AXCondition* el) - { handleSimpleQuantifierCondition(el); } - - virtual void _accept(const EUCondition* el) - { - if(found_type(el)) return; - (*el)[0]->visit(*this); - if(_value) return; - (*el)[1]->visit(*this); - } - - virtual void _accept(const AUCondition* el) - { - if(found_type(el)) return; - (*el)[0]->visit(*this); - if(_value) return; - (*el)[1]->visit(*this); - } // shallow elements, neither of these should exist in a compiled expression virtual void _accept(const UnfoldedFireableCondition* element) diff --git a/include/PetriEngine/PQL/Expressions.h b/include/PetriEngine/PQL/Expressions.h index 242ed7f97..14e512f9e 100644 --- a/include/PetriEngine/PQL/Expressions.h +++ b/include/PetriEngine/PQL/Expressions.h @@ -446,82 +446,6 @@ namespace PetriEngine { void visit(MutatingVisitor&) override; }; - class EXCondition : public SimpleQuantifierCondition { - public: - using SimpleQuantifierCondition::SimpleQuantifierCondition; - - Quantifier getQuantifier() const override { return Quantifier::E; } - Path getPath() const override { return Path::X; } - uint32_t distance(DistanceContext& context) const override; - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - }; - - class EGCondition : public SimpleQuantifierCondition { - public: - using SimpleQuantifierCondition::SimpleQuantifierCondition; - - - Quantifier getQuantifier() const override { return Quantifier::E; } - Path getPath() const override { return Path::G; } - uint32_t distance(DistanceContext& context) const override; - Result evaluate(const EvaluationContext& context) override; - Result evalAndSet(const EvaluationContext& context) override; - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - }; - - class EFCondition : public SimpleQuantifierCondition { - public: - using SimpleQuantifierCondition::SimpleQuantifierCondition; - - - Quantifier getQuantifier() const override { return Quantifier::E; } - Path getPath() const override { return Path::F; } - uint32_t distance(DistanceContext& context) const override; - Result evaluate(const EvaluationContext& context) override; - Result evalAndSet(const EvaluationContext& context) override; - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - }; - - class AXCondition : public SimpleQuantifierCondition { - public: - using SimpleQuantifierCondition::SimpleQuantifierCondition; - - Quantifier getQuantifier() const override { return Quantifier::A; } - Path getPath() const override { return Path::X; } - uint32_t distance(DistanceContext& context) const override; - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - }; - - class AGCondition : public SimpleQuantifierCondition { - public: - using SimpleQuantifierCondition::SimpleQuantifierCondition; - - Quantifier getQuantifier() const override { return Quantifier::A; } - Path getPath() const override { return Path::G; } - uint32_t distance(DistanceContext& context) const override; - Result evaluate(const EvaluationContext& context) override; - Result evalAndSet(const EvaluationContext& context) override; - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - }; - - class AFCondition : public SimpleQuantifierCondition { - public: - using SimpleQuantifierCondition::SimpleQuantifierCondition; - - Quantifier getQuantifier() const override { return Quantifier::A; } - Path getPath() const override { return Path::F; } - uint32_t distance(DistanceContext& context) const override; - Result evaluate(const EvaluationContext& context) override; - Result evalAndSet(const EvaluationContext& context) override; - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - }; - class UntilCondition : public QuantifierCondition { public: UntilCondition(const Condition_ptr cond1, const Condition_ptr cond2) { @@ -550,24 +474,6 @@ namespace PetriEngine { }; - class EUCondition : public UntilCondition { - public: - using UntilCondition::UntilCondition; - Quantifier getQuantifier() const override { return Quantifier::E; } - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - uint32_t distance(DistanceContext& context) const override; - }; - - class AUCondition : public UntilCondition { - public: - using UntilCondition::UntilCondition; - Quantifier getQuantifier() const override { return Quantifier::A; } - void visit(Visitor&) const override; - void visit(MutatingVisitor&) override; - uint32_t distance(DistanceContext& context) const override; - }; - /******************** CONDITIONS ********************/ class UnfoldedFireableCondition : public ShallowCondition { diff --git a/include/PetriEngine/PQL/MutatingVisitor.h b/include/PetriEngine/PQL/MutatingVisitor.h index d29ee315a..71ec81331 100644 --- a/include/PetriEngine/PQL/MutatingVisitor.h +++ b/include/PetriEngine/PQL/MutatingVisitor.h @@ -88,38 +88,6 @@ namespace PetriEngine { condition->SimpleQuantifierCondition::visit(*this); }; - virtual void _accept(EFCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(EGCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(AGCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(AFCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(EXCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(AXCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(EUCondition *condition) { - condition->UntilCondition::visit(*this); - }; - - virtual void _accept(AUCondition *condition) { - condition->UntilCondition::visit(*this); - }; - virtual void _accept(ACondition *condition) { condition->SimpleQuantifierCondition::visit(*this); }; diff --git a/include/PetriEngine/PQL/PlaceUseVisitor.h b/include/PetriEngine/PQL/PlaceUseVisitor.h index fb9ebe3d8..872517556 100644 --- a/include/PetriEngine/PQL/PlaceUseVisitor.h +++ b/include/PetriEngine/PQL/PlaceUseVisitor.h @@ -50,14 +50,6 @@ namespace PQL { virtual void _accept(const CompareConjunction* element) override; virtual void _accept(const UnfoldedUpperBoundsCondition* element) override; - virtual void _accept(const EFCondition* el); - virtual void _accept(const EGCondition* el); - virtual void _accept(const AGCondition* el); - virtual void _accept(const AFCondition* el); - virtual void _accept(const EXCondition* el); - virtual void _accept(const AXCondition* el); - virtual void _accept(const EUCondition* el); - virtual void _accept(const AUCondition* el); private: void visitCommutativeExpr(const CommutativeExpr* element); }; diff --git a/include/PetriEngine/PQL/PredicateCheckers.h b/include/PetriEngine/PQL/PredicateCheckers.h index 1279c2fae..8b619d697 100644 --- a/include/PetriEngine/PQL/PredicateCheckers.h +++ b/include/PetriEngine/PQL/PredicateCheckers.h @@ -60,12 +60,8 @@ namespace PetriEngine::PQL { // If it is currently nested inside an EF or AG quantifier bool _is_nested = false; - void _accept(const EFCondition *element) override; - void _accept(const SimpleQuantifierCondition *element) override; - void _accept(const AGCondition *element) override; - void _accept(const ECondition *element) override; void _accept(const ACondition *element) override; @@ -108,16 +104,6 @@ namespace PetriEngine::PQL { void _accept(const XCondition *condition) override; - void _accept(const EXCondition *condition) override; - - void _accept(const EGCondition *condition) override; - - void _accept(const AXCondition *condition) override; - - void _accept(const AUCondition *condition) override; - - void _accept(const AFCondition *condition) override; - void _accept(const DeadlockCondition *condition) override; }; @@ -126,10 +112,6 @@ namespace PetriEngine::PQL { class ContainsNextVisitor : public AnyVisitor { void _accept(const XCondition *condition) override; - - void _accept(const EXCondition *condition) override; - - void _accept(const AXCondition *condition) override; }; } diff --git a/include/PetriEngine/PQL/PrepareForReachability.h b/include/PetriEngine/PQL/PrepareForReachability.h index 3ffdb1aa5..302b5951e 100644 --- a/include/PetriEngine/PQL/PrepareForReachability.h +++ b/include/PetriEngine/PQL/PrepareForReachability.h @@ -49,46 +49,13 @@ namespace PetriEngine::PQL { return _return_value; } - void _accept(const ControlCondition *condition) override; - - void _accept(const EGCondition *condition) override; - - void _accept(const EXCondition *condition) override; - - void _accept(const EFCondition *condition) override; - - void _accept(const AXCondition *condition) override; - - void _accept(const AGCondition *condition) override; - - void _accept(const AFCondition *condition) override; void _accept(const ACondition *condition) override; void _accept(const ECondition *condition) override; - void _accept(const UntilCondition *condition) override; - - void _accept(const LogicalCondition *condition) override; - - void _accept(const CompareConjunction *condition) override; - - void _accept(const CompareCondition *condition) override; - void _accept(const NotCondition *condition) override; - void _accept(const BooleanCondition *condition) override; - - void _accept(const DeadlockCondition *condition) override; - - void _accept(const UnfoldedUpperBoundsCondition *condition) override; - - void _accept(const GCondition *condition) override; - - void _accept(const FCondition *condition) override; - - void _accept(const XCondition *condition) override; - void _accept(const ShallowCondition *condition) override; }; diff --git a/include/PetriEngine/PQL/PushNegation.h b/include/PetriEngine/PQL/PushNegation.h index 1c1561d70..f22816ccc 100644 --- a/include/PetriEngine/PQL/PushNegation.h +++ b/include/PetriEngine/PQL/PushNegation.h @@ -83,22 +83,6 @@ namespace PetriEngine::PQL { void _accept(ControlCondition *element) override; - void _accept(EFCondition *condition) override; - - void _accept(EGCondition *condition) override; - - void _accept(AGCondition *condition) override; - - void _accept(AFCondition *condition) override; - - void _accept(EXCondition *condition) override; - - void _accept(AXCondition *condition) override; - - void _accept(EUCondition *condition) override; - - void _accept(AUCondition *condition) override; - void _accept(ACondition *condition) override; void _accept(ECondition *condition) override; diff --git a/include/PetriEngine/PQL/QueryPrinter.h b/include/PetriEngine/PQL/QueryPrinter.h index 22a076c38..1d4d0f62b 100644 --- a/include/PetriEngine/PQL/QueryPrinter.h +++ b/include/PetriEngine/PQL/QueryPrinter.h @@ -53,22 +53,6 @@ namespace PetriEngine { void _accept(const ControlCondition *condition) override; - void _accept(const EFCondition *condition) override; - - void _accept(const EGCondition *condition) override; - - void _accept(const AGCondition *condition) override; - - void _accept(const AFCondition *condition) override; - - void _accept(const EXCondition *condition) override; - - void _accept(const AXCondition *condition) override; - - void _accept(const EUCondition *condition) override; - - void _accept(const AUCondition *condition) override; - void _accept(const ACondition *condition) override; void _accept(const ECondition *condition) override; diff --git a/include/PetriEngine/PQL/Simplifier.h b/include/PetriEngine/PQL/Simplifier.h index d9cfbf4bc..c05076026 100644 --- a/include/PetriEngine/PQL/Simplifier.h +++ b/include/PetriEngine/PQL/Simplifier.h @@ -30,22 +30,17 @@ namespace PetriEngine::PQL { public: explicit Simplifier(SimplificationContext& context) : - context(context) {} + _context(context) {} - Retval return_value; + Retval _return_value; protected: - SimplificationContext& context; + SimplificationContext& _context; Retval simplifyOr(const LogicalCondition* element); Retval simplifyAnd(const LogicalCondition *element); - Retval simplifyAG(Retval &r); - Retval simplifyAF(Retval &r); Retval simplifyAX(Retval &r); - - Retval simplifyEG(Retval &r); - Retval simplifyEF(Retval &r); Retval simplifyEX(Retval &r); template @@ -73,22 +68,6 @@ namespace PetriEngine::PQL { void _accept(const ControlCondition *condition) override; - void _accept(const EFCondition *condition) override; - - void _accept(const EGCondition *condition) override; - - void _accept(const AGCondition *condition) override; - - void _accept(const AFCondition *condition) override; - - void _accept(const EXCondition *condition) override; - - void _accept(const AXCondition *condition) override; - - void _accept(const EUCondition *condition) override; - - void _accept(const AUCondition *condition) override; - void _accept(const ACondition *condition) override; void _accept(const ECondition *condition) override; diff --git a/include/PetriEngine/PQL/Visitor.h b/include/PetriEngine/PQL/Visitor.h index b31e5b283..a5f6cae0b 100644 --- a/include/PetriEngine/PQL/Visitor.h +++ b/include/PetriEngine/PQL/Visitor.h @@ -92,38 +92,6 @@ namespace PetriEngine { condition->SimpleQuantifierCondition::visit(*this); }; - virtual void _accept(const EFCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(const EGCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(const AGCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(const AFCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(const EXCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(const AXCondition *condition) { - condition->SimpleQuantifierCondition::visit(*this); - }; - - virtual void _accept(const EUCondition *condition) { - condition->UntilCondition::visit(*this); - }; - - virtual void _accept(const AUCondition *condition) { - condition->UntilCondition::visit(*this); - }; - virtual void _accept(const ACondition *condition) { condition->SimpleQuantifierCondition::visit(*this); }; diff --git a/include/PetriEngine/PQL/XMLPrinter.h b/include/PetriEngine/PQL/XMLPrinter.h index 02586ec58..f59dee972 100644 --- a/include/PetriEngine/PQL/XMLPrinter.h +++ b/include/PetriEngine/PQL/XMLPrinter.h @@ -73,22 +73,6 @@ namespace PetriEngine { void _accept(const ControlCondition *condition) override; - void _accept(const EFCondition *condition) override; - - void _accept(const EGCondition *condition) override; - - void _accept(const AGCondition *condition) override; - - void _accept(const AFCondition *condition) override; - - void _accept(const EXCondition *condition) override; - - void _accept(const AXCondition *condition) override; - - void _accept(const EUCondition *condition) override; - - void _accept(const AUCondition *condition) override; - void _accept(const ACondition *condition) override; void _accept(const ECondition *condition) override; diff --git a/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h b/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h index bcc737618..e8f19c63a 100644 --- a/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h +++ b/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h @@ -100,18 +100,6 @@ namespace PetriEngine { void _accept(const PQL::SimpleQuantifierCondition *element); - void _accept(const PQL::EFCondition *condition) override; - - void _accept(const PQL::EGCondition *condition) override; - - void _accept(const PQL::AGCondition *condition) override; - - void _accept(const PQL::AFCondition *condition) override; - - void _accept(const PQL::EXCondition *condition) override; - - void _accept(const PQL::AXCondition *condition) override; - void _accept(const PQL::ACondition *condition) override; void _accept(const PQL::ECondition *condition) override; @@ -124,10 +112,6 @@ namespace PetriEngine { void _accept(const PQL::FCondition *condition) override; - void _accept(const PQL::EUCondition *condition) override; - - void _accept(const PQL::AUCondition *condition) override; - void _accept(const PQL::BooleanCondition *element) override; bool negated = false; diff --git a/src/CTL/PetriNets/OnTheFlyDG.cpp b/src/CTL/PetriNets/OnTheFlyDG.cpp index 23d64f98f..0de1332f7 100644 --- a/src/CTL/PetriNets/OnTheFlyDG.cpp +++ b/src/CTL/PetriNets/OnTheFlyDG.cpp @@ -147,7 +147,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) else if (query_type == PATHQEURY){ if(v->query->getQuantifier() == A){ if (v->query->getPath() == U){ - auto cond = static_cast(v->query); + auto cond = static_cast((*static_cast(v->query))[0].get()); Edge *right = NULL; auto r1 = fastEval((*cond)[1], &query_marking); if (r1 != Condition::RUNKNOWN){ @@ -211,7 +211,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) } } else if(v->query->getPath() == F){ - auto cond = static_cast(v->query); + auto cond = static_cast((*static_cast(v->query))[0].get()); Edge *subquery = NULL; auto r = fastEval((*cond)[0], &query_marking); if (r != Condition::RUNKNOWN) { @@ -259,7 +259,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) } } else if(v->query->getPath() == X){ - auto cond = static_cast(v->query); + auto cond = static_cast((*static_cast(v->query))[0].get()); Edge* e = newEdge(*v, std::numeric_limits::max()); Condition::Result allValid = Condition::RTRUE; nextStates(query_marking, cond, @@ -305,7 +305,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) } else if(v->query->getQuantifier() == E){ if (v->query->getPath() == U){ - auto cond = static_cast(v->query); + auto cond = static_cast((*static_cast(v->query))[0].get()); Edge *right = NULL; auto r1 = fastEval((*cond)[1], &query_marking); if (r1 == Condition::RUNKNOWN) { @@ -371,7 +371,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) } } else if(v->query->getPath() == F){ - auto cond = static_cast(v->query); + auto cond = static_cast((*static_cast(v->query))[0].get()); Edge *subquery = NULL; auto r = fastEval((*cond)[0], &query_marking); if (r != Condition::RUNKNOWN) { @@ -419,7 +419,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) } } else if(v->query->getPath() == X){ - auto cond = static_cast(v->query); + auto cond = static_cast((*static_cast(v->query))[0].get()); auto query = (*cond)[0]; nextStates(query_marking, cond, [](){}, diff --git a/src/PetriEngine/PQL/CTLVisitor.cpp b/src/PetriEngine/PQL/CTLVisitor.cpp index ec098cfa6..915c8b8fa 100644 --- a/src/PetriEngine/PQL/CTLVisitor.cpp +++ b/src/PetriEngine/PQL/CTLVisitor.cpp @@ -232,270 +232,4 @@ namespace PetriEngine::PQL { void IsCTLVisitor::_accept(const IdentifierExpr *element) { _cur_type = CTLSyntaxType::BOOLEAN; } - - - void AsCTL::_accept(const NotCondition *element) { - (*element)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - template - void AsCTL::_acceptNary(const T *element) { - std::vector children; - for (auto operand : *element){ - operand->visit(*this); - children.push_back(_ctl_query); - } - _ctl_query = std::make_shared(children); - } - - void AsCTL::_accept(const AndCondition *element) { - AsCTL::_acceptNary(element); - } - - void AsCTL::_accept(const OrCondition *element) { - AsCTL::_acceptNary(element); - } - - template - std::shared_ptr AsCTL::copy_compare_condition(const T *element) { - // we copy of sharedptr for now, but this is not safe! - // copy_narry_expr needs fixing. - return std::make_shared((*element)[0], (*element)[1]); - } - - void AsCTL::_accept(const LessThanCondition *element) { - _ctl_query = copy_compare_condition(element); - } - - void AsCTL::_accept(const LessThanOrEqualCondition *element) { - _ctl_query = copy_compare_condition(element); - } - - void AsCTL::_accept(const EqualCondition *element) { - _ctl_query = copy_compare_condition(element); - } - - void AsCTL::_accept(const NotEqualCondition *element) { - _ctl_query = copy_compare_condition(element); - } - - void AsCTL::_accept(const DeadlockCondition *element) { - _ctl_query = std::make_shared(); - } - - void AsCTL::_accept(const CompareConjunction *element) { - _ctl_query = std::make_shared(*element); - } - - void AsCTL::_accept(const UnfoldedUpperBoundsCondition *element) { - _ctl_query = std::make_shared(*element); - } - - void AsCTL::_accept(const ControlCondition* condition) { - (*condition)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - void AsCTL::_accept(const EFCondition *condition) { - (*condition)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - void AsCTL::_accept(const EGCondition *condition) { - (*condition)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - void AsCTL::_accept(const AGCondition *condition) { - (*condition)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - void AsCTL::_accept(const AFCondition *condition) { - (*condition)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - void AsCTL::_accept(const EXCondition *condition) { - (*condition)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - void AsCTL::_accept(const AXCondition *condition) { - (*condition)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - } - - void AsCTL::_accept(const EUCondition *condition) { - (*condition)[0]->visit(*this); - auto first = _ctl_query; - (*condition)[1]->visit(*this); - _ctl_query = std::make_shared(first, _ctl_query); - } - - void AsCTL::_accept(const AUCondition *condition) { - (*condition)[0]->visit(*this); - auto first = _ctl_query; - (*condition)[1]->visit(*this); - _ctl_query = std::make_shared(first, _ctl_query); - } - - void AsCTL::_accept(const ACondition *condition) { - auto child = dynamic_cast((*condition)[0].get()); - switch (child->getPath()) { - case Path::G: - (*child)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - break; - case Path::X: - (*child)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - break; - case Path::F: - (*child)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - break; - case Path::U: { - (*child)[0]->visit(*this); - auto first = _ctl_query; - (*child)[1]->visit(*this); - _ctl_query = std::make_shared(first, _ctl_query); - break; - } - default: - assert(false); - _ctl_query = nullptr; - break; - } - } - - void AsCTL::_accept(const ECondition *condition) { - auto child = dynamic_cast((*condition)[0].get()); - switch (child->getPath()) { - case Path::G: - (*child)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - break; - case Path::X: - (*child)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - break; - case Path::F: - (*child)[0]->visit(*this); - _ctl_query = std::make_shared(_ctl_query); - break; - case Path::U: { - (*child)[0]->visit(*this); - auto first = _ctl_query; - (*child)[1]->visit(*this); - _ctl_query = std::make_shared(first, _ctl_query); - break; - } - default: - assert(false); - _ctl_query = nullptr; - break; - } - } - - void AsCTL::_accept(const GCondition *condition) { - std::cerr << "Direct call to path quantifier in AsCTL GCondition" << std::endl; - assert(false); - _ctl_query = nullptr; - } - - void AsCTL::_accept(const FCondition *condition) { - std::cerr << "Direct call to path quantifier in AsCTL FCondition" << std::endl; - assert(false); - _ctl_query = nullptr; - } - - void AsCTL::_accept(const XCondition *condition) { - std::cerr << "Direct call to path quantifier in AsCTL XCondition" << std::endl; - assert(false); - _ctl_query = nullptr; - } - - void AsCTL::_accept(const UntilCondition *condition) { - std::cerr << "Direct call to path quantifier in AsCTL UntilCondition" << std::endl; - assert(false); - _ctl_query = nullptr; - } - - void AsCTL::_accept(const UnfoldedFireableCondition *element) { - _ctl_query = std::make_shared(*element); - } - - template - Condition_ptr copy_condition(const T* el) - { - return std::make_shared(*el); - } - - void AsCTL::_accept(const FireableCondition *element) { - _ctl_query = copy_condition(element); - } - - void AsCTL::_accept(const UpperBoundsCondition *element) { - _ctl_query = copy_condition(element); - } - - void AsCTL::_accept(const LivenessCondition *element) { - _ctl_query = copy_condition(element); - } - - void AsCTL::_accept(const KSafeCondition *element) { - _ctl_query = copy_condition(element); - } - - void AsCTL::_accept(const QuasiLivenessCondition *element) { - _ctl_query = copy_condition(element); - } - - void AsCTL::_accept(const StableMarkingCondition *element) { - _ctl_query = copy_condition(element); - } - - void AsCTL::_accept(const BooleanCondition *element) { - _ctl_query = element->value ? BooleanCondition::TRUE_CONSTANT : BooleanCondition::FALSE_CONSTANT; - } - - template - Expr_ptr AsCTL::copy_narry_expr(const T* el) - { - assert(false); - // TODO: fix - return nullptr; - } - - void AsCTL::_accept(const PlusExpr *element) { - _expression = copy_narry_expr(element); - } - - void AsCTL::_accept(const MultiplyExpr *element) { - _expression = copy_narry_expr(element); - } - - void AsCTL::_accept(const SubtractExpr *element) { - _expression = copy_narry_expr(element); - } - - void AsCTL::_accept(const MinusExpr *element) { - (*element)[0]->visit(*this); - _expression = std::make_shared(_expression); - } - - void AsCTL::_accept(const LiteralExpr *element) { - _expression = std::make_shared(element->value()); - } - - void AsCTL::_accept(const IdentifierExpr *element) { - _expression = std::make_shared(*element); - } - - void AsCTL::_accept(const UnfoldedIdentifierExpr *element) { - _expression = std::make_shared(*element); - } - } \ No newline at end of file diff --git a/src/PetriEngine/PQL/Expressions.cpp b/src/PetriEngine/PQL/Expressions.cpp index f0d4d6ad5..72aec4fc2 100644 --- a/src/PetriEngine/PQL/Expressions.cpp +++ b/src/PetriEngine/PQL/Expressions.cpp @@ -245,31 +245,10 @@ namespace PetriEngine { return RUNKNOWN; } - Condition::Result EGCondition::evaluate(const EvaluationContext& context) { - if(_cond->evaluate(context) == RFALSE) return RFALSE; - return RUNKNOWN; - } - - Condition::Result AGCondition::evaluate(const EvaluationContext& context) - { - if(_cond->evaluate(context) == RFALSE) return RFALSE; - return RUNKNOWN; - } - Condition::Result ControlCondition::evaluate(const EvaluationContext& context) { return RUNKNOWN; } - Condition::Result EFCondition::evaluate(const EvaluationContext& context) { - if(_cond->evaluate(context) == RTRUE) return RTRUE; - return RUNKNOWN; - } - - Condition::Result AFCondition::evaluate(const EvaluationContext& context) { - if(_cond->evaluate(context) == RTRUE) return RTRUE; - return RUNKNOWN; - } - Condition::Result ACondition::evaluate(const EvaluationContext& context) { //if (_cond->evaluate(context) == RFALSE) return RFALSE; return RUNKNOWN; @@ -402,34 +381,6 @@ namespace PetriEngine { return res; } - Condition::Result EGCondition::evalAndSet(const EvaluationContext& context) { - auto res = _cond->evalAndSet(context); - if(res != RFALSE) res = RUNKNOWN; - setSatisfied(res); - return res; - } - - Condition::Result AGCondition::evalAndSet(const EvaluationContext& context) { - auto res = _cond->evalAndSet(context); - if(res != RFALSE) res = RUNKNOWN; - setSatisfied(res); - return res; - } - - Condition::Result EFCondition::evalAndSet(const EvaluationContext& context) { - auto res = _cond->evalAndSet(context); - if(res != RTRUE) res = RUNKNOWN; - setSatisfied(res); - return res; - } - - Condition::Result AFCondition::evalAndSet(const EvaluationContext& context) { - auto res = _cond->evalAndSet(context); - if(res != RTRUE) res = RUNKNOWN; - setSatisfied(res); - return res; - } - Condition::Result UntilCondition::evalAndSet(const EvaluationContext& context) { auto r2 = _cond2->evalAndSet(context); if(r2 != RFALSE) return r2; @@ -539,46 +490,6 @@ namespace PetriEngine { ctx.accept(this); } - void EGCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - - void EUCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - - void EXCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - - void EFCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - - void AUCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - - void AXCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - - void AFCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - - void AGCondition::visit(Visitor& ctx) const - { - ctx.accept(this); - } - void ACondition::visit(Visitor& ctx) const { ctx.accept(this); @@ -795,46 +706,6 @@ namespace PetriEngine { ctx.accept(this); } - void EGCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - - void EUCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - - void EXCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - - void EFCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - - void AUCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - - void AXCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - - void AFCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - - void AGCondition::visit(MutatingVisitor& ctx) - { - ctx.accept(this); - } - void ACondition::visit(MutatingVisitor& ctx) { ctx.accept(this); diff --git a/src/PetriEngine/PQL/PredicateCheckers.cpp b/src/PetriEngine/PQL/PredicateCheckers.cpp index d13e3c34a..1c4aedf58 100644 --- a/src/PetriEngine/PQL/PredicateCheckers.cpp +++ b/src/PetriEngine/PQL/PredicateCheckers.cpp @@ -226,26 +226,6 @@ namespace PetriEngine::PQL { setConditionFound(); } - void IsLoopSensitiveVisitor::_accept(const EXCondition* condition) { - setConditionFound(); - } - - void IsLoopSensitiveVisitor::_accept(const EGCondition* condition) { - setConditionFound(); - } - - void IsLoopSensitiveVisitor::_accept(const AXCondition* condition) { - setConditionFound(); - } - - void IsLoopSensitiveVisitor::_accept(const AFCondition* condition) { - setConditionFound(); - } - - void IsLoopSensitiveVisitor::_accept(const AUCondition* condition) { - setConditionFound(); - } - void IsLoopSensitiveVisitor::_accept(const DeadlockCondition* condition) { setConditionFound(); } @@ -262,12 +242,4 @@ namespace PetriEngine::PQL { setConditionFound(); } - void ContainsNextVisitor::_accept(const EXCondition* condition) { - setConditionFound(); - } - - void ContainsNextVisitor::_accept(const AXCondition* condition) { - setConditionFound(); - } - } diff --git a/src/PetriEngine/PQL/PrepareForReachability.cpp b/src/PetriEngine/PQL/PrepareForReachability.cpp index 54cf0c608..9a2cf8a4d 100644 --- a/src/PetriEngine/PQL/PrepareForReachability.cpp +++ b/src/PetriEngine/PQL/PrepareForReachability.cpp @@ -34,98 +34,29 @@ namespace PetriEngine::PQL { return visitor.getReturnValue(); } - void PrepareForReachabilityVisitor::_accept(const ControlCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const EXCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const EGCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const EFCondition *condition) { - condition->getCond()->setInvariant(_negated); - RETURN(condition->getCond()); - } - - void PrepareForReachabilityVisitor::_accept(const AXCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const AGCondition *condition) { - Condition_ptr cond = std::make_shared(condition->getCond()); - cond->setInvariant(!_negated); - RETURN(cond) - } - - void PrepareForReachabilityVisitor::_accept(const AFCondition *condition) { - RETURN(nullptr) - } - void PrepareForReachabilityVisitor::_accept(const ACondition *condition) { - auto g = std::dynamic_pointer_cast(condition->getCond()); - auto agcond = std::make_shared((*g)[0]); - RETURN(g ? subvisit(agcond.get(), _negated) : nullptr) + if (auto g = std::dynamic_pointer_cast(condition->getCond())) { + Condition_ptr cond = std::make_shared(g->getCond()); + cond->setInvariant(!_negated); + RETURN(cond) + } else { + RETURN(nullptr) + } } void PrepareForReachabilityVisitor::_accept(const ECondition *condition) { - auto f = std::dynamic_pointer_cast(condition->getCond()); - auto efcond = std::make_shared((*f)[0]); - RETURN(f ? subvisit(efcond.get(), _negated) : nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const UntilCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const LogicalCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const CompareConjunction *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const CompareCondition *condition) { - RETURN(nullptr) + if (auto f = std::dynamic_pointer_cast(condition->getCond())) { + f->getCond()->setInvariant(_negated); + RETURN(f->getCond()); + } else { + RETURN(nullptr) + } } void PrepareForReachabilityVisitor::_accept(const NotCondition *condition) { RETURN(subvisit(condition->getCond().get(), !_negated)) } - void PrepareForReachabilityVisitor::_accept(const BooleanCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const DeadlockCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const UnfoldedUpperBoundsCondition *condition) { - RETURN(nullptr) - } - - void PrepareForReachabilityVisitor::_accept(const GCondition* condition) { - // TODO implement - assert(false); - throw base_error("TODO implement"); - } - - void PrepareForReachabilityVisitor::_accept(const FCondition* condition) { - // TODO implement - assert(false); - throw base_error("TODO implement"); - } - - void PrepareForReachabilityVisitor::_accept(const XCondition* condition) { - // TODO implement - assert(false); throw base_error("TODO implement"); - } - void PrepareForReachabilityVisitor::_accept(const ShallowCondition* condition) { RETURN(subvisit(condition->getCompiled().get(), _negated)) } diff --git a/src/PetriEngine/PQL/QueryPrinter.cpp b/src/PetriEngine/PQL/QueryPrinter.cpp index 4777ecd06..d82bcff26 100644 --- a/src/PetriEngine/PQL/QueryPrinter.cpp +++ b/src/PetriEngine/PQL/QueryPrinter.cpp @@ -104,46 +104,6 @@ namespace PetriEngine { (*condition)[0]->visit(*this); } - void QueryPrinter::_accept(const EFCondition *condition) { - os << "EF "; - (*condition)[0]->visit(*this); - } - - void QueryPrinter::_accept(const EGCondition *condition) { - os << "EG "; - (*condition)[0]->visit(*this); - } - - void QueryPrinter::_accept(const AGCondition *condition) { - os << "AG "; - (*condition)[0]->visit(*this); - } - - void QueryPrinter::_accept(const AFCondition *condition) { - os << "AF "; - (*condition)[0]->visit(*this); - } - - void QueryPrinter::_accept(const EXCondition *condition) { - os << "AF "; - (*condition)[0]->visit(*this); - } - - void QueryPrinter::_accept(const AXCondition *condition) { - os << "AX "; - (*condition)[0]->visit(*this); - } - - void QueryPrinter::_accept(const EUCondition *condition) { - os << "E "; - _accept((UntilCondition*) condition); - } - - void QueryPrinter::_accept(const AUCondition *condition) { - os << "A "; - _accept((UntilCondition*) condition); - } - void QueryPrinter::_accept(const ACondition *condition) { os << "A "; (*condition)[0]->visit(*this); diff --git a/src/PetriEngine/PQL/Simplifier.cpp b/src/PetriEngine/PQL/Simplifier.cpp index 7eea85fdf..73175f16a 100644 --- a/src/PetriEngine/PQL/Simplifier.cpp +++ b/src/PetriEngine/PQL/Simplifier.cpp @@ -19,14 +19,14 @@ */ #include "PetriEngine/PQL/Simplifier.h" -#define RETURN(x) {return_value = x; return;} +#define RETURN(x) {_return_value = x; return;} namespace PetriEngine::PQL { Retval simplify(const std::shared_ptr element, SimplificationContext& context) { Simplifier query_simplifier(context); element->visit(query_simplifier); - return std::move(query_simplifier.return_value); + return std::move(query_simplifier._return_value); } AbstractProgramCollection_ptr mergeLps(std::vector &&lps) { @@ -50,7 +50,7 @@ namespace PetriEngine::PQL { std::vector lps, neglpsv; for (const auto &c: element->getOperands()) { c->visit(*this); - auto r = std::move(return_value); + auto r = std::move(_return_value); assert(r.neglps); assert(r.lps); @@ -71,7 +71,7 @@ namespace PetriEngine::PQL { } try { - if (!context.timeout() && !neglps->satisfiable(context)) { + if (!_context.timeout() && !neglps->satisfiable(_context)) { return Retval(BooleanCondition::TRUE_CONSTANT); } } @@ -97,7 +97,7 @@ namespace PetriEngine::PQL { std::vector neglps; for (auto &c: element->getOperands()) { c->visit(*this); - auto r = std::move(return_value); + auto r = std::move(_return_value); if (r.formula->isTriviallyFalse()) { return Retval(BooleanCondition::FALSE_CONSTANT); } else if (r.formula->isTriviallyTrue()) { @@ -116,7 +116,7 @@ namespace PetriEngine::PQL { auto lps = mergeLps(std::move(lpsv)); try { - if (!context.timeout() && !lps->satisfiable(context)) { + if (!_context.timeout() && !lps->satisfiable(_context)) { return Retval(BooleanCondition::FALSE_CONSTANT); } } @@ -137,73 +137,33 @@ namespace PetriEngine::PQL { /************ Auxiliary functions for quantifier simplification ***********/ - Retval Simplifier::simplifyAG(Retval &r) { - if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(context)) { - return Retval(BooleanCondition::TRUE_CONSTANT); - } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(context)) { - return Retval(BooleanCondition::FALSE_CONSTANT); - } else { - return Retval(std::make_shared(r.formula)); - } - } - - Retval Simplifier::simplifyAF(Retval &r) { - if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(context)) { - return Retval(BooleanCondition::TRUE_CONSTANT); - } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(context)) { - return Retval(BooleanCondition::FALSE_CONSTANT); - } else { - return Retval(std::make_shared(r.formula)); - } - } - Retval Simplifier::simplifyAX(Retval &r) { - if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(context)) { + if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(_context)) { return Retval(BooleanCondition::TRUE_CONSTANT); - } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(context)) { + } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(_context)) { return Retval(std::make_shared()); } else { - return Retval(std::make_shared(r.formula)); - } - } - - Retval Simplifier::simplifyEG(Retval &r) { - if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(context)) { - return Retval(BooleanCondition::TRUE_CONSTANT); - } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(context)) { - return Retval(BooleanCondition::FALSE_CONSTANT); - } else { - return Retval(std::make_shared(r.formula)); - } - } - - Retval Simplifier::simplifyEF(Retval &r) { - if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(context)) { - return Retval(BooleanCondition::TRUE_CONSTANT); - } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(context)) { - return Retval(BooleanCondition::FALSE_CONSTANT); - } else { - return Retval(std::make_shared(r.formula)); + return Retval(std::make_shared(std::make_shared(r.formula))); } } Retval Simplifier::simplifyEX(Retval &r) { - if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(context)) { + if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(_context)) { return Retval(std::make_shared( std::make_shared())); - } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(context)) { + } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(_context)) { return Retval(BooleanCondition::FALSE_CONSTANT); } else { - return Retval(std::make_shared(r.formula)); + return Retval(std::make_shared(std::make_shared(r.formula))); } } template Retval Simplifier::simplifySimpleQuant(Retval &r) { static_assert(std::is_base_of_v); - if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(context)) { + if (r.formula->isTriviallyTrue() || !r.neglps->satisfiable(_context)) { return Retval(BooleanCondition::TRUE_CONSTANT); - } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(context)) { + } else if (r.formula->isTriviallyFalse() || !r.lps->satisfiable(_context)) { return Retval(BooleanCondition::FALSE_CONSTANT); } else { return Retval(std::make_shared(r.formula)); @@ -270,22 +230,22 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const NotCondition *element) { - context.negate(); + _context.negate(); element->getCond()->visit(*this); - context.negate(); + _context.negate(); // No return, since it will already be set by visit call } void Simplifier::_accept(const AndCondition *element) { - if (context.timeout()) { - if (context.negated()) { + if (_context.timeout()) { + if (_context.negated()) { RETURN(Retval(std::make_shared(makeAnd(element->getOperands())))) } else { RETURN(Retval(makeAnd(element->getOperands()))) } } - if (context.negated()) { + if (_context.negated()) { RETURN(simplifyOr(element)) } else { RETURN(simplifyAnd(element)) @@ -293,14 +253,14 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const OrCondition *element) { - if (context.timeout()) { - if (context.negated()) { + if (_context.timeout()) { + if (_context.negated()) { RETURN(Retval(std::make_shared(makeOr(element->getOperands())))) } else { RETURN(Retval(makeOr(element->getOperands()))) } } - if (context.negated()) { + if (_context.negated()) { RETURN(simplifyAnd(element)) } else { RETURN(simplifyOr(element)) @@ -308,36 +268,36 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const LessThanCondition *element) { - Member m1 = (*element)[0]->constraint(context); - Member m2 = (*element)[1]->constraint(context); + Member m1 = (*element)[0]->constraint(_context); + Member m2 = (*element)[1]->constraint(_context); AbstractProgramCollection_ptr lps, neglps; - if (!context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { + if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { // test for trivial comparison - Trivial eval = context.negated() ? m1 >= m2 : m1 < m2; + Trivial eval = _context.negated() ? m1 >= m2 : m1 < m2; if (eval != Trivial::Indeterminate) { RETURN(Retval(BooleanCondition::getShared(eval == Trivial::True))) } else { // if no trivial case int constant = m2.constant() - m1.constant(); m1 -= m2; m2 = m1; - lps = std::make_shared(context.cache(), std::move(m1), constant, - (context.negated() ? Simplification::OP_GE - : Simplification::OP_LT)); - neglps = std::make_shared(context.cache(), std::move(m2), constant, - (!context.negated() ? Simplification::OP_GE - : Simplification::OP_LT)); + lps = std::make_shared(_context.cache(), std::move(m1), constant, + (_context.negated() ? Simplification::OP_GE + : Simplification::OP_LT)); + neglps = std::make_shared(_context.cache(), std::move(m2), constant, + (!_context.negated() ? Simplification::OP_GE + : Simplification::OP_LT)); } } else { lps = std::make_shared(); neglps = std::make_shared(); } - if (!context.timeout() && !lps->satisfiable(context)) { + if (!_context.timeout() && !lps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::FALSE_CONSTANT)) - } else if (!context.timeout() && !neglps->satisfiable(context)) { + } else if (!_context.timeout() && !neglps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) } else { - if (context.negated()) { + if (_context.negated()) { RETURN(Retval(std::make_shared((*element)[1], (*element)[0]), std::move(lps), std::move(neglps))) } else { @@ -348,25 +308,25 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const LessThanOrEqualCondition *element) { - Member m1 = (*element)[0]->constraint(context); - Member m2 = (*element)[1]->constraint(context); + Member m1 = (*element)[0]->constraint(_context); + Member m2 = (*element)[1]->constraint(_context); AbstractProgramCollection_ptr lps, neglps; - if (!context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { + if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { // test for trivial comparison - Trivial eval = context.negated() ? m1 > m2 : m1 <= m2; + Trivial eval = _context.negated() ? m1 > m2 : m1 <= m2; if (eval != Trivial::Indeterminate) { RETURN(Retval(BooleanCondition::getShared(eval == Trivial::True))) } else { // if no trivial case int constant = m2.constant() - m1.constant(); m1 -= m2; m2 = m1; - lps = std::make_shared(context.cache(), std::move(m1), constant, - (context.negated() ? Simplification::OP_GT - : Simplification::OP_LE)); - neglps = std::make_shared(context.cache(), std::move(m2), constant, - (context.negated() ? Simplification::OP_LE - : Simplification::OP_GT)); + lps = std::make_shared(_context.cache(), std::move(m1), constant, + (_context.negated() ? Simplification::OP_GT + : Simplification::OP_LE)); + neglps = std::make_shared(_context.cache(), std::move(m2), constant, + (_context.negated() ? Simplification::OP_LE + : Simplification::OP_GT)); } } else { lps = std::make_shared(); @@ -376,12 +336,12 @@ namespace PetriEngine::PQL { assert(lps); assert(neglps); - if (!context.timeout() && !neglps->satisfiable(context)) { + if (!_context.timeout() && !neglps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) - } else if (!context.timeout() && !lps->satisfiable(context)) { + } else if (!_context.timeout() && !lps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::FALSE_CONSTANT)) } else { - if (context.negated()) { + if (_context.negated()) { RETURN(Retval(std::make_shared( (*element)[1], (*element)[0]), std::move(lps), std::move(neglps))) } else { @@ -392,39 +352,39 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const EqualCondition *element) { - Member m1 = (*element)[0]->constraint(context); - Member m2 = (*element)[1]->constraint(context); + Member m1 = (*element)[0]->constraint(_context); + Member m2 = (*element)[1]->constraint(_context); std::shared_ptr lps, neglps; - if (!context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { + if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { if ((m1.isZero() && m2.isZero()) || m1.substrationIsZero(m2)) { RETURN(Retval(BooleanCondition::getShared( - context.negated() ? (m1.constant() != m2.constant()) : (m1.constant() == m2.constant())))) + _context.negated() ? (m1.constant() != m2.constant()) : (m1.constant() == m2.constant())))) } else { int constant = m2.constant() - m1.constant(); m1 -= m2; m2 = m1; neglps = std::make_shared( - std::make_shared(context.cache(), std::move(m1), constant, + std::make_shared(_context.cache(), std::move(m1), constant, Simplification::OP_GT), - std::make_shared(context.cache(), std::move(m2), constant, + std::make_shared(_context.cache(), std::move(m2), constant, Simplification::OP_LT)); Member m3 = m2; - lps = std::make_shared(context.cache(), std::move(m3), constant, Simplification::OP_EQ); + lps = std::make_shared(_context.cache(), std::move(m3), constant, Simplification::OP_EQ); - if (context.negated()) lps.swap(neglps); + if (_context.negated()) lps.swap(neglps); } } else { lps = std::make_shared(); neglps = std::make_shared(); } - if (!context.timeout() && !lps->satisfiable(context)) { + if (!_context.timeout() && !lps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::FALSE_CONSTANT)) - } else if (!context.timeout() && !neglps->satisfiable(context)) { + } else if (!_context.timeout() && !neglps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) } else { - if (context.negated()) { + if (_context.negated()) { RETURN(Retval(std::make_shared((*element)[0], (*element)[1]), std::move(lps), std::move(neglps))) } else { @@ -435,39 +395,39 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const NotEqualCondition *element) { - Member m1 = (*element)[0]->constraint(context); - Member m2 = (*element)[1]->constraint(context); + Member m1 = (*element)[0]->constraint(_context); + Member m2 = (*element)[1]->constraint(_context); std::shared_ptr lps, neglps; - if (!context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { + if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { if ((m1.isZero() && m2.isZero()) || m1.substrationIsZero(m2)) { RETURN(Retval(std::make_shared( - context.negated() ? (m1.constant() == m2.constant()) : (m1.constant() != m2.constant())))) + _context.negated() ? (m1.constant() == m2.constant()) : (m1.constant() != m2.constant())))) } else { int constant = m2.constant() - m1.constant(); m1 -= m2; m2 = m1; lps = std::make_shared( - std::make_shared(context.cache(), std::move(m1), constant, + std::make_shared(_context.cache(), std::move(m1), constant, Simplification::OP_GT), - std::make_shared(context.cache(), std::move(m2), constant, + std::make_shared(_context.cache(), std::move(m2), constant, Simplification::OP_LT)); Member m3 = m2; - neglps = std::make_shared(context.cache(), std::move(m3), constant, + neglps = std::make_shared(_context.cache(), std::move(m3), constant, Simplification::OP_EQ); - if (context.negated()) lps.swap(neglps); + if (_context.negated()) lps.swap(neglps); } } else { lps = std::make_shared(); neglps = std::make_shared(); } - if (!context.timeout() && !lps->satisfiable(context)) { + if (!_context.timeout() && !lps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::FALSE_CONSTANT)) - } else if (!context.timeout() && !neglps->satisfiable(context)) { + } else if (!_context.timeout() && !neglps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) } else { - if (context.negated()) { + if (_context.negated()) { RETURN(Retval(std::make_shared((*element)[0], (*element)[1]), std::move(lps), std::move(neglps))) } else { @@ -478,7 +438,7 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const DeadlockCondition *element) { - if (context.negated()) { + if (_context.negated()) { RETURN(Retval(std::make_shared(DeadlockCondition::DEADLOCK))) } else { RETURN(Retval(DeadlockCondition::DEADLOCK)) @@ -486,16 +446,16 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const CompareConjunction *element) { - if (context.timeout()) { - RETURN(Retval(std::make_shared(*element, context.negated()))) + if (_context.timeout()) { + RETURN(Retval(std::make_shared(*element, _context.negated()))) } std::vector neglps, lpsv; - auto neg = context.negated() != element->isNegated(); + auto neg = _context.negated() != element->isNegated(); std::vector nconstraints; for (auto &c: element->constraints()) { nconstraints.push_back(c); if (c._lower != 0 /*&& !context.timeout()*/ ) { - auto m2 = memberForPlace(c._place, context); + auto m2 = memberForPlace(c._place, _context); Member m1(c._lower); // test for trivial comparison Trivial eval = m1 <= m2; @@ -508,9 +468,9 @@ namespace PetriEngine::PQL { int constant = m2.constant() - m1.constant(); m1 -= m2; m2 = m1; - auto lp = std::make_shared(context.cache(), std::move(m1), constant, + auto lp = std::make_shared(_context.cache(), std::move(m1), constant, Simplification::OP_LE); - auto nlp = std::make_shared(context.cache(), std::move(m2), constant, + auto nlp = std::make_shared(_context.cache(), std::move(m2), constant, Simplification::OP_GT); lpsv.push_back(lp); neglps.push_back(nlp); @@ -518,7 +478,7 @@ namespace PetriEngine::PQL { } if (c._upper != std::numeric_limits::max() /*&& !context.timeout()*/) { - auto m1 = memberForPlace(c._place, context); + auto m1 = memberForPlace(c._place, _context); Member m2(c._upper); // test for trivial comparison Trivial eval = m1 <= m2; @@ -531,9 +491,9 @@ namespace PetriEngine::PQL { int constant = m2.constant() - m1.constant(); m1 -= m2; m2 = m1; - auto lp = std::make_shared(context.cache(), std::move(m1), constant, + auto lp = std::make_shared(_context.cache(), std::move(m1), constant, Simplification::OP_LE); - auto nlp = std::make_shared(context.cache(), std::move(m2), constant, + auto nlp = std::make_shared(_context.cache(), std::move(m2), constant, Simplification::OP_GT); lpsv.push_back(lp); neglps.push_back(nlp); @@ -549,12 +509,12 @@ namespace PetriEngine::PQL { auto lps = mergeLps(std::move(lpsv)); - if (lps == nullptr && !context.timeout()) { + if (lps == nullptr && !_context.timeout()) { RETURN(Retval(BooleanCondition::getShared(!neg))) } try { - if (!context.timeout() && lps && !lps->satisfiable(context)) { + if (!_context.timeout() && lps && !lps->satisfiable(_context)) { RETURN(Retval(BooleanCondition::getShared(neg))) } } @@ -569,7 +529,7 @@ namespace PetriEngine::PQL { // remove trivial rules from neglp int ncnt = neglps.size() - 1; for (int i = nconstraints.size() - 1; i >= 0; --i) { - if (context.timeout()) break; + if (_context.timeout()) break; assert(ncnt >= 0); size_t cnt = 0; auto &c = nconstraints[i]; @@ -577,7 +537,7 @@ namespace PetriEngine::PQL { if (c._upper != std::numeric_limits::max()) ++cnt; for (size_t j = 0; j < cnt; ++j) { assert(ncnt >= 0); - if (!neglps[ncnt]->satisfiable(context)) { + if (!neglps[ncnt]->satisfiable(_context)) { if (j == 1 || c._upper == std::numeric_limits::max()) c._lower = 0; else if (j == 0) @@ -630,7 +590,7 @@ namespace PetriEngine::PQL { } } else { return std::make_shared(std::move(nconstraints), - context.negated() != element->isNegated()); + _context.negated() != element->isNegated()); } }(); @@ -648,7 +608,7 @@ namespace PetriEngine::PQL { for (auto &p: element->places()) places.push_back(p._place); const auto nplaces = element->places().size(); - const auto bounds = LinearProgram::bounds(context, context.getLpTimeout(), places); + const auto bounds = LinearProgram::bounds(_context, _context.getLpTimeout(), places); double offset = element->getOffset(); for (size_t i = 0; i < nplaces; ++i) { if (bounds[i].first != 0 && !bounds[i].second) @@ -667,172 +627,58 @@ namespace PetriEngine::PQL { void Simplifier::_accept(const ControlCondition *condition) { condition->getCond()->visit(*this); - if(return_value.formula->isTriviallyTrue() || return_value.formula->isTriviallyFalse()) + if(_return_value.formula->isTriviallyTrue() || _return_value.formula->isTriviallyFalse()) { - bool is_true = return_value.formula->isTriviallyTrue() xor (!context.negated()); + bool is_true = _return_value.formula->isTriviallyTrue() xor (!_context.negated()); RETURN(Retval(is_true ? Retval(BooleanCondition::TRUE_CONSTANT) : Retval(BooleanCondition::FALSE_CONSTANT))) } else { - RETURN(Retval(std::make_shared(context.negated() ? - std::make_shared(return_value.formula) : - return_value.formula + RETURN(Retval(std::make_shared(_context.negated() ? + std::make_shared(_return_value.formula) : + _return_value.formula ))) } } - void Simplifier::_accept(const EFCondition *condition) { - condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifyAG(return_value) : simplifyEF(return_value)) - } - - void Simplifier::_accept(const EXCondition *condition) { - condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifyAX(return_value) : simplifyEX(return_value)) - } - - void Simplifier::_accept(const AXCondition *condition) { - condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifyEX(return_value) : simplifyAX(return_value)) - } - - void Simplifier::_accept(const AFCondition *condition) { - condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifyEG(return_value) : simplifyAF(return_value)) - } - - void Simplifier::_accept(const EGCondition *condition) { - condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifyAF(return_value) : simplifyEG(return_value)) - } - - void Simplifier::_accept(const AGCondition *condition) { - condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifyEF(return_value) : simplifyAG(return_value)) - } - - void Simplifier::_accept(const EUCondition *condition) { - // cannot push negation any further - bool neg = context.negated(); - context.setNegate(false); - (*condition)[1]->visit(*this); - Retval r2 = std::move(return_value); - if (r2.formula->isTriviallyTrue() || !r2.neglps->satisfiable(context)) { - context.setNegate(neg); - RETURN(neg ? - Retval(BooleanCondition::FALSE_CONSTANT) : - Retval(BooleanCondition::TRUE_CONSTANT)) - } else if (r2.formula->isTriviallyFalse() || !r2.lps->satisfiable(context)) { - context.setNegate(neg); - RETURN(neg ? - Retval(BooleanCondition::TRUE_CONSTANT) : - Retval(BooleanCondition::FALSE_CONSTANT)) - } - (*condition)[0]->visit(*this); - Retval r1 = std::move(return_value); - context.setNegate(neg); - - if (context.negated()) { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(context)) { - RETURN(Retval(std::make_shared( - std::make_shared(r2.formula)))) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(context)) { - RETURN(Retval(std::make_shared(r2.formula))) - } else { - RETURN(Retval(std::make_shared( - std::make_shared(r1.formula, r2.formula)))) - } - } else { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(context)) { - RETURN(Retval(std::make_shared(r2.formula))) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(context)) { - RETURN(std::move(r2)) - } else { - RETURN(Retval(std::make_shared(r1.formula, r2.formula))) - } - } - } - - void Simplifier::_accept(const AUCondition *condition) { - // cannot push negation any further - bool neg = context.negated(); - context.setNegate(false); - condition->getCond2()->visit(*this); - Retval r2 = std::move(return_value); - if (r2.formula->isTriviallyTrue() || !r2.neglps->satisfiable(context)) { - context.setNegate(neg); - RETURN(neg ? - Retval(BooleanCondition::FALSE_CONSTANT) : - Retval(BooleanCondition::TRUE_CONSTANT)) - } else if (r2.formula->isTriviallyFalse() || !r2.lps->satisfiable(context)) { - context.setNegate(neg); - RETURN(neg ? - Retval(BooleanCondition::TRUE_CONSTANT) : - Retval(BooleanCondition::FALSE_CONSTANT)) - } - condition->getCond1()->visit(*this); - Retval r1 = std::move(return_value); - context.setNegate(neg); - - if (context.negated()) { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(context)) { - RETURN(Retval(std::make_shared( - std::make_shared(r2.formula)))) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(context)) { - RETURN(Retval(std::make_shared(r2.formula))) - } else { - RETURN(Retval(std::make_shared( - std::make_shared(r1.formula, r2.formula)))) - } - } else { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(context)) { - RETURN(Retval(std::make_shared(r2.formula))) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(context)) { - RETURN(std::move(r2)) - } else { - RETURN(Retval(std::make_shared(r1.formula, r2.formula))) - } - } - } - void Simplifier::_accept(const UntilCondition *condition) { - bool neg = context.negated(); - context.setNegate(false); + bool neg = _context.negated(); + _context.setNegate(false); condition->getCond2()->visit(*this); - Retval r2 = std::move(return_value); - if (r2.formula->isTriviallyTrue() || !r2.neglps->satisfiable(context)) { - context.setNegate(neg); + Retval r2 = std::move(_return_value); + if (r2.formula->isTriviallyTrue() || !r2.neglps->satisfiable(_context)) { + _context.setNegate(neg); RETURN(neg ? Retval(BooleanCondition::FALSE_CONSTANT) : Retval(BooleanCondition::TRUE_CONSTANT)) - } else if (r2.formula->isTriviallyFalse() || !r2.lps->satisfiable(context)) { - context.setNegate(neg); + } else if (r2.formula->isTriviallyFalse() || !r2.lps->satisfiable(_context)) { + _context.setNegate(neg); RETURN(neg ? Retval(BooleanCondition::TRUE_CONSTANT) : Retval(BooleanCondition::FALSE_CONSTANT)) } condition->getCond1()->visit(*this); - Retval r1 = std::move(return_value); + Retval r1 = std::move(_return_value); - context.setNegate(neg); + _context.setNegate(neg); - if (context.negated()) { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(context)) { + if (_context.negated()) { + if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(_context)) { RETURN(Retval(std::make_shared( std::make_shared(r2.formula)))) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(context)) { + } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(_context)) { RETURN(Retval(std::make_shared(r2.formula))) } else { RETURN(Retval(std::make_shared( std::make_shared(r1.formula, r2.formula)))) } } else { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(context)) { + if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(_context)) { RETURN(Retval(std::make_shared(r2.formula))) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(context)) { + } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(_context)) { RETURN(std::move(r2)) } else { RETURN(Retval(std::make_shared(r1.formula, r2.formula))) @@ -841,38 +687,50 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const ECondition *condition) { - assert(false); - condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifySimpleQuant(return_value) - : simplifySimpleQuant(return_value)) + if (const std::shared_ptr xcond = std::dynamic_pointer_cast((*condition)[0])) { + (*xcond)[0]->visit(*this); + RETURN(simplifyEX(_return_value)); + } + if (const std::shared_ptr ucond = std::dynamic_pointer_cast((*condition)[0])) { + RETURN(simplifyEU(ucond.get())) + } + + RETURN(_context.negated() ? simplifySimpleQuant(_return_value) + : simplifySimpleQuant(_return_value)) } void Simplifier::_accept(const ACondition *condition) { - assert(false); + if (const std::shared_ptr xcond = std::dynamic_pointer_cast((*condition)[0])) { + (*xcond)[0]->visit(*this); + RETURN(simplifyAX(_return_value)) + } + if (const std::shared_ptr ucond = std::dynamic_pointer_cast((*condition)[0])) { + RETURN(simplifyAU(ucond.get())) + } condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifySimpleQuant(return_value) - : simplifySimpleQuant(return_value)) + RETURN(_context.negated() ? simplifySimpleQuant(_return_value) + : simplifySimpleQuant(_return_value)) } void Simplifier::_accept(const FCondition *condition) { condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifySimpleQuant(return_value) - : simplifySimpleQuant(return_value)) + RETURN(_context.negated() ? simplifySimpleQuant(_return_value) + : simplifySimpleQuant(_return_value)) } void Simplifier::_accept(const GCondition *condition) { condition->getCond()->visit(*this); - RETURN(context.negated() ? simplifySimpleQuant(return_value) - : simplifySimpleQuant(return_value)) + RETURN(_context.negated() ? simplifySimpleQuant(_return_value) + : simplifySimpleQuant(_return_value)) } void Simplifier::_accept(const XCondition *condition) { condition->getCond()->visit(*this); - RETURN(simplifySimpleQuant(return_value)) + RETURN(simplifySimpleQuant(_return_value)) } void Simplifier::_accept(const BooleanCondition *condition) { - if (context.negated()) { + if (_context.negated()) { RETURN(Retval(BooleanCondition::getShared(!condition->value))) } else { RETURN(Retval(BooleanCondition::getShared(condition->value))) diff --git a/src/PetriEngine/PQL/XMLPrinter.cpp b/src/PetriEngine/PQL/XMLPrinter.cpp index 9d65ce3d8..9f3db0e2a 100644 --- a/src/PetriEngine/PQL/XMLPrinter.cpp +++ b/src/PetriEngine/PQL/XMLPrinter.cpp @@ -177,84 +177,6 @@ namespace PetriEngine { (*condition)[0]->visit(*this); } - void XMLPrinter::_accept(const EFCondition *condition) { - Tag ep(this, "exists-path"); - { - Tag f(this, "finally"); - condition->getCond()->visit(*this); - } - } - - void XMLPrinter::_accept(const EGCondition *condition) { - Tag ep(this, "exists-path"); - { - Tag g(this, "globally"); - condition->getCond()->visit(*this); - } - } - - void XMLPrinter::_accept(const AGCondition *condition) { - Tag a(this, "all-paths"); - { - Tag g(this, "globally"); - condition->getCond()->visit(*this); - } - } - - void XMLPrinter::_accept(const AFCondition *condition) { - Tag a(this, "all-paths"); - { - Tag f(this, "finally"); - condition->getCond()->visit(*this); - } - } - - void XMLPrinter::_accept(const EXCondition *condition) { - Tag e(this, "exists-path"); - { - Tag n(this, "next"); - condition->getCond()->visit(*this); - } - } - - void XMLPrinter::_accept(const AXCondition *condition) { - Tag a(this, "all-paths"); - { - Tag e(this, "next"); - condition->getCond()->visit(*this); - } - } - - void XMLPrinter::_accept(const EUCondition *condition) { - Tag e(this, "exists-path"); - { - Tag u(this, "until"); - { - Tag b(this, "before"); - (*condition)[0]->visit(*this); - } - { - Tag r(this, "reach"); - (*condition)[1]->visit(*this); - } - } - } - - void XMLPrinter::_accept(const AUCondition *condition) { - Tag e(this, "all-paths"); - { - Tag u(this, "until"); - { - Tag b(this, "before"); - (*condition)[0]->visit(*this); - } - { - Tag r(this, "reach"); - (*condition)[1]->visit(*this); - } - } - } - void XMLPrinter::_accept(const ACondition *condition) { Tag a(this, "all-paths"); condition->getCond()->visit(*this); diff --git a/src/PetriEngine/Synthesis/SimpleSynthesis.cpp b/src/PetriEngine/Synthesis/SimpleSynthesis.cpp index e207e4b2e..1631da5ae 100644 --- a/src/PetriEngine/Synthesis/SimpleSynthesis.cpp +++ b/src/PetriEngine/Synthesis/SimpleSynthesis.cpp @@ -57,10 +57,6 @@ namespace PetriEngine { } else if (auto p = dynamic_cast ((*a)[0].get())) { return {true, (*p)[0].get()}; } - } else if (auto a = dynamic_cast (condition)) { - return {true, (*a)[0].get()}; - } else if (auto a = dynamic_cast (condition)) { - return {false, (*a)[0].get()}; } throw base_error("Only AF and AG propositions supported for synthesis"); } diff --git a/src/VerifyPN.cpp b/src/VerifyPN.cpp index cd473c224..b425cbb07 100644 --- a/src/VerifyPN.cpp +++ b/src/VerifyPN.cpp @@ -153,7 +153,7 @@ readQueries(options_t& options, std::vector& qstrings) { return conditions; } else { // state-space exploration qstrings.push_back("statespace-search"); - conditions.push_back(std::make_shared(BooleanCondition::FALSE_CONSTANT)); + conditions.push_back(std::make_shared(std::make_shared(BooleanCondition::FALSE_CONSTANT))); return conditions; } } @@ -252,11 +252,9 @@ std::vector getCTLQueries(const std::vector& ctlSt IsCTLVisitor isCtlVisitor; ctlStarQuery->visit(isCtlVisitor); if (isCtlVisitor.isCTL) { - AsCTL asCtl; - ctlStarQuery->visit(asCtl); - ctlQueries.push_back(asCtl._ctl_query); + ctlQueries.push_back(ctlStarQuery); } else { - throw base_error("A query could not be translated from CTL* to CTL."); + throw base_error("A CTL* query could not be interpreted as CTL."); } } From def62dbbadd46fd9780487e1b2d07774b8ccafe6 Mon Sep 17 00:00:00 2001 From: Ragusaen Date: Mon, 21 Feb 2022 15:45:33 +0100 Subject: [PATCH 04/41] Fixed some bugs after removing CTL quants --- include/PetriEngine/PQL/Evaluation.h | 16 - include/PetriEngine/PQL/Expressions.h | 14 +- include/PetriEngine/PQL/PlaceUseVisitor.h | 2 + include/PetriEngine/PQL/PushNegation.h | 16 + src/CTL/Algorithm/CertainZeroFPA.cpp | 8 + src/CTL/PetriNets/OnTheFlyDG.cpp | 65 ++-- src/LTL/Algorithm/LTLToBuchi.cpp | 44 --- src/PetriEngine/PQL/Analyze.cpp | 18 +- src/PetriEngine/PQL/Evaluation.cpp | 13 +- src/PetriEngine/PQL/Expressions.cpp | 71 ++-- src/PetriEngine/PQL/PlaceUseVisitor.cpp | 18 +- src/PetriEngine/PQL/PredicateCheckers.cpp | 26 +- src/PetriEngine/PQL/PushNegation.cpp | 307 +++++++++++------- .../Reachability/ResultPrinter.cpp | 7 +- src/PetriEngine/options.cpp | 1 + src/PetriParse/QueryBinaryParser.cpp | 16 +- src/PetriParse/QueryXMLParser.cpp | 8 +- src/VerifyPN.cpp | 17 +- src/main.cpp | 1 + 19 files changed, 353 insertions(+), 315 deletions(-) diff --git a/include/PetriEngine/PQL/Evaluation.h b/include/PetriEngine/PQL/Evaluation.h index 3ad90ecda..727ad5f5a 100644 --- a/include/PetriEngine/PQL/Evaluation.h +++ b/include/PetriEngine/PQL/Evaluation.h @@ -72,16 +72,8 @@ namespace PetriEngine { namespace PQL { private: void _accept(SimpleQuantifierCondition *element) override; - void _accept(EGCondition *element) override; - - void _accept(AGCondition *element) override; - void _accept(ControlCondition *element) override; - void _accept(EFCondition *element) override; - - void _accept(AFCondition *element) override; - void _accept(ACondition *element) override; void _accept(ECondition *element) override; @@ -133,14 +125,6 @@ namespace PetriEngine { namespace PQL { void _accept(FCondition *element) override; - void _accept(EGCondition *element) override; - - void _accept(AGCondition *element) override; - - void _accept(EFCondition *element) override; - - void _accept(AFCondition *element) override; - void _accept(UntilCondition *element) override; void _accept(AndCondition *element) override; diff --git a/include/PetriEngine/PQL/Expressions.h b/include/PetriEngine/PQL/Expressions.h index 219be180b..098d85d5c 100644 --- a/include/PetriEngine/PQL/Expressions.h +++ b/include/PetriEngine/PQL/Expressions.h @@ -426,11 +426,8 @@ namespace PetriEngine { using SimpleQuantifierCondition::SimpleQuantifierCondition; Quantifier getQuantifier() const override { return Quantifier::E; } - Path getPath() const override { return Path::pError; } - uint32_t distance(DistanceContext& context) const override { - // TODO implement - assert(false); throw base_error("TODO implement"); - } + Path getPath() const override { return _cond->getPath(); } + uint32_t distance(DistanceContext& context) const override; virtual type_id_t type() const { return PQL::type_id(); }; }; @@ -440,11 +437,8 @@ namespace PetriEngine { Quantifier getQuantifier() const override { return Quantifier::A; } - Path getPath() const override { return Path::pError; } - uint32_t distance(DistanceContext& context) const override { - uint32_t retval = _cond->distance(context); - return retval; - } + Path getPath() const override { return _cond->getPath(); } + uint32_t distance(DistanceContext& context) const override; virtual type_id_t type() const { return PQL::type_id(); }; }; diff --git a/include/PetriEngine/PQL/PlaceUseVisitor.h b/include/PetriEngine/PQL/PlaceUseVisitor.h index 872517556..4f43eb260 100644 --- a/include/PetriEngine/PQL/PlaceUseVisitor.h +++ b/include/PetriEngine/PQL/PlaceUseVisitor.h @@ -49,6 +49,8 @@ namespace PQL { virtual void _accept(const DeadlockCondition* element) override; virtual void _accept(const CompareConjunction* element) override; virtual void _accept(const UnfoldedUpperBoundsCondition* element) override; + virtual void _accept(const SimpleQuantifierCondition *element) override; + virtual void _accept(const UntilCondition *element) override; private: void visitCommutativeExpr(const CommutativeExpr* element); diff --git a/include/PetriEngine/PQL/PushNegation.h b/include/PetriEngine/PQL/PushNegation.h index f22816ccc..1d9f59347 100644 --- a/include/PetriEngine/PQL/PushNegation.h +++ b/include/PetriEngine/PQL/PushNegation.h @@ -110,6 +110,22 @@ namespace PetriEngine::PQL { void _accept(QuasiLivenessCondition* element) override; void _accept(StableMarkingCondition* element) override; + + Condition_ptr pushneg_EG(GCondition *element); + + Condition_ptr pushneg_AG(GCondition *element); + + Condition_ptr pushneg_EX(XCondition *element); + + Condition_ptr pushneg_AX(XCondition *element); + + Condition_ptr pushneg_EF(FCondition *element); + + Condition_ptr pushneg_AU(UntilCondition *element); + + Condition_ptr pushneg_AF(FCondition *element); + + Condition_ptr pushneg_EU(UntilCondition *element); }; } diff --git a/src/CTL/Algorithm/CertainZeroFPA.cpp b/src/CTL/Algorithm/CertainZeroFPA.cpp index 249b7e91a..ba7ad61d3 100644 --- a/src/CTL/Algorithm/CertainZeroFPA.cpp +++ b/src/CTL/Algorithm/CertainZeroFPA.cpp @@ -1,4 +1,6 @@ #include "CTL/Algorithm/CertainZeroFPA.h" +#include "CTL/PetriNets/PetriConfig.h" +#include "PetriEngine/PQL/CTLVisitor.h" #include #include @@ -249,6 +251,12 @@ void Algorithm::CertainZeroFPA::explore(Configuration *c) assert(succ->refcnt <= 1); if(succ->refcnt > 0) { +// for (auto& a : succ->targets) { +// auto b = (PetriNets::PetriConfig*) a; +// PetriEngine::PQL::IsCTLVisitor isCtlVisitor; +// PetriEngine::PQL::Visitor::visit(isCtlVisitor, b->query); +// std::cout << isCtlVisitor.isCTL << " "; b->query->toString(std::cout); std::cout << std::endl; +// } strategy->pushEdge(succ); --succ->refcnt; if(succ->refcnt == 0) graph->release(succ); diff --git a/src/CTL/PetriNets/OnTheFlyDG.cpp b/src/CTL/PetriNets/OnTheFlyDG.cpp index 9d68ab8b2..26753a2b0 100644 --- a/src/CTL/PetriNets/OnTheFlyDG.cpp +++ b/src/CTL/PetriNets/OnTheFlyDG.cpp @@ -66,6 +66,9 @@ std::vector OnTheFlyDG::successors(Configuration *c) // v->printConfiguration(); std::vector succs; auto query_type = v->query->getQueryType(); + + v->query->toString(std::cout); std::cout << std::endl; + if(query_type == EVAL){ assert(false); //assert(false && "Someone told me, this was a bad place to be."); @@ -147,8 +150,10 @@ std::vector OnTheFlyDG::successors(Configuration *c) } else if (query_type == PATHQEURY){ if(v->query->getQuantifier() == A){ - if (v->query->getPath() == U){ - auto cond = static_cast((*static_cast(v->query))[0].get()); + auto acond = static_cast(v->query); + auto path_cond = (*acond)[0]; + if (path_cond->getPath() == U){ + auto cond = static_cast(path_cond.get()); Edge *right = NULL; auto r1 = fastEval((*cond)[1], &query_marking); if (r1 != Condition::RUNKNOWN){ @@ -177,10 +182,10 @@ std::vector OnTheFlyDG::successors(Configuration *c) if (valid || left != NULL) { //if left side is guaranteed to be not satisfied, skip successor generation Edge* leftEdge = NULL; - nextStates (query_marking, cond, + nextStates (query_marking, acond, [&](){ leftEdge = newEdge(*v, std::numeric_limits::max());}, [&](Marking& mark){ - auto res = fastEval(cond, &mark); + auto res = fastEval(acond, &mark); if(res == Condition::RTRUE) return true; if(res == Condition::RFALSE) { @@ -190,7 +195,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) return false; } context.setMarking(mark.marking()); - Configuration* c = createConfiguration(createMarking(mark), owner(mark, cond), cond); + Configuration* c = createConfiguration(createMarking(mark), owner(mark, acond), acond); leftEdge->addTarget(c); return true; }, @@ -211,8 +216,8 @@ std::vector OnTheFlyDG::successors(Configuration *c) succs.push_back(right); } } - else if(v->query->getPath() == F){ - auto cond = static_cast((*static_cast(v->query))[0].get()); + else if(path_cond->getPath() == F){ + auto cond = static_cast(path_cond.get()); Edge *subquery = NULL; auto r = fastEval((*cond)[0], &query_marking); if (r != Condition::RUNKNOWN) { @@ -227,11 +232,11 @@ std::vector OnTheFlyDG::successors(Configuration *c) subquery->addTarget(c); } Edge* e1 = NULL; - nextStates(query_marking, cond, + nextStates(query_marking, acond, [&](){e1 = newEdge(*v, std::numeric_limits::max());}, [&](Marking& mark) { - auto res = fastEval(cond, &mark); + auto res = fastEval(acond, &mark); if(res == Condition::RTRUE) return true; if(res == Condition::RFALSE) { @@ -245,7 +250,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) return false; } context.setMarking(mark.marking()); - Configuration* c = createConfiguration(createMarking(mark), owner(mark, cond), cond); + Configuration* c = createConfiguration(createMarking(mark), owner(mark, acond), acond); e1->addTarget(c); return true; }, @@ -259,11 +264,11 @@ std::vector OnTheFlyDG::successors(Configuration *c) succs.push_back(subquery); } } - else if(v->query->getPath() == X){ - auto cond = static_cast((*static_cast(v->query))[0].get()); + else if(path_cond->getPath() == X){ + auto cond = static_cast(path_cond.get()); Edge* e = newEdge(*v, std::numeric_limits::max()); Condition::Result allValid = Condition::RTRUE; - nextStates(query_marking, cond, + nextStates(query_marking, acond, [](){}, [&](Marking& mark){ auto res = fastEval((*cond)[0], &mark); @@ -298,15 +303,17 @@ std::vector OnTheFlyDG::successors(Configuration *c) { } } - else if(v->query->getPath() == G ){ + else if(path_cond->getPath() == G ){ assert(false && "Path operator G had not been translated - Parse error detected in succ()"); } else assert(false && "An unknown error occoured in the successor generator"); } else if(v->query->getQuantifier() == E){ - if (v->query->getPath() == U){ - auto cond = static_cast((*static_cast(v->query))[0].get()); + auto econd = static_cast(v->query); + auto path_cond = (*econd)[0]; + if (path_cond->getPath() == U){ + auto cond = static_cast(path_cond.get()); Edge *right = NULL; auto r1 = fastEval((*cond)[1], &query_marking); if (r1 == Condition::RUNKNOWN) { @@ -324,7 +331,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) Configuration *left = NULL; bool valid = false; - nextStates(query_marking, cond, + nextStates(query_marking, econd, [&](){ auto r0 = fastEval((*cond)[0], &query_marking); if (r0 == Condition::RUNKNOWN) { @@ -335,7 +342,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) }, [&](Marking& marking){ if(left == NULL && !valid) return false; - auto res = fastEval(cond, &marking); + auto res = fastEval(econd, &marking); if(res == Condition::RFALSE) return true; if(res == Condition::RTRUE) { @@ -358,7 +365,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) } context.setMarking(marking.marking()); Edge* e = newEdge(*v, /*cond->distance(context)*/0); - Configuration* c1 = createConfiguration(createMarking(marking), owner(marking, cond), cond); + Configuration* c1 = createConfiguration(createMarking(marking), owner(marking, econd), econd); e->addTarget(c1); if (left != NULL) { e->addTarget(left); @@ -371,8 +378,8 @@ std::vector OnTheFlyDG::successors(Configuration *c) succs.push_back(right); } } - else if(v->query->getPath() == F){ - auto cond = static_cast((*static_cast(v->query))[0].get()); + else if(path_cond->getPath() == F){ + auto cond = static_cast(path_cond.get()); Edge *subquery = NULL; auto r = fastEval((*cond)[0], &query_marking); if (r != Condition::RUNKNOWN) { @@ -387,10 +394,10 @@ std::vector OnTheFlyDG::successors(Configuration *c) subquery->addTarget(c); } - nextStates(query_marking, cond, + nextStates(query_marking, econd, [](){}, [&](Marking& mark){ - auto res = fastEval(cond, &mark); + auto res = fastEval(econd, &mark); if(res == Condition::RFALSE) return true; if(res == Condition::RTRUE) { @@ -407,7 +414,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) } context.setMarking(mark.marking()); Edge* e = newEdge(*v, /*cond->distance(context)*/0); - Configuration* c = createConfiguration(createMarking(mark), owner(mark, cond), cond); + Configuration* c = createConfiguration(createMarking(mark), owner(mark, econd), econd); e->addTarget(c); succs.push_back(e); return true; @@ -419,10 +426,10 @@ std::vector OnTheFlyDG::successors(Configuration *c) succs.push_back(subquery); } } - else if(v->query->getPath() == X){ - auto cond = static_cast((*static_cast(v->query))[0].get()); + else if(path_cond->getPath() == X){ + auto cond = static_cast(path_cond.get()); auto query = (*cond)[0]; - nextStates(query_marking, cond, + nextStates(query_marking, econd, [](){}, [&](Marking& marking) { auto res = fastEval(query, &marking); @@ -446,7 +453,7 @@ std::vector OnTheFlyDG::successors(Configuration *c) [](){} ); } - else if(v->query->getPath() == G ){ + else if(path_cond->getPath() == G ){ assert(false && "Path operator G had not been translated - Parse error detected in succ()"); } else @@ -486,7 +493,7 @@ void OnTheFlyDG::nextStates(Marking& t_marking, Condition* ptr, { bool first = true; memcpy(working_marking.marking(), query_marking.marking(), n_places*sizeof(PetriEngine::MarkVal)); - auto qf = static_cast(ptr); + auto qf = static_cast((*static_cast(ptr))[0].get()); if(!_partial_order || ptr->getQuantifier() != E || ptr->getPath() != F || PetriEngine::PQL::isTemporal((*qf)[0])) { PetriEngine::SuccessorGenerator PNGen(*net); diff --git a/src/LTL/Algorithm/LTLToBuchi.cpp b/src/LTL/Algorithm/LTLToBuchi.cpp index d3c244a3c..58903d9b6 100644 --- a/src/LTL/Algorithm/LTLToBuchi.cpp +++ b/src/LTL/Algorithm/LTLToBuchi.cpp @@ -63,46 +63,16 @@ namespace LTL { _formula = spot::formula::X(_formula); } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::EXCondition *element) { - Visitor::visit(this, (*element)[0]); - _formula = spot::formula::X(_formula); - } - - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::AXCondition *element) { - Visitor::visit(this, (*element)[0]); - _formula = spot::formula::X(_formula); - } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::FCondition *element) { Visitor::visit(this, (*element)[0]); _formula = spot::formula::F(_formula); } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::EFCondition *element) { - Visitor::visit(this, (*element)[0]); - _formula = spot::formula::F(_formula); - } - - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::AFCondition *element) { - Visitor::visit(this, (*element)[0]); - _formula = spot::formula::F(_formula); - } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::GCondition *element) { Visitor::visit(this, (*element)[0]); _formula = spot::formula::G(_formula); } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::EGCondition *element) { - Visitor::visit(this, (*element)[0]); - _formula = spot::formula::G(_formula); - } - - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::AGCondition *element) { - Visitor::visit(this, (*element)[0]); - _formula = spot::formula::G(_formula); - } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::UntilCondition *element) { Visitor::visit(this, (*element)[0]); auto lhs = _formula; @@ -110,20 +80,6 @@ namespace LTL { _formula = spot::formula::U(lhs, _formula); } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::AUCondition *element) { - Visitor::visit(this, (*element)[0]); - auto lhs = _formula; - Visitor::visit(this, (*element)[1]); - _formula = spot::formula::U(lhs, _formula); - } - - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::EUCondition *element) { - Visitor::visit(this, (*element)[0]); - auto lhs = _formula; - Visitor::visit(this, (*element)[1]); - _formula = spot::formula::U(lhs, _formula); - } - void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::LessThanCondition *element) { _formula = make_atomic_prop(std::make_shared(*element)); } diff --git a/src/PetriEngine/PQL/Analyze.cpp b/src/PetriEngine/PQL/Analyze.cpp index b5f910afd..55e22a529 100644 --- a/src/PetriEngine/PQL/Analyze.cpp +++ b/src/PetriEngine/PQL/Analyze.cpp @@ -257,7 +257,7 @@ namespace PetriEngine::PQL { for(auto& p : _context.allPlaceNames()) k_safe.emplace_back(std::make_shared(std::make_shared(p.first), element->_bound)); } - element->_compiled = std::make_shared(std::make_shared(std::move(k_safe))); + element->_compiled = std::make_shared(std::make_shared(std::make_shared(std::move(k_safe)))); Visitor::visit(this, element->_compiled); } @@ -278,14 +278,14 @@ namespace PetriEngine::PQL { std::vector disj; for(auto& tn : n.second) disj.emplace_back(std::make_shared(tn)); - quasi.emplace_back(std::make_shared(std::make_shared(std::move(disj)))); + quasi.emplace_back(std::make_shared(std::make_shared(std::make_shared(std::move(disj))))); } } else { for(auto& n : _context.allTransitionNames()) { - quasi.emplace_back(std::make_shared(std::make_shared(n.first))); + quasi.emplace_back(std::make_shared(std::make_shared(std::make_shared(n.first)))); } } element->_compiled = std::make_shared(std::move(quasi)); @@ -304,14 +304,14 @@ namespace PetriEngine::PQL { std::vector disj; for(auto& tn : n.second) disj.emplace_back(std::make_shared(tn)); - liveness.emplace_back(std::make_shared(std::make_shared(std::make_shared(std::move(disj))))); + liveness.emplace_back(std::make_shared(std::make_shared(std::make_shared(std::make_shared(std::make_shared(std::move(disj))))))); } } else { for(auto& n : _context.allTransitionNames()) { - liveness.emplace_back(std::make_shared(std::make_shared(std::make_shared(n.first)))); + liveness.emplace_back(std::make_shared(std::make_shared(std::make_shared(std::make_shared(std::make_shared(n.first)))))); } } element->_compiled = std::make_shared(std::move(liveness)); @@ -337,9 +337,9 @@ namespace PetriEngine::PQL { sum.emplace_back(std::move(id)); } - stable_check.emplace_back(std::make_shared(std::make_shared( + stable_check.emplace_back(std::make_shared(std::make_shared(std::make_shared( std::make_shared(std::move(sum)), - std::make_shared(init_marking)))); + std::make_shared(init_marking))))); } } else @@ -347,9 +347,9 @@ namespace PetriEngine::PQL { size_t i = 0; for(auto& p : _context.net()->placeNames()) { - stable_check.emplace_back(std::make_shared(std::make_shared( + stable_check.emplace_back(std::make_shared(std::make_shared(std::make_shared( std::make_shared(p, i), - std::make_shared(_context.net()->initial(i))))); + std::make_shared(_context.net()->initial(i)))))); ++i; } } diff --git a/src/PetriEngine/PQL/Evaluation.cpp b/src/PetriEngine/PQL/Evaluation.cpp index e1d0089e9..070a31a4a 100644 --- a/src/PetriEngine/PQL/Evaluation.cpp +++ b/src/PetriEngine/PQL/Evaluation.cpp @@ -124,13 +124,21 @@ namespace PetriEngine { namespace PQL { } void EvaluateVisitor::_accept(ACondition *element) { - Visitor::visit(this, (*element)[0]); + auto cond = (*element)[0]; + Visitor::visit(this, cond); + if (cond->type() == type_id() || cond->type() == type_id() || cond->type() == type_id()) + return; + if (_return_value == Condition::RFALSE) _return_value = {Condition::RFALSE}; else _return_value = {Condition::RUNKNOWN}; } void EvaluateVisitor::_accept(ECondition *element) { - Visitor::visit(this, (*element)[0]); + auto cond = (*element)[0]; + Visitor::visit(this, cond); + if (cond->type() == type_id() || cond->type() == type_id() || cond->type() == type_id()) + return; + if (_return_value == Condition::RTRUE) _return_value = {Condition::RTRUE}; else _return_value = {Condition::RUNKNOWN}; } @@ -147,7 +155,6 @@ namespace PetriEngine { namespace PQL { else _return_value = {Condition::RUNKNOWN}; } - void EvaluateVisitor::_accept(UntilCondition *element) { Visitor::visit(this, (*element)[1]); if (_return_value != Condition::RFALSE) diff --git a/src/PetriEngine/PQL/Expressions.cpp b/src/PetriEngine/PQL/Expressions.cpp index d8e522a26..ad2fff7dd 100644 --- a/src/PetriEngine/PQL/Expressions.cpp +++ b/src/PetriEngine/PQL/Expressions.cpp @@ -329,49 +329,34 @@ namespace PetriEngine { return _max - tmp; } - uint32_t EFCondition::distance(DistanceContext& context) const { - return _cond->distance(context); - } - - uint32_t EGCondition::distance(DistanceContext& context) const { - return _cond->distance(context); - } - - uint32_t EXCondition::distance(DistanceContext& context) const { - return _cond->distance(context); - } - - uint32_t EUCondition::distance(DistanceContext& context) const { - return _cond2->distance(context); - } - - uint32_t AFCondition::distance(DistanceContext& context) const { - context.negate(); - uint32_t retval = _cond->distance(context); - context.negate(); - return retval; - } - - uint32_t AXCondition::distance(DistanceContext& context) const { - context.negate(); - uint32_t retval = _cond->distance(context); - context.negate(); - return retval; - } - - uint32_t AGCondition::distance(DistanceContext& context) const { - context.negate(); - uint32_t retval = _cond->distance(context); - context.negate(); - return retval; + uint32_t ACondition::distance(DistanceContext &context) const { + auto cond = (*this)[0].get(); + uint32_t res; + if (cond->type() == type_id()) { + auto ucond = static_cast(cond); + context.negate(); + res = (*ucond)[0]->distance(context) + (*ucond)[0]->distance(context); + context.negate(); + } else if (cond->type() == type_id()) { + context.negate(); + res = static_cast(cond)->distance(context); + context.negate(); + } else if (cond->type() == type_id()) { + context.negate(); + res = static_cast(cond)->distance(context); + context.negate(); + } else if (cond->type() == type_id()) { + context.negate(); + res = static_cast(cond)->distance(context); + context.negate(); + } else { + res = cond->distance(context); + } + return res; } - uint32_t AUCondition::distance(DistanceContext& context) const { - context.negate(); - auto r1 = _cond1->distance(context); - auto r2 = _cond2->distance(context); - context.negate(); - return r1 + r2; + uint32_t ECondition::distance(DistanceContext& context) const { + return (*this)[0]->distance(context); } uint32_t CompareConjunction::distance(DistanceContext& context) const { @@ -435,6 +420,7 @@ namespace PetriEngine { return conjDistance(context, _conds); } + uint32_t OrCondition::distance(DistanceContext& context) const { if(context.negated()) return conjDistance(context, _conds); @@ -442,7 +428,6 @@ namespace PetriEngine { return disjDistance(context, _conds); } - struct S { int d; unsigned int p; @@ -499,13 +484,13 @@ namespace PetriEngine { postMerge(_conds); } + OrCondition::OrCondition(Condition_ptr left, Condition_ptr right) { tryMerge(_conds, left); tryMerge(_conds, right); postMerge(_conds); } - CompareConjunction::CompareConjunction(const std::vector& conditions, bool negated) { _negated = negated; diff --git a/src/PetriEngine/PQL/PlaceUseVisitor.cpp b/src/PetriEngine/PQL/PlaceUseVisitor.cpp index 422277c82..6012a81ea 100644 --- a/src/PetriEngine/PQL/PlaceUseVisitor.cpp +++ b/src/PetriEngine/PQL/PlaceUseVisitor.cpp @@ -107,24 +107,18 @@ namespace PQL { _in_use[p._place] = true; } - void PlaceUseVisitor::_accept(const EUCondition* el) + void PlaceUseVisitor::_accept(const UntilCondition* element) { - Visitor::visit(this, (*el)[0]); - Visitor::visit(this, (*el)[1]); + Visitor::visit(this, (*element)[0]); + Visitor::visit(this, (*element)[1]); } - void PlaceUseVisitor::_accept(const AUCondition* el) + + void PlaceUseVisitor::_accept(const SimpleQuantifierCondition* element) { - Visitor::visit(this, (*el)[0]); - Visitor::visit(this, (*el)[1]); + Visitor::visit(this, (*element)[0]); } - void PlaceUseVisitor::_accept(const EFCondition* el) { Visitor::visit(this, (*el)[0]); } - void PlaceUseVisitor::_accept(const EGCondition* el) { Visitor::visit(this, (*el)[0]); } - void PlaceUseVisitor::_accept(const AGCondition* el) { Visitor::visit(this, (*el)[0]); } - void PlaceUseVisitor::_accept(const AFCondition* el) { Visitor::visit(this, (*el)[0]); } - void PlaceUseVisitor::_accept(const EXCondition* el) { Visitor::visit(this, (*el)[0]); } - void PlaceUseVisitor::_accept(const AXCondition* el) { Visitor::visit(this, (*el)[0]); } // shallow elements, neither of these should exist in a compiled expression void PlaceUseVisitor::_accept(const LiteralExpr* element) {} diff --git a/src/PetriEngine/PQL/PredicateCheckers.cpp b/src/PetriEngine/PQL/PredicateCheckers.cpp index ef5f9e97f..2693626d9 100644 --- a/src/PetriEngine/PQL/PredicateCheckers.cpp +++ b/src/PetriEngine/PQL/PredicateCheckers.cpp @@ -89,29 +89,10 @@ namespace PetriEngine::PQL { setConditionFound(); } - void IsNotReachabilityVisitor::_accept(const EFCondition *element) { - if (!_is_nested) { - _is_nested = true; - Visitor::visit(this, element->getCond()); - _is_nested = false; - } else { - setConditionFound(); - } - } - - void IsNotReachabilityVisitor ::_accept(const AGCondition *element) { - if (!_is_nested) { - _is_nested = true; - Visitor::visit(this, element->getCond()); - _is_nested = false; - } else { - setConditionFound(); - } - } - void IsNotReachabilityVisitor::_accept(const ECondition *element) { if (!_is_nested) { - if (auto cond = dynamic_cast(element->getCond().get())) { + if ((*element)[0]->type() == type_id()) { + auto cond = static_cast(element->getCond().get()); _is_nested = true; Visitor::visit(this, cond->getCond()); _is_nested = false; @@ -125,7 +106,8 @@ namespace PetriEngine::PQL { void IsNotReachabilityVisitor::_accept(const ACondition *element) { if (!_is_nested) { - if (auto cond = dynamic_cast(element->getCond().get())) { + if ((*element)[0]->type() == type_id()) { + auto cond = static_cast(element->getCond().get()); _is_nested = true; Visitor::visit(this, cond->getCond()); _is_nested = false; diff --git a/src/PetriEngine/PQL/PushNegation.cpp b/src/PetriEngine/PQL/PushNegation.cpp index ec555744c..cca992ff4 100644 --- a/src/PetriEngine/PQL/PushNegation.cpp +++ b/src/PetriEngine/PQL/PushNegation.cpp @@ -22,6 +22,7 @@ #include "PetriEngine/PQL/PredicateCheckers.h" #include "PetriEngine/PQL/Expressions.h" #include "PetriEngine/PQL/Evaluation.h" +#include "PetriEngine/PQL/CTLVisitor.h" // Macro to ensure that returns are done correctly @@ -43,8 +44,9 @@ namespace PetriEngine::PQL { { if(res->getQuantifier() == E && res->getPath() == F) { - auto ef = static_cast(res.get()); - if(dynamic_cast((*ef)[0].get())) + auto e = static_cast(res.get()); + auto f = static_cast((*e)[0].get()); + if((*f)[0]->type() == type_id()) { return res; } @@ -107,24 +109,24 @@ namespace PetriEngine::PQL { return_value = std::make_shared(res); } - void PushNegationVisitor::_accept(EGCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_EG(GCondition *element) { ++stats[0]; - auto af_cond = AFCondition(std::make_shared(element->getCond())); - RETURN(subvisit(&af_cond, nested, !negated)) + auto af_cond = std::make_shared(std::make_shared(std::make_shared(element->getCond()))); + return subvisit(af_cond, nested, !negated); } - void PushNegationVisitor::_accept(AGCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_AG(GCondition *element) { ++stats[1]; - auto ef_cond = EFCondition(std::make_shared(element->getCond())); - RETURN(subvisit(&ef_cond, nested, !negated)) + auto ef_cond = std::make_shared(std::make_shared(std::make_shared(element->getCond()))); + return subvisit(ef_cond, nested, !negated); } - void PushNegationVisitor::_accept(EXCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_EX(XCondition *element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { auto a = subvisit(element->getCond(), true, negated); if (negated) { ++stats[2]; - return subvisit(std::make_unique(a), nested, false); + return subvisit(std::make_shared(std::make_shared(a)), nested, false); } else { if (a == BooleanCondition::FALSE_CONSTANT) { ++stats[3]; @@ -134,19 +136,19 @@ namespace PetriEngine::PQL { ++stats[4]; return std::make_shared(DeadlockCondition::DEADLOCK); } - a = std::make_shared(a); + a = std::make_shared(std::make_shared(a)); } return a; }, stats, context, nested, negated, initrw); - RETURN(cond) + return cond; } - void PushNegationVisitor::_accept(AXCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_AX(XCondition *element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { auto a = subvisit(element->getCond(), true, negated); if (negated) { ++stats[5]; - return subvisit(std::make_shared(a), nested, false); + return subvisit(std::make_shared(std::make_shared(a)), nested, false); } else { if (a == BooleanCondition::TRUE_CONSTANT) { ++stats[6]; @@ -156,94 +158,124 @@ namespace PetriEngine::PQL { ++stats[7]; return DeadlockCondition::DEADLOCK; } - a = std::make_shared(a); + a = std::make_shared(std::make_shared(a)); } return a; }, stats, context, nested, negated, initrw); - RETURN(cond) + return cond; } - void PushNegationVisitor::_accept(EFCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_EF(FCondition *element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { auto a = subvisit(element->getCond(), true, false); - if (auto cond = dynamic_cast(a.get())) { - if ((*cond)[0] == DeadlockCondition::DEADLOCK) { + if (a->type() == type_id()) { + auto notcond = static_cast(a.get()); + if ((*notcond)[0] == DeadlockCondition::DEADLOCK) { ++stats[8]; return subvisit(a, nested, negated); } } if (!isTemporal(a)) { - auto res = std::make_shared(a); + auto res = std::make_shared(std::make_shared(a)); if (negated) return std::make_shared(res); return res; } - if (dynamic_cast(a.get())) { - ++stats[9]; - if (negated) a = std::make_shared(a); - return a; - } else if (auto cond = dynamic_cast(a.get())) { - ++stats[10]; - a = subvisit(std::make_shared((*cond)[0]), nested, negated); - return a; - } else if (auto cond = dynamic_cast(a.get())) { - ++stats[11]; - a = subvisit(std::make_shared((*cond)[1]), nested, negated); - return a; - } else if (auto cond = dynamic_cast(a.get())) { - ++stats[12]; - a = subvisit(std::make_shared((*cond)[1]), nested, negated); - return a; - } else if (auto cond = dynamic_cast(a.get())) { - if (!isTemporal(cond)) { - Condition_ptr b = std::make_shared(a); + if (a->type() == type_id()) { + auto econd = static_cast(a.get()); + + if (econd->getCond()->type() == type_id()) { + ++stats[9]; + if (negated) a = std::make_shared(a); + return a; + } else if (econd->getCond()->type() == type_id()) { + ++stats[11]; + auto ucond = static_cast(econd->getCond().get()); + a = subvisit(std::make_shared(std::make_shared((*ucond)[1])), nested, negated); + return a; + } + } else if (a->type() == type_id()) { + auto acond = static_cast(a.get()); + + if (acond->getCond()->type() == type_id()) { + ++stats[10]; + auto fcond = static_cast(acond->getCond().get()); + a = subvisit(std::make_shared(std::make_shared((*fcond)[0])), nested, negated); + return a; + } else if (acond->getCond()->type() == type_id()) { + ++stats[12]; + auto ucond = static_cast(acond->getCond().get()); + a = subvisit(std::make_shared(std::make_shared((*ucond)[1])), nested, negated); + return a; + } + } else if (a->type() == type_id()) { + auto orcond = static_cast(a.get()); + if (!isTemporal(orcond)) { + Condition_ptr b = std::make_shared(std::make_shared(a)); if (negated) b = std::make_shared(b); return b; } ++stats[13]; std::vector pef, atomic; - for (auto &i: *cond) { - pef.push_back(std::make_shared(i)); + for (auto &i: *orcond) { + pef.push_back(std::make_shared(std::make_shared(i))); } a = subvisit(makeOr(pef), nested, negated); return a; - } else { - Condition_ptr b = std::make_shared(a); - if (negated) b = std::make_shared(b); - return b; } + + Condition_ptr b = std::make_shared(std::make_shared(a)); + if (negated) b = std::make_shared(b); + return b; }, stats, context, nested, negated, initrw); - RETURN(cond) + return cond; } - void PushNegationVisitor::_accept(AFCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_AF(FCondition *element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { auto a = subvisit(element->getCond(), true, false); - if (auto cond = dynamic_cast(a.get())) { - if ((*cond)[0] == DeadlockCondition::DEADLOCK) { + + if (a->type() == type_id()) { + auto notcond = static_cast(a.get()); + if ((*notcond)[0] == DeadlockCondition::DEADLOCK) { ++stats[14]; return subvisit(a, nested, negated); } } - if (dynamic_cast(a.get())) { - ++stats[15]; - if (negated) return std::make_shared(a); - return a; + if (a->type() == type_id()) { + auto acond = static_cast(a.get()); - } else if (dynamic_cast(a.get())) { - ++stats[16]; - if (negated) return std::make_shared(a); - return a; - } else if (auto cond = dynamic_cast(a.get())) { + if (acond->getCond()->type() == type_id()) { + ++stats[15]; + if (negated) return std::make_shared(a); + return a; + } else if (acond->getCond()->type() == type_id()) { + ++stats[18]; + auto ucond = static_cast(acond->getCond().get()); + return subvisit(std::make_shared(std::make_shared((*ucond)[1])), nested, negated); + } + } + + if (a->type() == type_id()) { + auto econd = static_cast(a.get()); + if (econd->getCond()->type() == type_id()) { + ++stats[16]; + if (negated) return std::make_shared(a); + return a; + } + } + + if (a->type() == type_id()) { + auto cond = static_cast(a.get()); std::vector pef, npef; for (auto &i: *cond) { - if (dynamic_cast(i.get())) { + if (i->type() == type_id() && static_cast(i.get())->getCond()->type() == type_id()) { pef.push_back(i); } else { npef.push_back(i); @@ -251,50 +283,58 @@ namespace PetriEngine::PQL { } if (pef.size() > 0) { stats[17] += pef.size(); - pef.push_back(std::make_shared(makeOr(npef))); + pef.push_back(std::make_shared(std::make_shared(makeOr(npef)))); return subvisit(makeOr(pef), nested, negated); } - } else if (auto cond = dynamic_cast(a.get())) { - ++stats[18]; - return subvisit(std::make_shared((*cond)[1]), nested, negated); } - auto b = std::make_shared(a); + + auto b = std::make_shared(std::make_shared(a)); if (negated) return std::make_shared(b); return b; }, stats, context, nested, negated, initrw); - RETURN(cond) + return cond; } - void PushNegationVisitor::_accept(AUCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_AU(UntilCondition *element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { auto b = subvisit(element->getCond2(), true, false); auto a = subvisit(element->getCond1(), true, false); - if (auto cond = dynamic_cast(b.get())) { - if ((*cond)[0] == DeadlockCondition::DEADLOCK) { + + if (b->type() == type_id()) { + auto notcond = static_cast(b.get()); + if ((*notcond)[0] == DeadlockCondition::DEADLOCK) { ++stats[19]; return subvisit(b, nested, negated); } } else if (a == DeadlockCondition::DEADLOCK) { ++stats[20]; return subvisit(b, nested, negated); - } else if (auto cond = dynamic_cast(a.get())) { - if ((*cond)[0] == DeadlockCondition::DEADLOCK) { + } else if (a->type() == type_id()) { + auto notcond = static_cast(a.get()); + if ((*notcond)[0] == DeadlockCondition::DEADLOCK) { ++stats[21]; - return subvisit(std::make_shared(b), nested, negated); + return subvisit(std::make_shared(std::make_shared(b)), nested, negated); } } - if (auto cond = dynamic_cast(b.get())) { - ++stats[22]; - return subvisit(cond, nested, negated); - } else if (dynamic_cast(b.get())) { - ++stats[23]; - if (negated) return std::make_shared(b); - return b; - } else if (auto cond = dynamic_cast(b.get())) { + if (b->type() == type_id()) { + auto acond = static_cast(b.get()); + if (acond->getCond()->type() == type_id()) { + ++stats[22]; + return subvisit(acond, nested, negated); + } + } else if (b->type() == type_id()) { + auto econd = static_cast(b.get()); + if (econd->getCond()->type() == type_id()) { + ++stats[23]; + if (negated) return std::make_shared(b); + return b; + } + } else if (b->type() == type_id()) { + auto orcond = static_cast(b.get()); std::vector pef, npef; - for (auto &i: *cond) { - if (dynamic_cast(i.get())) { + for (auto &i: *orcond) { + if (i->type() == type_id() && static_cast(i.get())->getCond()->type() == type_id()) { pef.push_back(i); } else { npef.push_back(i); @@ -303,7 +343,7 @@ namespace PetriEngine::PQL { if (pef.size() > 0) { stats[24] += pef.size(); if (npef.size() != 0) { - pef.push_back(std::make_shared(element->getCond1(), makeOr(npef))); + pef.push_back(std::make_shared(std::make_shared(element->getCond1(), makeOr(npef)))); } else { ++stats[23]; --stats[24]; @@ -312,42 +352,44 @@ namespace PetriEngine::PQL { } } - auto c = std::make_shared(a, b); + auto c = std::make_shared(std::make_shared(a, b)); if (negated) return std::make_shared(c); return c; }, stats, context, nested, negated, initrw); - RETURN(cond) + return cond; } - void PushNegationVisitor::_accept(EUCondition *element) { + Condition_ptr PushNegationVisitor::pushneg_EU(UntilCondition *element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { auto b = subvisit(element->getCond2(), true, false); auto a = subvisit(element->getCond1(), true, false); - if (auto cond = dynamic_cast(b.get())) { - if ((*cond)[0] == DeadlockCondition::DEADLOCK) { + if (b->type() == type_id()) { + auto notcond = static_cast(b.get()); + if ((*notcond)[0] == DeadlockCondition::DEADLOCK) { ++stats[25]; return subvisit(b, nested, negated); } } else if (a == DeadlockCondition::DEADLOCK) { ++stats[26]; return subvisit(b, nested, negated); - } else if (auto cond = dynamic_cast(a.get())) { - if ((*cond)[0] == DeadlockCondition::DEADLOCK) { + } else if (a->type() == type_id()) { + auto notcond = static_cast(a.get()); + if ((*notcond)[0] == DeadlockCondition::DEADLOCK) { ++stats[27]; - return subvisit(std::make_shared(b), nested, negated); + return subvisit(std::make_shared(std::make_shared(b)), nested, negated); } } - if (dynamic_cast(b.get())) { + if (b->type() == type_id() && static_cast(b.get())->getCond()->type() == type_id()) { ++stats[28]; if (negated) return std::make_shared(b); return b; } else if (auto cond = dynamic_cast(b.get())) { std::vector pef, npef; for (auto &i: *cond) { - if (dynamic_cast(i.get())) { + if (i->type() == type_id() && static_cast(i.get())->getCond()->type() == type_id()) { pef.push_back(i); } else { npef.push_back(i); @@ -356,18 +398,18 @@ namespace PetriEngine::PQL { if (pef.size() > 0) { stats[29] += pef.size(); if (npef.size() != 0) { - pef.push_back(std::make_shared(element->getCond1(), makeOr(npef))); + pef.push_back(std::make_shared(std::make_shared(element->getCond1(), makeOr(npef)))); ++stats[28]; --stats[29]; } return subvisit(makeOr(pef), nested, negated); } } - auto c = std::make_shared(a, b); + auto c = std::make_shared(std::make_shared(a, b)); if (negated) return std::make_shared(c); return c; }, stats, context, nested, negated, initrw); - RETURN(cond) + return cond; } /*LTL negation push*/ @@ -440,16 +482,36 @@ namespace PetriEngine::PQL { } void PushNegationVisitor::_accept(ACondition *element) { - auto e_cond = ECondition(std::make_shared(element->getCond())); - RETURN(subvisit(&e_cond, nested, !negated)) + if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_AF(static_cast((*element)[0].get()))); + } else if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_AG(static_cast((*element)[0].get()))); + } else if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_AX(static_cast((*element)[0].get()))); + } else if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_AU(static_cast((*element)[0].get()))); + } else { + auto e_cond = ECondition(std::make_shared(element->getCond())); + RETURN(subvisit(&e_cond, nested, !negated)) + } } void PushNegationVisitor::_accept(ECondition *element) { - // we forward the negated flag, we flip the outer quantifier later! - auto _sub = subvisit(element->getCond(), nested, negated); - if (negated) RETURN(std::make_shared(_sub)) - else RETURN(std::make_shared(_sub)) + if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_EF(static_cast((*element)[0].get()))); + } else if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_EG(static_cast((*element)[0].get()))); + } else if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_EX(static_cast((*element)[0].get()))); + } else if ((*element)[0]->type() == type_id()) { + RETURN(pushneg_EU(static_cast((*element)[0].get()))); + } else { + // we forward the negated flag, we flip the outer quantifier later! + auto _sub = subvisit(element->getCond(), nested, negated); + if (negated) RETURN(std::make_shared(_sub)) + else RETURN(std::make_shared(_sub)) + } } void PushNegationVisitor::_accept(GCondition *element) { @@ -464,9 +526,12 @@ namespace PetriEngine::PQL { auto n = subvisit(c, _nested, negate_children); if (n->isTriviallyFalse()) return n; if (n->isTriviallyTrue()) continue; - if (auto neg = dynamic_cast(n.get())) { - if (auto ef = dynamic_cast((*neg)[0].get())) { - nef.push_back((*ef)[0]); + if (n->type() == type_id()) { + auto neg = static_cast(n.get()); + if (neg->getCond()->type() == type_id() && static_cast(neg->getCond().get())->getCond()->type() == type_id()) { + auto econd = static_cast(neg->getCond().get()); + auto fcond = static_cast(econd->getCond().get()); + nef.push_back(fcond->getCond()); } else { other.emplace_back(n); } @@ -479,13 +544,14 @@ namespace PetriEngine::PQL { if (nef.size() + other.size() == 1) { return nef.size() == 0 ? other[0] : - std::make_shared(std::make_shared(nef[0])); + std::make_shared(std::make_shared(std::make_shared(nef[0]))); } if (nef.size() != 0) other.push_back( std::make_shared( - std::make_shared( - makeOr(nef)))); + std::make_shared( + std::make_shared( + makeOr(nef))))); if (other.size() == 1) return other[0]; auto res = makeAnd(other); return res; @@ -499,8 +565,10 @@ namespace PetriEngine::PQL { return n; } if (n->isTriviallyFalse()) continue; - if (auto ef = dynamic_cast(n.get())) { - nef.push_back((*ef)[0]); + if (n->type() == type_id() && static_cast(n.get())->getCond()->type() == type_id()) { + auto econd = static_cast(n.get()); + auto fcond = static_cast(econd->getCond().get()); + nef.push_back((*fcond)[0]); } else { other.emplace_back(n); } @@ -508,12 +576,13 @@ namespace PetriEngine::PQL { if (nef.size() + other.size() == 0) return BooleanCondition::FALSE_CONSTANT; if (nef.size() + other.size() == 1) { - return nef.size() == 0 ? other[0] : std::make_shared(nef[0]); + return nef.size() == 0 ? other[0] : std::make_shared(std::make_shared(nef[0])); } if (nef.size() != 0) other.push_back( - std::make_shared( - makeOr(nef))); + std::make_shared( + std::make_shared( + makeOr(nef)))); if (other.size() == 1) return other[0]; return makeOr(other); } @@ -688,7 +757,21 @@ namespace PetriEngine::PQL { nested = _nested; negated = _negated; +// if (condition->type() == type_id()) +// if ((*static_cast(condition))[0]->type() == type_id()) +// std::cout << "E!" << std::endl; + +// condition->toString(std::cout); std::cout << " IN GO " << std::endl; Visitor::visit(this, condition); + +// if (return_value->type() == type_id()) +// if ((*static_cast(condition))[0]->type() == type_id()) +// std::cout << "HERE" << std::endl; + +// PetriEngine::PQL::IsCTLVisitor isCtlVisitor3; +// Visitor::visit(isCtlVisitor3, return_value); +// std::cout << isCtlVisitor3.isCTL << std::endl; +// return_value->toString(std::cout); std::cout << std::endl; #ifndef NDEBUG assert(has_returned); // Subvisit should return value has_returned = false; diff --git a/src/PetriEngine/Reachability/ResultPrinter.cpp b/src/PetriEngine/Reachability/ResultPrinter.cpp index df4fbb7f3..0cf0c6018 100644 --- a/src/PetriEngine/Reachability/ResultPrinter.cpp +++ b/src/PetriEngine/Reachability/ResultPrinter.cpp @@ -3,6 +3,7 @@ #include "PetriEngine/PetriNetBuilder.h" #include "PetriEngine/options.h" #include "PetriEngine/PQL/Expressions.h" +#include "PetriEngine/PQL/PQL.h" namespace PetriEngine { namespace Reachability { @@ -90,9 +91,11 @@ namespace PetriEngine { //Print result auto bound = query; - if(auto ef = dynamic_cast(query)) + if(query->type() == PQL::type_id() && static_cast(query)->getCond()->type() == PQL::type_id()) { - bound = (*ef)[0].get(); + auto econd = static_cast(query); + auto fcond = static_cast(econd->getCond().get()); + bound = (*fcond)[0].get(); } bound = dynamic_cast(bound); diff --git a/src/PetriEngine/options.cpp b/src/PetriEngine/options.cpp index 8e2083dab..8947ae845 100644 --- a/src/PetriEngine/options.cpp +++ b/src/PetriEngine/options.cpp @@ -536,6 +536,7 @@ bool options_t::parse(int argc, const char** argv) { printf(" Nikolaj Jensen Ulrik \n"); printf(" Simon Mejlby Virenfeldt \n"); printf(" Lars Kærlund Østergaard \n"); + printf(" Rasmus Tollund \n"); printf("GNU GPLv3 or later \n"); return true; } else if (modelfile == nullptr) { diff --git a/src/PetriParse/QueryBinaryParser.cpp b/src/PetriParse/QueryBinaryParser.cpp index 49be8f614..d5bb0302a 100644 --- a/src/PetriParse/QueryBinaryParser.cpp +++ b/src/PetriParse/QueryBinaryParser.cpp @@ -187,27 +187,27 @@ Condition_ptr QueryBinaryParser::parseQuery(std::istream& binary, const std::vec if (q == Quantifier::EMPTY) return std::make_shared(cond1); else if(q == Quantifier::A) - return std::make_shared(cond1); + return std::make_shared(std::make_shared(cond1)); else - return std::make_shared(cond1); + return std::make_shared(std::make_shared(cond1)); } else if(p == Path::F) { if (q == Quantifier::EMPTY) return std::make_shared(cond1); else if(q == Quantifier::A) - return std::make_shared(cond1); + return std::make_shared(std::make_shared(cond1)); else - return std::make_shared(cond1); + return std::make_shared(std::make_shared(cond1)); } else if(p == Path::G) { if (q == Quantifier::EMPTY) return std::make_shared(cond1); else if(q == Quantifier::A) - return std::make_shared(cond1); + return std::make_shared(std::make_shared(cond1)); else - return std::make_shared(cond1); + return std::make_shared(std::make_shared(cond1)); } else if(p == Path::U) { @@ -220,9 +220,9 @@ Condition_ptr QueryBinaryParser::parseQuery(std::istream& binary, const std::vec if (q == Quantifier::EMPTY) return std::make_shared(cond1, cond2); else if(q == Quantifier::A) - return std::make_shared(cond1, cond2); + return std::make_shared(std::make_shared(cond1, cond2)); else - return std::make_shared(cond1, cond2); + return std::make_shared(std::make_shared(cond1, cond2)); } else if(p == Path::PControl) { diff --git a/src/PetriParse/QueryXMLParser.cpp b/src/PetriParse/QueryXMLParser.cpp index 0fbbe955b..4109ad4b5 100644 --- a/src/PetriParse/QueryXMLParser.cpp +++ b/src/PetriParse/QueryXMLParser.cpp @@ -192,7 +192,7 @@ Condition_ptr QueryXMLParser::parseFormula(rapidxml::xml_node<>* element) { places.push_back(place); } auto bnds = std::make_shared(places); - return std::make_shared(bnds); + return std::make_shared(std::make_shared(bnds)); } else if ((cond = parseBooleanFormula(child)) != nullptr) { return cond; } else { @@ -219,13 +219,13 @@ Condition_ptr QueryXMLParser::parseBooleanFormula(rapidxml::xml_node<>* element //TODO: Break invariant, impossibility, and possibility into their own nodes. What is the corresponding semantics of these nodes? if (elementName == "invariant") { if ((cond = parseBooleanFormula(element->first_node())) != nullptr) - return std::make_shared(std::make_shared(std::make_shared(cond))); + return std::make_shared(std::make_shared(std::make_shared(std::make_shared(cond)))); } else if (elementName == "impossibility") { if ((cond = parseBooleanFormula(element->first_node())) != nullptr) - return std::make_shared(std::make_shared(cond)); + return std::make_shared(std::make_shared(std::make_shared(cond))); } else if (elementName == "possibility") { if ((cond = parseBooleanFormula(element->first_node())) != nullptr) - return std::make_shared(cond); + return std::make_shared(std::make_shared(cond)); } else if (elementName == "control") { if (getChildCount(element) != 1) { assert(false); diff --git a/src/VerifyPN.cpp b/src/VerifyPN.cpp index 695e4eced..b0246e38b 100644 --- a/src/VerifyPN.cpp +++ b/src/VerifyPN.cpp @@ -452,11 +452,21 @@ void simplify_queries( const MarkVal* marking, #endif continue; } + + PetriEngine::PQL::IsCTLVisitor isCtlVisitor; + Visitor::visit(isCtlVisitor, queries[i]); + std::cout << isCtlVisitor.isCTL << std::endl; + queries[i]->toString(std::cout); std::cout << std::endl; queries[i] = pushNegation(initialMarkingRW([&]() { return queries[i]; }, stats, context, false, false, true), stats, context, false, false, true); wasAGCPNApprox |= dynamic_cast (queries[i].get()) != nullptr; + PetriEngine::PQL::IsCTLVisitor isCtlVisitor2; + Visitor::visit(isCtlVisitor2, queries[i]); + std::cout << isCtlVisitor2.isCTL << std::endl; + queries[i]->toString(std::cout); std::cout << std::endl; + if (options.queryReductionTimeout > 0 && options.printstatistics) { out << "RWSTATS PRE:"; stats.print(out); @@ -469,8 +479,13 @@ void simplify_queries( const MarkVal* marking, options.lpsolveTimeout, &cache); try { negstat_t stats; - auto simp_cond = PetriEngine::PQL::simplify(queries[i], simplificationContext); + auto simp_cond = PetriEngine::PQL::simplify(queries[i], simplificationContext);; + queries[i]->toString(std::cout); std::cout << std::endl; queries[i] = pushNegation(simp_cond.formula, stats, context, false, false, true); + PetriEngine::PQL::IsCTLVisitor isCtlVisitor3; + Visitor::visit(isCtlVisitor3, queries[i]); + std::cout << (isCtlVisitor3.isCTL? "": "NO LONGER CTL!") << std::endl; + queries[i]->toString(std::cout); std::cout << std::endl; wasAGCPNApprox |= dynamic_cast (queries[i].get()) != nullptr; if (options.printstatistics) { out << "RWSTATS POST:"; diff --git a/src/main.cpp b/src/main.cpp index 019f17a5b..8b07a00f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,6 +90,7 @@ int main(int argc, const char** argv) { auto queries = options.logic == TemporalLogic::CTL ? getCTLQueries(ctlStarQueries) : getLTLQueries(ctlStarQueries); + ctlStarQueries[0]->toString(std::cout); std::cout << std::endl; if (options.printstatistics && options.queryReductionTimeout > 0) { negstat_t stats; From 72d48f805aa8d318f3951a9be93b66ee986b3c9f Mon Sep 17 00:00:00 2001 From: Ragusaen Date: Tue, 22 Feb 2022 14:59:29 +0100 Subject: [PATCH 05/41] Mostly added ReleaseCondition --- include/PetriEngine/PQL/Analyze.h | 2 + include/PetriEngine/PQL/CTLVisitor.h | 2 + include/PetriEngine/PQL/Evaluation.h | 4 ++ include/PetriEngine/PQL/Expressions.h | 27 +++++++++++- include/PetriEngine/PQL/FormulaSize.h | 2 + include/PetriEngine/PQL/MutatingVisitor.h | 4 ++ include/PetriEngine/PQL/PQL.h | 2 +- include/PetriEngine/PQL/PlaceUseVisitor.h | 2 + include/PetriEngine/PQL/PushNegation.h | 2 + include/PetriEngine/PQL/QueryPrinter.h | 6 ++- include/PetriEngine/PQL/Simplifier.h | 2 + include/PetriEngine/PQL/Visitor.h | 13 ++++-- include/PetriEngine/PQL/XMLPrinter.h | 1 + src/PetriEngine/PQL/Analyze.cpp | 5 +++ src/PetriEngine/PQL/CTLVisitor.cpp | 10 +++++ src/PetriEngine/PQL/Evaluation.cpp | 21 +++++++++ src/PetriEngine/PQL/FormulaSize.cpp | 4 ++ src/PetriEngine/PQL/PlaceUseVisitor.cpp | 6 +++ src/PetriEngine/PQL/PushNegation.cpp | 53 ++++++++++++++++------- src/PetriEngine/PQL/QueryPrinter.cpp | 8 ++++ src/PetriEngine/PQL/Simplifier.cpp | 42 ++++++++++++++++++ src/PetriEngine/PQL/XMLPrinter.cpp | 14 ++++++ src/PetriParse/QueryXMLParser.cpp | 19 ++++++++ 23 files changed, 228 insertions(+), 23 deletions(-) diff --git a/include/PetriEngine/PQL/Analyze.h b/include/PetriEngine/PQL/Analyze.h index 7f7f20cf7..0bf20c922 100644 --- a/include/PetriEngine/PQL/Analyze.h +++ b/include/PetriEngine/PQL/Analyze.h @@ -78,6 +78,8 @@ namespace PetriEngine::PQL { void _accept(UntilCondition *element) override; void _accept(SimpleQuantifierCondition *element) override; + + void _accept(ReleaseCondition *element); }; } diff --git a/include/PetriEngine/PQL/CTLVisitor.h b/include/PetriEngine/PQL/CTLVisitor.h index 568e98f61..29f302884 100644 --- a/include/PetriEngine/PQL/CTLVisitor.h +++ b/include/PetriEngine/PQL/CTLVisitor.h @@ -82,6 +82,8 @@ namespace PetriEngine::PQL { void _accept(const LogicalCondition *element); void _accept(const CompareCondition *element); + + void _accept(const ReleaseCondition *condition); }; } diff --git a/include/PetriEngine/PQL/Evaluation.h b/include/PetriEngine/PQL/Evaluation.h index 727ad5f5a..4179890cd 100644 --- a/include/PetriEngine/PQL/Evaluation.h +++ b/include/PetriEngine/PQL/Evaluation.h @@ -107,6 +107,8 @@ namespace PetriEngine { namespace PQL { void _accept(UnfoldedUpperBoundsCondition *element) override; void _accept(ShallowCondition *element) override; + + void _accept(ReleaseCondition *element); }; Condition::Result evaluateAndSet(Condition *element, const EvaluationContext &context); @@ -150,6 +152,8 @@ namespace PetriEngine { namespace PQL { void _accept(UnfoldedUpperBoundsCondition *element) override; void _accept(ShallowCondition *element) override; + + void _accept(ReleaseCondition *element) override; }; } } diff --git a/include/PetriEngine/PQL/Expressions.h b/include/PetriEngine/PQL/Expressions.h index 098d85d5c..ec027b7ea 100644 --- a/include/PetriEngine/PQL/Expressions.h +++ b/include/PetriEngine/PQL/Expressions.h @@ -101,9 +101,13 @@ namespace PetriEngine { template<> constexpr type_id_t type_id() { return type_id() + 1; } + class ReleaseCondition; + template<> + constexpr type_id_t type_id() { return type_id() + 1; } + class XCondition; template<> - constexpr type_id_t type_id() { return type_id() + 1; } + constexpr type_id_t type_id() { return type_id() + 1; } class ControlCondition; template<> @@ -508,7 +512,28 @@ namespace PetriEngine { protected: Condition_ptr _cond1; Condition_ptr _cond2; + }; + + class ReleaseCondition : public QuantifierCondition { + public: + ReleaseCondition(const Condition_ptr cond1, const Condition_ptr cond2) { + _cond1 = cond1; + _cond2 = cond2; + } + + [[nodiscard]] virtual const Condition_ptr& operator[] (size_t i) const override + { if(i == 0) return _cond1; return _cond2;} + Path getPath() const override { return Path::R; } + [[nodiscard]] const Condition_ptr& getCond1() const { return (*this)[0]; } + [[nodiscard]] const Condition_ptr& getCond2() const { return (*this)[1]; } + + uint32_t distance(DistanceContext& context) const override { return (*this)[1]->distance(context); } + Quantifier getQuantifier() const override { return Quantifier::EMPTY; } + virtual type_id_t type() const { return PQL::type_id(); }; + protected: + Condition_ptr _cond1; + Condition_ptr _cond2; }; /******************** CONDITIONS ********************/ diff --git a/include/PetriEngine/PQL/FormulaSize.h b/include/PetriEngine/PQL/FormulaSize.h index 70a1c41d6..6c293f2b8 100644 --- a/include/PetriEngine/PQL/FormulaSize.h +++ b/include/PetriEngine/PQL/FormulaSize.h @@ -74,6 +74,8 @@ namespace PetriEngine::PQL { void _accept(const UntilCondition *condition) override; void _accept(const LogicalCondition *condition) override; + + void _accept(const ReleaseCondition *condition); }; } diff --git a/include/PetriEngine/PQL/MutatingVisitor.h b/include/PetriEngine/PQL/MutatingVisitor.h index 31466a0b6..0d92e8d0c 100644 --- a/include/PetriEngine/PQL/MutatingVisitor.h +++ b/include/PetriEngine/PQL/MutatingVisitor.h @@ -100,6 +100,10 @@ namespace PetriEngine { _accept(static_cast(element)); } + virtual void _accept(ReleaseCondition *element) { + _accept(static_cast(element)); + } + virtual void _accept(ControlCondition *condition) { _accept(static_cast(condition)); }; diff --git a/include/PetriEngine/PQL/PQL.h b/include/PetriEngine/PQL/PQL.h index 6f0aa1599..68b32312d 100644 --- a/include/PetriEngine/PQL/PQL.h +++ b/include/PetriEngine/PQL/PQL.h @@ -62,7 +62,7 @@ namespace PetriEngine { enum CTLType {PATHQEURY = 1, LOPERATOR = 2, EVAL = 3, TYPE_ERROR = -1}; enum Quantifier { AND = 1, OR = 2, A = 3, E = 4, NEG = 5, COMPCONJ = 6, DEADLOCK = 7, UPPERBOUNDS = 8, PN_BOOLEAN = 9, BControl = 10, EMPTY = -1 }; - enum Path { G = 1, X = 2, F = 3, U = 4, PControl = 5, pError = -1 }; + enum Path { G = 1, X = 2, F = 3, U = 4, R = 5, PControl = 6, pError = -1 }; class AnalysisContext; diff --git a/include/PetriEngine/PQL/PlaceUseVisitor.h b/include/PetriEngine/PQL/PlaceUseVisitor.h index 4f43eb260..ce61d3709 100644 --- a/include/PetriEngine/PQL/PlaceUseVisitor.h +++ b/include/PetriEngine/PQL/PlaceUseVisitor.h @@ -51,9 +51,11 @@ namespace PQL { virtual void _accept(const UnfoldedUpperBoundsCondition* element) override; virtual void _accept(const SimpleQuantifierCondition *element) override; virtual void _accept(const UntilCondition *element) override; + virtual void _accept(const ReleaseCondition *element) override; private: void visitCommutativeExpr(const CommutativeExpr* element); + }; } } diff --git a/include/PetriEngine/PQL/PushNegation.h b/include/PetriEngine/PQL/PushNegation.h index 1d9f59347..28901623c 100644 --- a/include/PetriEngine/PQL/PushNegation.h +++ b/include/PetriEngine/PQL/PushNegation.h @@ -126,6 +126,8 @@ namespace PetriEngine::PQL { Condition_ptr pushneg_AF(FCondition *element); Condition_ptr pushneg_EU(UntilCondition *element); + + void _accept(ReleaseCondition *element); }; } diff --git a/include/PetriEngine/PQL/QueryPrinter.h b/include/PetriEngine/PQL/QueryPrinter.h index 1d4d0f62b..e39daf818 100644 --- a/include/PetriEngine/PQL/QueryPrinter.h +++ b/include/PetriEngine/PQL/QueryPrinter.h @@ -65,6 +65,8 @@ namespace PetriEngine { void _accept(const UntilCondition *condition) override; + void _accept(const ReleaseCondition *condition) override; + void _accept(const UnfoldedFireableCondition *element) override; void _accept(const FireableCondition *element) override; @@ -93,10 +95,10 @@ namespace PetriEngine { void _accept(const SubtractExpr *element) override; - void _accept(const IdentifierExpr *element) override; - + void _accept(const IdentifierExpr *element) override; protected: + std::ostream &os; void _accept(const LogicalCondition *element, const std::string &op); diff --git a/include/PetriEngine/PQL/Simplifier.h b/include/PetriEngine/PQL/Simplifier.h index 73ae8b932..29b06a1e6 100644 --- a/include/PetriEngine/PQL/Simplifier.h +++ b/include/PetriEngine/PQL/Simplifier.h @@ -82,6 +82,8 @@ namespace PetriEngine::PQL { void _accept(const UntilCondition *condition) override; void _accept(const BooleanCondition *element) override; + + void _accept(const ReleaseCondition *condition); }; Member constraint(const Expr *element, const SimplificationContext &context); diff --git a/include/PetriEngine/PQL/Visitor.h b/include/PetriEngine/PQL/Visitor.h index 366abfaf8..bc023bf3f 100644 --- a/include/PetriEngine/PQL/Visitor.h +++ b/include/PetriEngine/PQL/Visitor.h @@ -163,6 +163,9 @@ namespace PetriEngine { case type_id(): visitor->accept(static_cast (c)); break; + case type_id(): + visitor->accept(static_cast(c)); + break; case type_id(): visitor->accept(static_cast (c)); break; @@ -264,13 +267,15 @@ namespace PetriEngine { _accept(static_cast(element)); } + // Quantifiers + virtual void _accept(const UntilCondition *element) { - _accept(static_cast(element)); + _accept(static_cast(element)); } - - // Quantifiers, most uses of the visitor will not use the quantifiers - so we give a default implementation. - // default behaviour is error + virtual void _accept(const ReleaseCondition *element) { + _accept(static_cast(element)); + } virtual void _accept(const ControlCondition *condition) { _accept(static_cast (condition)); diff --git a/include/PetriEngine/PQL/XMLPrinter.h b/include/PetriEngine/PQL/XMLPrinter.h index f59dee972..b4db7b8bb 100644 --- a/include/PetriEngine/PQL/XMLPrinter.h +++ b/include/PetriEngine/PQL/XMLPrinter.h @@ -123,6 +123,7 @@ namespace PetriEngine { } }; + void _accept(const ReleaseCondition *element); }; } } diff --git a/src/PetriEngine/PQL/Analyze.cpp b/src/PetriEngine/PQL/Analyze.cpp index 55e22a529..18470c847 100644 --- a/src/PetriEngine/PQL/Analyze.cpp +++ b/src/PetriEngine/PQL/Analyze.cpp @@ -226,6 +226,11 @@ namespace PetriEngine::PQL { Visitor::visit(this, (*element)[1]); } + void AnalyzeVisitor::_accept(ReleaseCondition *element) { + Visitor::visit(this, (*element)[0]); + Visitor::visit(this, (*element)[1]); + } + void AnalyzeVisitor::_accept(SimpleQuantifierCondition *element) { Visitor::visit(this, (*element)[0]); } diff --git a/src/PetriEngine/PQL/CTLVisitor.cpp b/src/PetriEngine/PQL/CTLVisitor.cpp index 3940e4df7..03e197ca4 100644 --- a/src/PetriEngine/PQL/CTLVisitor.cpp +++ b/src/PetriEngine/PQL/CTLVisitor.cpp @@ -125,6 +125,16 @@ namespace PetriEngine::PQL { _cur_type = CTLSyntaxType::PATH; } + void IsCTLVisitor::_accept(const ReleaseCondition *condition) { + Visitor::visit(this, (*condition)[0]); + if (_cur_type != CTLSyntaxType::BOOLEAN) + isCTL = false; + Visitor::visit(this, (*condition)[1]); + if (_cur_type != CTLSyntaxType::BOOLEAN) + isCTL = false; + _cur_type = CTLSyntaxType::PATH; + } + void IsCTLVisitor::_accept(const UnfoldedFireableCondition *element) { _cur_type = CTLSyntaxType::BOOLEAN; } diff --git a/src/PetriEngine/PQL/Evaluation.cpp b/src/PetriEngine/PQL/Evaluation.cpp index 070a31a4a..a5d1709c0 100644 --- a/src/PetriEngine/PQL/Evaluation.cpp +++ b/src/PetriEngine/PQL/Evaluation.cpp @@ -170,6 +170,17 @@ namespace PetriEngine { namespace PQL { } } + void EvaluateVisitor::_accept(ReleaseCondition *element) { + Visitor::visit(this, (*element)[1]); + if (_return_value != Condition::RFALSE) + { + // retain return, either true or unknown. + return; + } + _return_value = Condition::RUNKNOWN; +// TODO: Don't know how to handle this +// Visitor::visit(this, (*element)[0]); + } void EvaluateVisitor::_accept(AndCondition *element) { auto res = Condition::RTRUE; @@ -293,6 +304,16 @@ namespace PetriEngine { namespace PQL { _return_value = {Condition::RUNKNOWN}; } + void EvaluateAndSetVisitor::_accept(ReleaseCondition *element) { + Visitor::visit(this, (*element)[1]); + if (_return_value != Condition::RFALSE) + return; + + _return_value = Condition::RUNKNOWN; + // TODO: Don't know how to handle this + //Visitor::visit(this, (*element)[0]); + } + void EvaluateAndSetVisitor::_accept(AndCondition *element) { Condition::Result res = Condition::RTRUE; for (auto &c: element->getOperands()) { diff --git a/src/PetriEngine/PQL/FormulaSize.cpp b/src/PetriEngine/PQL/FormulaSize.cpp index 7cfa9116f..e85b4009e 100644 --- a/src/PetriEngine/PQL/FormulaSize.cpp +++ b/src/PetriEngine/PQL/FormulaSize.cpp @@ -112,6 +112,10 @@ void FormulaSizeVisitor::_accept(const UntilCondition *condition) { RETURN(subvisit(condition->getCond1()) + subvisit(condition->getCond2()) + 1) } +void FormulaSizeVisitor::_accept(const ReleaseCondition *condition) { + RETURN(subvisit(condition->getCond1()) + subvisit(condition->getCond2()) + 1) +} + void FormulaSizeVisitor::_accept(const LogicalCondition *condition) { size_t i = 1; for(auto& c : *condition) diff --git a/src/PetriEngine/PQL/PlaceUseVisitor.cpp b/src/PetriEngine/PQL/PlaceUseVisitor.cpp index 6012a81ea..936347d2c 100644 --- a/src/PetriEngine/PQL/PlaceUseVisitor.cpp +++ b/src/PetriEngine/PQL/PlaceUseVisitor.cpp @@ -113,6 +113,12 @@ namespace PQL { Visitor::visit(this, (*element)[1]); } + void PlaceUseVisitor::_accept(const ReleaseCondition* element) + { + Visitor::visit(this, (*element)[0]); + Visitor::visit(this, (*element)[1]); + } + void PlaceUseVisitor::_accept(const SimpleQuantifierCondition* element) { diff --git a/src/PetriEngine/PQL/PushNegation.cpp b/src/PetriEngine/PQL/PushNegation.cpp index cca992ff4..28e4c60a7 100644 --- a/src/PetriEngine/PQL/PushNegation.cpp +++ b/src/PetriEngine/PQL/PushNegation.cpp @@ -297,8 +297,9 @@ namespace PetriEngine::PQL { Condition_ptr PushNegationVisitor::pushneg_AU(UntilCondition *element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { - auto b = subvisit(element->getCond2(), true, false); - auto a = subvisit(element->getCond1(), true, false); + // We push negation and convert this to a ReleaseCondition if it is negated + auto b = subvisit(element->getCond2(), true, negated); + auto a = subvisit(element->getCond1(), true, negated); if (b->type() == type_id()) { auto notcond = static_cast(b.get()); @@ -352,9 +353,10 @@ namespace PetriEngine::PQL { } } - auto c = std::make_shared(std::make_shared(a, b)); - if (negated) return std::make_shared(c); - return c; + if (negated) + return std::make_shared(std::make_shared(a, b)); + else + return std::make_shared(std::make_shared(a, b)); }, stats, context, nested, negated, initrw); return cond; } @@ -405,9 +407,10 @@ namespace PetriEngine::PQL { return subvisit(makeOr(pef), nested, negated); } } - auto c = std::make_shared(std::make_shared(a, b)); - if (negated) return std::make_shared(c); - return c; + if (negated) + return std::make_shared(std::make_shared(a, b)); + else + return std::make_shared(std::make_shared(a, b)); }, stats, context, nested, negated, initrw); return cond; } @@ -415,20 +418,40 @@ namespace PetriEngine::PQL { /*LTL negation push*/ void PushNegationVisitor::_accept(UntilCondition* element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { - auto b = subvisit(element->getCond2(), true, false); - auto a = subvisit(element->getCond1(), true, false); + // Push negation and convert this to a Release if it is negated + auto b = subvisit(element->getCond2(), true, negated); + auto a = subvisit(element->getCond1(), true, negated); + + if (auto cond = std::dynamic_pointer_cast(b)) { + static_assert(negstat_t::nrules >= 35); + ++stats[34]; + return b; + } + + if (negated) + return std::make_shared(a, b); + else + return std::make_shared(a, b); + }, stats, context, nested, negated, initrw); + RETURN(cond) + } + + void PushNegationVisitor::_accept(ReleaseCondition* element) { + auto cond = initialMarkingRW([&]() -> Condition_ptr { + // Push negation and convert this to a UntilCondition if it is negated + auto b = subvisit(element->getCond2(), true, negated); + auto a = subvisit(element->getCond1(), true, negated); if (auto cond = std::dynamic_pointer_cast(b)) { static_assert(negstat_t::nrules >= 35); ++stats[34]; - if (negated) - return std::make_shared(b); return b; } - auto c = std::make_shared(a, b); - if (negated) return std::make_shared(c); - return c; + if (negated) + return std::make_shared(a, b); + else + return std::make_shared(a, b); }, stats, context, nested, negated, initrw); RETURN(cond) } diff --git a/src/PetriEngine/PQL/QueryPrinter.cpp b/src/PetriEngine/PQL/QueryPrinter.cpp index c6b46d839..ff91e3b8a 100644 --- a/src/PetriEngine/PQL/QueryPrinter.cpp +++ b/src/PetriEngine/PQL/QueryPrinter.cpp @@ -137,6 +137,14 @@ namespace PetriEngine { os << ")"; } + void QueryPrinter::_accept(const ReleaseCondition *condition) { + os << "("; + Visitor::visit(this, condition->getCond1()); + os << " R "; + Visitor::visit(this, condition->getCond2()); + os << ")"; + } + void QueryPrinter::_accept(const UnfoldedFireableCondition *element) { os << "is-fireable(" << element->getName() << ")"; } diff --git a/src/PetriEngine/PQL/Simplifier.cpp b/src/PetriEngine/PQL/Simplifier.cpp index 5ac64f556..378e69643 100644 --- a/src/PetriEngine/PQL/Simplifier.cpp +++ b/src/PetriEngine/PQL/Simplifier.cpp @@ -709,6 +709,48 @@ namespace PetriEngine::PQL { } } + void Simplifier::_accept(const ReleaseCondition *condition) { + bool neg = _context.negated(); + _context.setNegate(false); + + Visitor::visit(this, condition->getCond2()); + Retval r2 = std::move(_return_value); + if (r2.formula->isTriviallyTrue() || !r2.neglps->satisfiable(_context)) { + _context.setNegate(neg); + RETURN(neg ? + Retval(BooleanCondition::FALSE_CONSTANT) : + Retval(BooleanCondition::TRUE_CONSTANT)) + } else if (r2.formula->isTriviallyFalse() || !r2.lps->satisfiable(_context)) { + _context.setNegate(neg); + RETURN(neg ? + Retval(BooleanCondition::TRUE_CONSTANT) : + Retval(BooleanCondition::FALSE_CONSTANT)) + } + Visitor::visit(this, condition->getCond1()); + Retval r1 = std::move(_return_value); + + _context.setNegate(neg); + + if (_context.negated()) { + if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(_context)) { + RETURN(Retval(std::make_shared(r2.formula))) + } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(_context)) { + RETURN(Retval(std::make_shared(std::make_shared(r2.formula)))) + } else { + RETURN(Retval(std::make_shared( + std::make_shared(r1.formula, r2.formula)))) + } + } else { + if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(_context)) { + RETURN(std::move(r2)) + } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(_context)) { + RETURN(Retval(std::make_shared(r2.formula))) + } else { + RETURN(Retval(std::make_shared(r1.formula, r2.formula))) + } + } + } + void Simplifier::_accept(const ECondition *condition) { if (const std::shared_ptr xcond = std::dynamic_pointer_cast((*condition)[0])) { Visitor::visit(*this, (*xcond)[0]); diff --git a/src/PetriEngine/PQL/XMLPrinter.cpp b/src/PetriEngine/PQL/XMLPrinter.cpp index 528d21374..0439e55f0 100644 --- a/src/PetriEngine/PQL/XMLPrinter.cpp +++ b/src/PetriEngine/PQL/XMLPrinter.cpp @@ -216,6 +216,20 @@ namespace PetriEngine { } } + void XMLPrinter::_accept(const ReleaseCondition *condition) { + Tag R(this, "release"); + { + { + Tag r(this, "reach"); + Visitor::visit(this, (*condition)[1]); + } + { + Tag b(this, "before"); + Visitor::visit(this, (*condition)[0]); + } + } + } + void XMLPrinter::_accept(const UnfoldedFireableCondition *element) { outputLine("", element->getName(), ""); } diff --git a/src/PetriParse/QueryXMLParser.cpp b/src/PetriParse/QueryXMLParser.cpp index 4109ad4b5..a4922d05d 100644 --- a/src/PetriParse/QueryXMLParser.cpp +++ b/src/PetriParse/QueryXMLParser.cpp @@ -282,6 +282,25 @@ Condition_ptr QueryXMLParser::parseBooleanFormula(rapidxml::xml_node<>* element return std::make_shared(cond, cond2); } } + } else if (elementName == "release") { + if (getChildCount(element) != 2) + { + assert(false); + return nullptr; + } + auto reach = element->first_node(); + auto before = reach->next_sibling(); + if (getChildCount(reach) != 1 || getChildCount(before) != 1 || + strcmp(reach->name(), "reach") != 0 || strcmp(before->name(), "before") != 0) + { + assert(false); + return nullptr; + } + if ((cond = parseBooleanFormula(reach->first_node())) != nullptr) { + if ((cond2 = parseBooleanFormula(before->first_node())) != nullptr) { + return std::make_shared(cond, cond2); + } + } } else if (elementName == "all-paths") { if (getChildCount(element) != 1) { From d2dc989cc0861ac9fa8c2cf02231c2514cb1cbae Mon Sep 17 00:00:00 2001 From: Ragusaen Date: Tue, 22 Feb 2022 15:52:56 +0100 Subject: [PATCH 06/41] Fixed evaluation, interestingtransitions and distance --- include/PetriEngine/PQL/Evaluation.h | 2 +- include/PetriEngine/PQL/Expressions.h | 2 +- .../Stubborn/InterestingTransitionVisitor.h | 6 +++-- src/PetriEngine/PQL/Evaluation.cpp | 26 +++++++++++-------- .../Stubborn/InterestingTransitionVisitor.cpp | 8 ++++++ 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/include/PetriEngine/PQL/Evaluation.h b/include/PetriEngine/PQL/Evaluation.h index 4179890cd..5dce1177c 100644 --- a/include/PetriEngine/PQL/Evaluation.h +++ b/include/PetriEngine/PQL/Evaluation.h @@ -108,7 +108,7 @@ namespace PetriEngine { namespace PQL { void _accept(ShallowCondition *element) override; - void _accept(ReleaseCondition *element); + void _accept(ReleaseCondition *element) override; }; Condition::Result evaluateAndSet(Condition *element, const EvaluationContext &context); diff --git a/include/PetriEngine/PQL/Expressions.h b/include/PetriEngine/PQL/Expressions.h index ec027b7ea..2f1dae311 100644 --- a/include/PetriEngine/PQL/Expressions.h +++ b/include/PetriEngine/PQL/Expressions.h @@ -528,7 +528,7 @@ namespace PetriEngine { [[nodiscard]] const Condition_ptr& getCond1() const { return (*this)[0]; } [[nodiscard]] const Condition_ptr& getCond2() const { return (*this)[1]; } - uint32_t distance(DistanceContext& context) const override { return (*this)[1]->distance(context); } + uint32_t distance(DistanceContext& context) const override { return (*this)[0]->distance(context); } Quantifier getQuantifier() const override { return Quantifier::EMPTY; } virtual type_id_t type() const { return PQL::type_id(); }; protected: diff --git a/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h b/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h index ed3d573dd..6137c0465 100644 --- a/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h +++ b/include/PetriEngine/Stubborn/InterestingTransitionVisitor.h @@ -108,13 +108,15 @@ namespace PetriEngine { void _accept(const PQL::UntilCondition *element) override; + void _accept(const PQL::ReleaseCondition *element); + void _accept(const PQL::GCondition *condition) override; void _accept(const PQL::FCondition *condition) override; void _accept(const PQL::BooleanCondition *element) override; - bool negated = false; + private: /* @@ -179,8 +181,8 @@ namespace PetriEngine { void _accept(const PQL::SubtractExpr *element) override; }; - IncrVisitor incr; + DecrVisitor decr; }; diff --git a/src/PetriEngine/PQL/Evaluation.cpp b/src/PetriEngine/PQL/Evaluation.cpp index a5d1709c0..a0fdd87e6 100644 --- a/src/PetriEngine/PQL/Evaluation.cpp +++ b/src/PetriEngine/PQL/Evaluation.cpp @@ -172,14 +172,15 @@ namespace PetriEngine { namespace PQL { void EvaluateVisitor::_accept(ReleaseCondition *element) { Visitor::visit(this, (*element)[1]); - if (_return_value != Condition::RFALSE) - { - // retain return, either true or unknown. - return; - } + if (_return_value == Condition::RFALSE) + return; // Retain false + + auto r2 = _return_value; + Visitor::visit(this, (*element)[0]); + if (r2 == Condition::RTRUE && _return_value == Condition::RTRUE) + return; // Retain true + _return_value = Condition::RUNKNOWN; -// TODO: Don't know how to handle this -// Visitor::visit(this, (*element)[0]); } void EvaluateVisitor::_accept(AndCondition *element) { @@ -306,12 +307,15 @@ namespace PetriEngine { namespace PQL { void EvaluateAndSetVisitor::_accept(ReleaseCondition *element) { Visitor::visit(this, (*element)[1]); - if (_return_value != Condition::RFALSE) - return; + if (_return_value == Condition::RFALSE) + return; // Retain false + + auto r2 = _return_value; + Visitor::visit(this, (*element)[0]); + if (r2 == Condition::RTRUE && _return_value == Condition::RTRUE) + return; // Retain true _return_value = Condition::RUNKNOWN; - // TODO: Don't know how to handle this - //Visitor::visit(this, (*element)[0]); } void EvaluateAndSetVisitor::_accept(AndCondition *element) { diff --git a/src/PetriEngine/Stubborn/InterestingTransitionVisitor.cpp b/src/PetriEngine/Stubborn/InterestingTransitionVisitor.cpp index 15192badf..3f499ba1c 100644 --- a/src/PetriEngine/Stubborn/InterestingTransitionVisitor.cpp +++ b/src/PetriEngine/Stubborn/InterestingTransitionVisitor.cpp @@ -33,6 +33,14 @@ namespace PetriEngine { Visitor::visit(this, element->getCond2()); } + void InterestingTransitionVisitor::_accept(const PQL::ReleaseCondition *element) + { + Visitor::visit(this, element->getCond2()); + negate(); + Visitor::visit(this, element->getCond2()); + negate(); + Visitor::visit(this, element->getCond1()); + } void InterestingTransitionVisitor::_accept(const PQL::AndCondition *element) { From ee84d01a4fd0aba7eafccf637d6a2c69e3484714 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 11:42:36 +0100 Subject: [PATCH 07/41] replacing unordered_set with ptrie --- include/LTL/Structures/BitProductStateSet.h | 28 ++++++++------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/include/LTL/Structures/BitProductStateSet.h b/include/LTL/Structures/BitProductStateSet.h index 1458d57a1..4b11deccd 100644 --- a/include/LTL/Structures/BitProductStateSet.h +++ b/include/LTL/Structures/BitProductStateSet.h @@ -20,9 +20,9 @@ #include "PetriEngine/Structures/StateSet.h" #include "LTL/Structures/ProductState.h" + +#include #include -#include -#include namespace LTL { namespace Structures { @@ -39,7 +39,7 @@ namespace LTL { namespace Structures { virtual result_t add(const LTL::Structures::ProductState &state) = 0; - virtual bool decode(LTL::Structures::ProductState &state, stateid_t id) = 0; + virtual void decode(LTL::Structures::ProductState &state, stateid_t id) = 0; virtual void setHistory(stateid_t id, size_t transition) {} @@ -100,9 +100,7 @@ namespace LTL { namespace Structures { return res; } const stateid_t product_id = get_product_id(res.second, state.get_buchi_state()); - - const auto[iter, is_new] = _states.insert(product_id); - assert(iter != std::end(_states)); + auto [is_new, _] = _states.insert(product_id); return std::make_pair(is_new, product_id); } @@ -112,17 +110,13 @@ namespace LTL { namespace Structures { * @param state Output parameter to write product state to. * @return true if the state was successfully retrieved, false otherwise. */ - bool decode(LTL::Structures::ProductState &state, stateid_t id) override + void decode(LTL::Structures::ProductState &state, stateid_t id) override { - const auto it = _states.find(id); - if (it == std::cend(_states)) { - return false; - } - auto marking_id = get_marking_id(*it); - auto buchi_state = get_buchi_state(*it); + assert(_states.exists(id).first); + auto marking_id = get_marking_id(id); + auto buchi_state = get_buchi_state(id); _markings.decode(state, marking_id); state.set_buchi_state(buchi_state); - return true; } //size_t size() { return states.size(); } @@ -136,7 +130,7 @@ namespace LTL { namespace Structures { static constexpr auto BUCHI_SHIFT = 64 - nbits; PetriEngine::Structures::StateSet _markings; - std::unordered_set _states; + ptrie::set _states; static constexpr auto _err_val = std::make_pair(false, std::numeric_limits::max()); size_t _discovered = 0; @@ -151,10 +145,10 @@ namespace LTL { namespace Structures { { } - bool decode(ProductState &state, stateid_t id) override + void decode(ProductState &state, stateid_t id) override { _parent = id; - return BitProductStateSet::decode(state, id); + BitProductStateSet::decode(state, id); } void setHistory(stateid_t id, size_t transition) override From 9b6d39edfb0320f6d5c203975a18946c24bf6cb4 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 11:53:20 +0100 Subject: [PATCH 08/41] changing combination of buchi-id and state id --- include/LTL/Structures/BitProductStateSet.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/include/LTL/Structures/BitProductStateSet.h b/include/LTL/Structures/BitProductStateSet.h index 4b11deccd..b19f26ede 100644 --- a/include/LTL/Structures/BitProductStateSet.h +++ b/include/LTL/Structures/BitProductStateSet.h @@ -59,9 +59,9 @@ namespace LTL { namespace Structures { /** * Bit-hacking product state set for storing pairs (M, q) compactly in 64 bits. * Allows for a max of 2^nbits Büchi states and 2^(64-nbits) markings without overflow. - * @tparam nbits the number of bits to allocate for Büchi state. Defaults to 16-bit. Max is 32-bit. + * @tparam nbits the number of bits to allocate for Büchi state. Defaults to 20-bit. Max is 32-bit. */ - template + template class BitProductStateSet : public ProductStateSetInterface { public: explicit BitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) @@ -78,13 +78,13 @@ namespace LTL { namespace Structures { * size_t stateID; if error it is UINT64_MAX. */ - size_t get_buchi_state(stateid_t id) override { return id >> BUCHI_SHIFT; } + size_t get_buchi_state(stateid_t id) override { return id & BUCHI_MASK; } - size_t get_marking_id(stateid_t id) override { return id & MARKING_MASK; } + size_t get_marking_id(stateid_t id) override { return id >> MARKING_SHIFT; } stateid_t get_product_id(size_t markingId, size_t buchiState) override { - return (buchiState << BUCHI_SHIFT) | (MARKING_MASK & markingId); + return (buchiState & BUCHI_MASK) | (markingId << MARKING_SHIFT); } /** @@ -100,6 +100,8 @@ namespace LTL { namespace Structures { return res; } const stateid_t product_id = get_product_id(res.second, state.get_buchi_state()); + assert(res.second == get_marking_id(product_id)); + assert(state.get_buchi_state() == get_buchi_state(product_id)); auto [is_new, _] = _states.insert(product_id); return std::make_pair(is_new, product_id); } @@ -125,9 +127,9 @@ namespace LTL { namespace Structures { size_t max_tokens() const override { return _markings.maxTokens(); } protected: - static constexpr auto MARKING_MASK = (1LL << (64 - nbits)) - 1; - static constexpr auto BUCHI_MASK = std::numeric_limits::max() ^ MARKING_MASK; - static constexpr auto BUCHI_SHIFT = 64 - nbits; + + static constexpr auto BUCHI_MASK = ~(std::numeric_limits::max() << (nbits)); + static constexpr auto MARKING_SHIFT = nbits; PetriEngine::Structures::StateSet _markings; ptrie::set _states; From c86b86765ae29a62b54d614294ca0d33d735ab38 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 11:56:19 +0100 Subject: [PATCH 09/41] fixed warning --- include/LTL/Algorithm/TarjanModelChecker.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/LTL/Algorithm/TarjanModelChecker.h b/include/LTL/Algorithm/TarjanModelChecker.h index 89958ef5a..8e99969ab 100644 --- a/include/LTL/Algorithm/TarjanModelChecker.h +++ b/include/LTL/Algorithm/TarjanModelChecker.h @@ -49,8 +49,8 @@ namespace LTL { uint32_t kbound) : ModelChecker(net, cond, buchi), _k_bound(kbound) { - if (buchi.buchi().num_states() > 65535) { - throw base_error("Cannot handle Büchi automata larger than 2^16 states"); + if (buchi.buchi().num_states() > 1048576) { + throw base_error("Cannot handle Büchi automata larger than 2^20 states"); } _chash.fill(std::numeric_limits::max()); } From dbee655bee4937ebd3400f8c02829f404491aded Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 12:02:19 +0100 Subject: [PATCH 10/41] more ptries --- include/LTL/Algorithm/NestedDepthFirstSearch.h | 4 +++- src/LTL/Algorithm/NestedDepthFirstSearch.cpp | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/LTL/Algorithm/NestedDepthFirstSearch.h b/include/LTL/Algorithm/NestedDepthFirstSearch.h index bdd78d0ef..62e0c0a23 100644 --- a/include/LTL/Algorithm/NestedDepthFirstSearch.h +++ b/include/LTL/Algorithm/NestedDepthFirstSearch.h @@ -25,6 +25,8 @@ #include "utils/structures/light_deque.h" #include "LTL/Structures/ProductStateFactory.h" +#include + namespace LTL { /** @@ -57,7 +59,7 @@ namespace LTL { LTL::Structures::BitProductStateSet<> _states; - std::unordered_map _markers; + ptrie::map _markers; static constexpr uint8_t MARKER1 = 1; static constexpr uint8_t MARKER2 = 2; size_t _mark_count[3] = {0,0,0}; diff --git a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp index e60302c95..21ba9f9dc 100644 --- a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp +++ b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp @@ -45,13 +45,12 @@ namespace LTL { return std::make_pair(false, stateid); } - auto r = _markers[stateid]; - _markers[stateid] = (MARKER | r); + auto& r = _markers[stateid]; const bool is_new = (r & MARKER) == 0; if(is_new) { ++_mark_count[MARKER]; - } + } else r = (MARKER | r); return std::make_pair(is_new, stateid); } @@ -66,7 +65,7 @@ namespace LTL { State curState = this->_factory.new_state(); { - std::vector initial_states = successor_generator.make_initial_state(); + auto initial_states = successor_generator.make_initial_state(); for (auto &state : initial_states) { auto res = _states.add(state); if (res.first) { From e516015fb2ef1fcf44c513b605216f9a17b248d0 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 14:37:49 +0100 Subject: [PATCH 11/41] fixed markers --- src/LTL/Algorithm/NestedDepthFirstSearch.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp index 21ba9f9dc..437b5b893 100644 --- a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp +++ b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp @@ -40,6 +40,9 @@ namespace LTL { std::pair NestedDepthFirstSearch::mark(State& state, const uint8_t MARKER) { + // technically we could decorate the states here instead of + // maintaining the index twice in the _mark_count. + // this would also spare us one ptrie lookup. auto[_, stateid] = _states.add(state); if (stateid == std::numeric_limits::max()) { return std::make_pair(false, stateid); @@ -49,8 +52,9 @@ namespace LTL { const bool is_new = (r & MARKER) == 0; if(is_new) { + r = (MARKER | r); ++_mark_count[MARKER]; - } else r = (MARKER | r); + } return std::make_pair(is_new, stateid); } From 3b97f17b4a75bbf6119078ccb01267acfde7d110 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 12:04:12 +0100 Subject: [PATCH 12/41] added ltl test --- boost_tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boost_tests/CMakeLists.txt b/boost_tests/CMakeLists.txt index af086aae1..71bcc81b2 100644 --- a/boost_tests/CMakeLists.txt +++ b/boost_tests/CMakeLists.txt @@ -30,7 +30,7 @@ add_test(NAME XMLPrinterTests COMMAND XMLPrinterTests) add_test(NAME PQLParserTests COMMAND PQLParserTests) add_test(NAME PredicateCheckerTests COMMAND PredicateCheckerTests) add_test(NAME reachability COMMAND reachability) -add_test(NAME ltl COMMAND reachability) +add_test(NAME ltl COMMAND ltl) add_test(NAME games COMMAND games) add_test(NAME color COMMAND color) From 0677bc56ed956329d9813cb272708eb34dfc24dd Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 14:48:23 +0100 Subject: [PATCH 13/41] avoiding double-index when tracing --- include/LTL/Structures/BitProductStateSet.h | 33 +++++++-------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/include/LTL/Structures/BitProductStateSet.h b/include/LTL/Structures/BitProductStateSet.h index b19f26ede..5a545d27d 100644 --- a/include/LTL/Structures/BitProductStateSet.h +++ b/include/LTL/Structures/BitProductStateSet.h @@ -61,7 +61,7 @@ namespace LTL { namespace Structures { * Allows for a max of 2^nbits Büchi states and 2^(64-nbits) markings without overflow. * @tparam nbits the number of bits to allocate for Büchi state. Defaults to 20-bit. Max is 32-bit. */ - template + template> class BitProductStateSet : public ProductStateSetInterface { public: explicit BitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) @@ -71,12 +71,6 @@ namespace LTL { namespace Structures { static_assert(nbits <= 32, "Only up to 2^32 Büchi states supported"); static_assert(sizeof(size_t) >= 8, "Expecting size_t to be at least 8 bytes"); - //using stateid_t = size_t; - - /** - * bool success - * size_t stateID; if error it is UINT64_MAX. - */ size_t get_buchi_state(stateid_t id) override { return id & BUCHI_MASK; } @@ -132,46 +126,41 @@ namespace LTL { namespace Structures { static constexpr auto MARKING_SHIFT = nbits; PetriEngine::Structures::StateSet _markings; - ptrie::set _states; + stateset_type _states; static constexpr auto _err_val = std::make_pair(false, std::numeric_limits::max()); size_t _discovered = 0; }; - template - class TraceableBitProductStateSet : public BitProductStateSet { - using stateid_t = typename BitProductStateSet::stateid_t; + template + class TraceableBitProductStateSet : public BitProductStateSet>> { + using stateid_t = typename BitProductStateSet>>::stateid_t; public: explicit TraceableBitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) - : BitProductStateSet(net, kbound) + : BitProductStateSet>>(net, kbound) { } void decode(ProductState &state, stateid_t id) override { _parent = id; - BitProductStateSet::decode(state, id); + BitProductStateSet>>::decode(state, id); } void setHistory(stateid_t id, size_t transition) override { - _history[id] = {_parent, transition}; + assert(this->_states.exists(id).first); + this->_states[id] = {_parent, transition}; } std::pair getHistory(stateid_t stateid) override { - auto[parent, trans] = _history.at(stateid); - return std::make_pair(parent, trans); + assert(this->_states.exists(stateid).first); + return this->_states[stateid]; } private: - struct history_t { - size_t _parent; - size_t _trans; - }; stateid_t _parent = 0; - // product ID to parent ID - std::unordered_map _history; }; } } From 5e3e2f07d08dea66e67e6beb8c2d90b90c263d83 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 15:04:48 +0100 Subject: [PATCH 14/41] switching to faster data-structures for Tarjan also --- include/LTL/Algorithm/TarjanModelChecker.h | 21 +++++---- include/utils/structures/light_deque.h | 8 ++++ src/LTL/Algorithm/TarjanModelChecker.cpp | 54 +++++++++++----------- 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/include/LTL/Algorithm/TarjanModelChecker.h b/include/LTL/Algorithm/TarjanModelChecker.h index 8e99969ab..ff19dd46a 100644 --- a/include/LTL/Algorithm/TarjanModelChecker.h +++ b/include/LTL/Algorithm/TarjanModelChecker.h @@ -24,10 +24,11 @@ #include "LTL/Structures/BitProductStateSet.h" #include "LTL/SuccessorGeneration/ResumingSuccessorGenerator.h" #include "LTL/SuccessorGeneration/SpoolingSuccessorGenerator.h" +#include "utils/structures/light_deque.h" + +#include #include -#include -#include namespace LTL { @@ -77,7 +78,7 @@ namespace LTL { // 64 MB hash table static constexpr idx_t _hash_sz = 16777216; - std::unordered_set _store; + ptrie::set _store; // rudimentary hash table of state IDs. chash[hash(state)] is the top index in cstack // corresponding to state. Collisions are resolved using linked list via CEntry::next. @@ -114,7 +115,7 @@ namespace LTL { // cstack positions of accepting states in current search path, for quick access. - std::stack _astack; + light_deque _astack; bool _invariant_loop = true; size_t _loop_state = std::numeric_limits::max(); @@ -126,22 +127,22 @@ namespace LTL { // TODO, instead of this template hell, we should really just have a templated state that we shuffle around. template - void push(std::vector& cstack, std::stack& dstack, S& successor_generator, State &state, size_t stateid); + void push(light_deque& cstack, light_deque& dstack, S& successor_generator, State &state, size_t stateid); template - void pop(S& seen, std::vector& cstack, std::stack& dstack, SuccGen& successorGenerator); + void pop(S& seen, light_deque& cstack, light_deque& dstack, SuccGen& successorGenerator); template - void update(std::vector& cstack, std::stack& d, SuccGen& successorGenerator, idx_t to); + void update(light_deque& cstack, light_deque& d, SuccGen& successorGenerator, idx_t to); template - bool next_trans(S& seen, std::vector& cstack, SuccGen& successorGenerator, State &state, State &parent, D &delem); + bool next_trans(S& seen, light_deque& cstack, SuccGen& successorGenerator, State &state, State &parent, D &delem); template - void popCStack(std::vector& cstack); + void popCStack(light_deque& cstack); template - void build_trace(S& seen, std::stack &&dstack, std::vector& cstack); + void build_trace(S& seen, light_deque &&dstack, light_deque& cstack); }; } diff --git a/include/utils/structures/light_deque.h b/include/utils/structures/light_deque.h index 1d464ab0d..96bc1c459 100644 --- a/include/utils/structures/light_deque.h +++ b/include/utils/structures/light_deque.h @@ -140,6 +140,14 @@ class light_deque return &_data[_back]; } + const T& operator[](size_t i) const { + return *(begin() + i); + } + + T& operator[](size_t i) { + return *(begin() + i); + } + private: void expand() { T* ndata = (T*)new uint8_t[_size*2*sizeof(T)]; diff --git a/src/LTL/Algorithm/TarjanModelChecker.cpp b/src/LTL/Algorithm/TarjanModelChecker.cpp index b36b3e813..f990f1ef7 100644 --- a/src/LTL/Algorithm/TarjanModelChecker.cpp +++ b/src/LTL/Algorithm/TarjanModelChecker.cpp @@ -102,9 +102,9 @@ namespace LTL { StateSet seen(_net, _k_bound); // master list of state information. - std::vector cstack; + light_deque cstack; // depth-first search stack, contains current search path. - std::stack> dstack; + light_deque> dstack; _is_weak = successorGenerator.is_weak() && _shortcircuitweak; auto initial_states = successorGenerator.make_initial_state(); @@ -117,7 +117,7 @@ namespace LTL { push(cstack, dstack, successorGenerator, state, res.second); } while (!dstack.empty() && !_violation) { - auto &dtop = dstack.top(); + auto &dtop = dstack.back(); // write next successor state to working. if (!next_trans(seen, cstack, successorGenerator, working, parent, dtop)) { ++_expanded; @@ -172,17 +172,17 @@ namespace LTL { update(cstack, dstack, successorGenerator, suc_pos); continue; } - if (_store.find(stateid) == std::end(_store)) { + if (!_store.exists(stateid).first) { push(cstack, dstack, successorGenerator, working, stateid); } } if constexpr (SaveTrace) { // print counter-example if it exists. if (_violation) { - std::stack> revstack; + light_deque> revstack; while (!dstack.empty()) { - revstack.push(std::move(dstack.top())); - dstack.pop(); + revstack.push_back(std::move(dstack.back())); + dstack.pop_back(); } build_trace(seen, std::move(revstack), cstack); } @@ -198,14 +198,14 @@ namespace LTL { * @param state */ template - void TarjanModelChecker::push(std::vector& cstack, std::stack& dstack, S& successor_generator, State &state, size_t stateid) { + void TarjanModelChecker::push(light_deque& cstack, light_deque& dstack, S& successor_generator, State &state, size_t stateid) { const auto ctop = static_cast(cstack.size()); const auto h = hash(stateid); - cstack.emplace_back(ctop, stateid, _chash[h]); + cstack.push_back(T{ctop, stateid, _chash[h]}); _chash[h] = ctop; - dstack.push(D{ctop}); + dstack.push_back(D{ctop}); if (successor_generator.is_accepting(state)) { - _astack.push(ctop); + _astack.push_back(ctop); if (successor_generator.has_invariant_self_loop(state)){ _violation = true; _invariant_loop = true; @@ -217,10 +217,10 @@ namespace LTL { } template - void TarjanModelChecker::pop(S& seen, std::vector& cstack, std::stack& dstack, SuccGen& successorGenerator) + void TarjanModelChecker::pop(S& seen, light_deque& cstack, light_deque& dstack, SuccGen& successorGenerator) { - const auto p = dstack.top()._pos; - dstack.pop(); + const auto p = dstack.back()._pos; + dstack.pop_back(); cstack[p]._dstack = false; if (cstack[p]._lowlink == p) { while (cstack.size() > p) { @@ -233,19 +233,19 @@ namespace LTL { popCStack(cstack); } } - if (!_astack.empty() && p == _astack.top()) { - _astack.pop(); + if (!_astack.empty() && p == _astack.back()) { + _astack.pop_back(); } if (!dstack.empty()) { update(cstack, dstack, successorGenerator, p); if constexpr (is_spooling()) { - successorGenerator.pop(dstack.top()._sucinfo); + successorGenerator.pop(dstack.back()._sucinfo); } } } template - void TarjanModelChecker::popCStack(std::vector& cstack) + void TarjanModelChecker::popCStack(light_deque& cstack) { auto h = hash(cstack.back()._stateid); _store.insert(cstack.back()._stateid); @@ -255,15 +255,15 @@ namespace LTL { template - void TarjanModelChecker::update(std::vector& cstack, std::stack& dstack, SuccGen& successorGenerator, idx_t to) + void TarjanModelChecker::update(light_deque& cstack, light_deque& dstack, SuccGen& successorGenerator, idx_t to) { - const auto from = dstack.top()._pos; + const auto from = dstack.back()._pos; assert(cstack[to]._lowlink != std::numeric_limits::max() && cstack[from]._lowlink != std::numeric_limits::max()); if (cstack[to]._lowlink <= cstack[from]._lowlink) { // we have now found a loop into earlier seen component cstack[to].lowlink. // if this earlier component precedes an accepting state, // the found loop is accepting and thus a violation. - _violation = (!_astack.empty() && to <= _astack.top()); + _violation = (!_astack.empty() && to <= _astack.back()); // either way update the component ID of the state we came from. cstack[from]._lowlink = cstack[to]._lowlink; if constexpr (T::save_trace()) { @@ -275,7 +275,7 @@ namespace LTL { } template - bool TarjanModelChecker::next_trans(S& seen, std::vector& cstack, SuccGen& successorGenerator, State &state, State &parent, D &delem) + bool TarjanModelChecker::next_trans(S& seen, light_deque& cstack, SuccGen& successorGenerator, State &state, State &parent, D &delem) { seen.decode(parent, cstack[delem._pos]._stateid); successorGenerator.prepare(&parent, delem._sucinfo); @@ -288,18 +288,18 @@ namespace LTL { } template - void TarjanModelChecker::build_trace(S& seen, std::stack &&dstack, std::vector& cstack) + void TarjanModelChecker::build_trace(S& seen, light_deque &&dstack, light_deque& cstack) { assert(_violation); - if (cstack[dstack.top()._pos]._stateid == _loop_state) + if (cstack[dstack.back()._pos]._stateid == _loop_state) _loop = _trace.size(); - dstack.pop(); + dstack.pop_back(); unsigned long p; bool had_deadlock = false; // print (reverted) dstack while (!dstack.empty()) { - p = dstack.top()._pos; - dstack.pop(); + p = dstack.back()._pos; + dstack.pop_back(); auto stateid = cstack[p]._stateid; auto[parent, tid] = seen.getHistory(stateid); _trace.emplace_back(tid); From f34d36beb0a035c94e0b63250730704c6a8bdd11 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 15:20:04 +0100 Subject: [PATCH 15/41] avoiding decoding --- src/LTL/Algorithm/TarjanModelChecker.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/LTL/Algorithm/TarjanModelChecker.cpp b/src/LTL/Algorithm/TarjanModelChecker.cpp index f990f1ef7..18b6f8d57 100644 --- a/src/LTL/Algorithm/TarjanModelChecker.cpp +++ b/src/LTL/Algorithm/TarjanModelChecker.cpp @@ -227,9 +227,8 @@ namespace LTL { popCStack(cstack); } } else if (this->_is_weak) { - State state = this->_factory.new_state(); - seen.decode(state, cstack[p]._stateid); - if (!successorGenerator.is_accepting(state)) { + auto bstate = seen.get_buchi_state(cstack[p]._stateid); + if (!_buchi.buchi().state_is_accepting(bstate)) { popCStack(cstack); } } From 93e59d36c44bdd4eb598019d319772dc4576eb63 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 15:42:25 +0100 Subject: [PATCH 16/41] removing double-lookup for NDFS --- .../LTL/Algorithm/NestedDepthFirstSearch.h | 2 +- include/LTL/Structures/BitProductStateSet.h | 32 +++++++++++-------- src/LTL/Algorithm/NestedDepthFirstSearch.cpp | 10 +++--- src/LTL/Algorithm/TarjanModelChecker.cpp | 12 +++---- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/include/LTL/Algorithm/NestedDepthFirstSearch.h b/include/LTL/Algorithm/NestedDepthFirstSearch.h index 62e0c0a23..62dc7d671 100644 --- a/include/LTL/Algorithm/NestedDepthFirstSearch.h +++ b/include/LTL/Algorithm/NestedDepthFirstSearch.h @@ -57,7 +57,7 @@ namespace LTL { using State = LTL::Structures::ProductState; std::pair mark(State& state, uint8_t); - LTL::Structures::BitProductStateSet<> _states; + LTL::Structures::BitProductStateSet> _states; ptrie::map _markers; static constexpr uint8_t MARKER1 = 1; diff --git a/include/LTL/Structures/BitProductStateSet.h b/include/LTL/Structures/BitProductStateSet.h index 5a545d27d..6816078d5 100644 --- a/include/LTL/Structures/BitProductStateSet.h +++ b/include/LTL/Structures/BitProductStateSet.h @@ -29,7 +29,7 @@ namespace LTL { namespace Structures { class ProductStateSetInterface { public: using stateid_t = size_t; - using result_t = std::pair; + using result_t = std::tuple; virtual size_t get_buchi_state(stateid_t id) = 0; @@ -41,9 +41,9 @@ namespace LTL { namespace Structures { virtual void decode(LTL::Structures::ProductState &state, stateid_t id) = 0; - virtual void setHistory(stateid_t id, size_t transition) {} + virtual void set_history(stateid_t id, size_t transition) {} - virtual std::pair getHistory(stateid_t stateid) + virtual std::pair get_history(stateid_t stateid) { return std::make_pair(std::numeric_limits::max(), std::numeric_limits::max()); } @@ -61,7 +61,7 @@ namespace LTL { namespace Structures { * Allows for a max of 2^nbits Büchi states and 2^(64-nbits) markings without overflow. * @tparam nbits the number of bits to allocate for Büchi state. Defaults to 20-bit. Max is 32-bit. */ - template> + template, uint8_t nbits = 20> class BitProductStateSet : public ProductStateSetInterface { public: explicit BitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) @@ -91,13 +91,18 @@ namespace LTL { namespace Structures { ++_discovered; const auto res = _markings.add(state); if (res.second == std::numeric_limits::max()) { - return res; + return {res.first, res.second, res.second}; } const stateid_t product_id = get_product_id(res.second, state.get_buchi_state()); assert(res.second == get_marking_id(product_id)); assert(state.get_buchi_state() == get_buchi_state(product_id)); - auto [is_new, _] = _states.insert(product_id); - return std::make_pair(is_new, product_id); + auto [is_new, data_id] = _states.insert(product_id); + return {is_new, product_id, data_id}; + } + + + auto& get_data(size_t data_id) { + return _states.get_data(data_id); } /** @@ -115,7 +120,6 @@ namespace LTL { namespace Structures { state.set_buchi_state(buchi_state); } - //size_t size() { return states.size(); } size_t discovered() const override { return _discovered; } size_t max_tokens() const override { return _markings.maxTokens(); } @@ -133,27 +137,27 @@ namespace LTL { namespace Structures { }; template - class TraceableBitProductStateSet : public BitProductStateSet>> { - using stateid_t = typename BitProductStateSet>>::stateid_t; + class TraceableBitProductStateSet : public BitProductStateSet>, nbits> { + using stateid_t = typename BitProductStateSet>, nbits>::stateid_t; public: explicit TraceableBitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) - : BitProductStateSet>>(net, kbound) + : BitProductStateSet>,nbits>(net, kbound) { } void decode(ProductState &state, stateid_t id) override { _parent = id; - BitProductStateSet>>::decode(state, id); + BitProductStateSet>,nbits>::decode(state, id); } - void setHistory(stateid_t id, size_t transition) override + void set_history(stateid_t id, size_t transition) override { assert(this->_states.exists(id).first); this->_states[id] = {_parent, transition}; } - std::pair getHistory(stateid_t stateid) override + std::pair get_history(stateid_t stateid) override { assert(this->_states.exists(stateid).first); return this->_states[stateid]; diff --git a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp index 437b5b893..5ae9fe528 100644 --- a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp +++ b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp @@ -43,12 +43,12 @@ namespace LTL { // technically we could decorate the states here instead of // maintaining the index twice in the _mark_count. // this would also spare us one ptrie lookup. - auto[_, stateid] = _states.add(state); + auto[_, stateid, data_id] = _states.add(state); if (stateid == std::numeric_limits::max()) { return std::make_pair(false, stateid); } - auto& r = _markers[stateid]; + auto& r = _states.get_data(data_id); const bool is_new = (r & MARKER) == 0; if(is_new) { @@ -72,8 +72,8 @@ namespace LTL { auto initial_states = successor_generator.make_initial_state(); for (auto &state : initial_states) { auto res = _states.add(state); - if (res.first) { - todo.push_back(stack_entry_t{res.second, T::initial_suc_info()}); + if (std::get<0>(res)) { + todo.push_back(stack_entry_t{std::get<1>(res), T::initial_suc_info()}); } } } @@ -127,7 +127,7 @@ namespace LTL { State working = _factory.new_state(); State curState = _factory.new_state(); - nested_todo.push_back(stack_entry_t{_states.add(state).second, T::initial_suc_info()}); + nested_todo.push_back(stack_entry_t{std::get<1>(_states.add(state)), T::initial_suc_info()}); while (!nested_todo.empty()) { auto &top = nested_todo.back(); diff --git a/src/LTL/Algorithm/TarjanModelChecker.cpp b/src/LTL/Algorithm/TarjanModelChecker.cpp index 18b6f8d57..ef40a4fa3 100644 --- a/src/LTL/Algorithm/TarjanModelChecker.cpp +++ b/src/LTL/Algorithm/TarjanModelChecker.cpp @@ -113,8 +113,8 @@ namespace LTL { for (auto &state : initial_states) { if(_violation) break; const auto res = seen.add(state); - if (res.first) { - push(cstack, dstack, successorGenerator, state, res.second); + if (std::get<0>(res)) { + push(cstack, dstack, successorGenerator, state, std::get<1>(res)); } while (!dstack.empty() && !_violation) { auto &dtop = dstack.back(); @@ -137,14 +137,14 @@ namespace LTL { } #endif ++_explored; - const auto[isnew, stateid] = seen.add(working); + const auto[isnew, stateid, _] = seen.add(working); if (stateid == std::numeric_limits::max()) { continue; } if constexpr (SaveTrace) { if (isnew) { - seen.setHistory(stateid, successorGenerator.fired()); + seen.set_history(stateid, successorGenerator.fired()); } } @@ -300,7 +300,7 @@ namespace LTL { p = dstack.back()._pos; dstack.pop_back(); auto stateid = cstack[p]._stateid; - auto[parent, tid] = seen.getHistory(stateid); + auto[parent, tid] = seen.get_history(stateid); _trace.emplace_back(tid); if(tid >= std::numeric_limits::max() - 1) { @@ -316,7 +316,7 @@ namespace LTL { { p = cstack[p]._lowsource; while (cstack[p]._lowlink != std::numeric_limits::max()) { - auto[parent, tid] = seen.getHistory(cstack[p]._stateid); + auto[parent, tid] = seen.get_history(cstack[p]._stateid); _trace.emplace_back(tid); if(tid >= std::numeric_limits::max() - 1) { From 7f7d39c2454793bb1c2c3b35c90d7668b63af863 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 15:59:12 +0100 Subject: [PATCH 17/41] more precise weak-skip --- include/LTL/Algorithm/ModelChecker.h | 3 +-- .../ProductSuccessorGenerator.h | 9 ++++++++- src/LTL/Algorithm/NestedDepthFirstSearch.cpp | 7 ++----- src/LTL/Algorithm/TarjanModelChecker.cpp | 14 ++++++++------ 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/LTL/Algorithm/ModelChecker.h b/include/LTL/Algorithm/ModelChecker.h index e7c1a3f19..febf514d5 100644 --- a/include/LTL/Algorithm/ModelChecker.h +++ b/include/LTL/Algorithm/ModelChecker.h @@ -61,7 +61,7 @@ namespace LTL { virtual ~ModelChecker() = default; [[nodiscard]] bool is_weak() const { - return _is_weak; + return _shortcircuitweak; } size_t get_explored() { @@ -107,7 +107,6 @@ namespace LTL { const Structures::BuchiAutomaton& _buchi; bool _shortcircuitweak; bool _weakskip = false; - bool _is_weak = false; bool _build_trace = false; Heuristic* _heuristic = nullptr; size_t _loop = std::numeric_limits::max(); diff --git a/include/LTL/SuccessorGeneration/ProductSuccessorGenerator.h b/include/LTL/SuccessorGeneration/ProductSuccessorGenerator.h index 17a1581db..72cfb6663 100644 --- a/include/LTL/SuccessorGeneration/ProductSuccessorGenerator.h +++ b/include/LTL/SuccessorGeneration/ProductSuccessorGenerator.h @@ -83,6 +83,11 @@ namespace LTL { } } + bool is_accepting(size_t b_state) + { + return _buchi_succ_gen.is_accepting(b_state); + } + bool is_accepting(const LTL::Structures::ProductState &state) { return _buchi_succ_gen.is_accepting(state.get_buchi_state()); @@ -235,7 +240,9 @@ namespace LTL { return _buchi_succ_gen.has_invariant_self_loop(state.get_buchi_state()); } - + bool has_invariant_self_loop(size_t bstate) { + return _buchi_succ_gen.has_invariant_self_loop(bstate); + } virtual ~ProductSuccessorGenerator() = default; diff --git a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp index 5ae9fe528..714477ee9 100644 --- a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp +++ b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp @@ -61,7 +61,6 @@ namespace LTL { template void NestedDepthFirstSearch::dfs(ProductSuccessorGenerator& successor_generator) { - this->_is_weak = successor_generator.is_weak() && this->_shortcircuitweak; light_deque> todo; light_deque> nested_todo; @@ -106,7 +105,8 @@ namespace LTL { } top._sucinfo._last_state = stateid; if (is_new) { - if(successor_generator.is_accepting(curState) && + if(_shortcircuitweak && + successor_generator.is_accepting(curState) && successor_generator.has_invariant_self_loop(curState)) { _violation = true; @@ -139,9 +139,6 @@ namespace LTL { if (!successor_generator.next(working, top._sucinfo)) { nested_todo.pop_back(); } else { - if (this->_is_weak && !successor_generator.is_accepting(working)) { - continue; - } if (working == state) { _violation = true; return; diff --git a/src/LTL/Algorithm/TarjanModelChecker.cpp b/src/LTL/Algorithm/TarjanModelChecker.cpp index ef40a4fa3..720112478 100644 --- a/src/LTL/Algorithm/TarjanModelChecker.cpp +++ b/src/LTL/Algorithm/TarjanModelChecker.cpp @@ -106,7 +106,6 @@ namespace LTL { // depth-first search stack, contains current search path. light_deque> dstack; - _is_weak = successorGenerator.is_weak() && _shortcircuitweak; auto initial_states = successorGenerator.make_initial_state(); State working = _factory.new_state(); State parent = _factory.new_state(); @@ -173,6 +172,14 @@ namespace LTL { continue; } if (!_store.exists(stateid).first) { + auto bstate = seen.get_buchi_state(stateid); + if(_weakskip && + successorGenerator.is_accepting(bstate) && + successorGenerator.has_invariant_self_loop(bstate)) + { + _violation = true; + break; + } push(cstack, dstack, successorGenerator, working, stateid); } } @@ -226,11 +233,6 @@ namespace LTL { while (cstack.size() > p) { popCStack(cstack); } - } else if (this->_is_weak) { - auto bstate = seen.get_buchi_state(cstack[p]._stateid); - if (!_buchi.buchi().state_is_accepting(bstate)) { - popCStack(cstack); - } } if (!_astack.empty() && p == _astack.back()) { _astack.pop_back(); From ddcb9c160491de7abc485bb648680565959ad7af Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 16:08:23 +0100 Subject: [PATCH 18/41] added test-timeout --- boost_tests/color_test.cpp | 17 +++++++++-------- boost_tests/game_test.cpp | 23 ++++++++++++----------- boost_tests/ltl_test.cpp | 5 +++-- boost_tests/reachability_test.cpp | 5 +++-- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/boost_tests/color_test.cpp b/boost_tests/color_test.cpp index e9179c363..8f18a70b9 100644 --- a/boost_tests/color_test.cpp +++ b/boost_tests/color_test.cpp @@ -27,13 +27,14 @@ using namespace PetriEngine; using namespace PetriEngine::Colored; +namespace utf = boost::unit_test; BOOST_AUTO_TEST_CASE(DirectoryTest) { BOOST_REQUIRE(getenv("TEST_FILES")); } -BOOST_AUTO_TEST_CASE(InitialMarkingMismatch) { +BOOST_AUTO_TEST_CASE(InitialMarkingMismatch, * utf::timeout(5)) { std::string model("/models/color_mismatch.pnml"); std::string query("/models/color_mismatch.xml"); @@ -49,7 +50,7 @@ BOOST_AUTO_TEST_CASE(InitialMarkingMismatch) { BOOST_REQUIRE(saw_exception); } -BOOST_AUTO_TEST_CASE(InitialMarkingMatch) { +BOOST_AUTO_TEST_CASE(InitialMarkingMatch, * utf::timeout(5)) { std::string model("/models/color_match.pnml"); std::string query("/models/color_match.xml"); @@ -69,7 +70,7 @@ BOOST_AUTO_TEST_CASE(InitialMarkingMatch) { } -BOOST_AUTO_TEST_CASE(PhilosophersDynCOL03) { +BOOST_AUTO_TEST_CASE(PhilosophersDynCOL03, * utf::timeout(60)) { std::string model("/models/PhilosophersDyn-COL-03/model.pnml"); std::string query("/models/PhilosophersDyn-COL-03/ReachabilityCardinality.xml"); @@ -124,7 +125,7 @@ BOOST_AUTO_TEST_CASE(PhilosophersDynCOL03) { } } -BOOST_AUTO_TEST_CASE(PetersonCOL2) { +BOOST_AUTO_TEST_CASE(PetersonCOL2, * utf::timeout(60)) { std::string model("/models/Peterson-COL-2/model.pnml"); std::string query("/models/Peterson-COL-2/ReachabilityCardinality.xml"); @@ -188,11 +189,11 @@ BOOST_AUTO_TEST_CASE(PetersonCOL2) { } -BOOST_AUTO_TEST_CASE(UtilityControlRoomCOLZ2T3N04) { +BOOST_AUTO_TEST_CASE(UtilityControlRoomCOLZ2T3N04, * utf::timeout(60)) { std::string model("/models/UtilityControlRoom-COL-Z2T3N04/model.pnml"); std::string query("/models/UtilityControlRoom-COL-Z2T3N04/ReachabilityCardinality.xml"); - // this model is to large to verify as a test, but unfolding should be ok. + // this model is to large too verify as a test, but unfolding should be ok. // the unfolding provoked an error in the CFP of colored nets. std::set qnums{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; for(auto partition : {false, true}) @@ -219,11 +220,11 @@ BOOST_AUTO_TEST_CASE(UtilityControlRoomCOLZ2T3N04) { } } -BOOST_AUTO_TEST_CASE(NeoElectionCOL3) { +BOOST_AUTO_TEST_CASE(NeoElectionCOL3, * utf::timeout(60)) { std::string model("/models/NeoElection-COL-3/model.pnml"); std::string query("/models/NeoElection-COL-3/ReachabilityCardinality.xml"); - // this model is to large to verify as a test, but unfolding should be ok. + // this model is to large too verify as a test, but unfolding should be ok. // the unfolding provoked an error in the CFP of colored nets. std::set qnums{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; for(auto partition : {false, true}) diff --git a/boost_tests/game_test.cpp b/boost_tests/game_test.cpp index 688d65ae7..e611d80bf 100644 --- a/boost_tests/game_test.cpp +++ b/boost_tests/game_test.cpp @@ -26,6 +26,7 @@ using namespace PetriEngine; using namespace PetriEngine::Synthesis; +namespace utf = boost::unit_test; BOOST_AUTO_TEST_CASE(DirectoryTest) { BOOST_REQUIRE(getenv("TEST_FILES")); @@ -56,7 +57,7 @@ void test_single_game(const char* fn, Reachability::ResultPrinter::Result expect } -BOOST_AUTO_TEST_CASE(Algorithm1Counterexample) { +BOOST_AUTO_TEST_CASE(Algorithm1Counterexample, * utf::timeout(5)) { std::cerr << "Q1" << std::endl; test_single_game("algorithm 1 counterexample", Reachability::ResultPrinter::NotSatisfied, 0); std::cerr << "Q2" << std::endl; @@ -67,43 +68,43 @@ BOOST_AUTO_TEST_CASE(Algorithm1Counterexample) { test_single_game("algorithm 1 counterexample", Reachability::ResultPrinter::Satisfied, 3); } -BOOST_AUTO_TEST_CASE(Algorithm1Counterexample2) { +BOOST_AUTO_TEST_CASE(Algorithm1Counterexample2, * utf::timeout(5)) { test_single_game("algorithm 1 counterexample 2", Reachability::ResultPrinter::Satisfied); } -BOOST_AUTO_TEST_CASE(CycleTestFalse) { +BOOST_AUTO_TEST_CASE(CycleTestFalse, * utf::timeout(5)) { test_single_game("cycle test false", Reachability::ResultPrinter::Satisfied); } -BOOST_AUTO_TEST_CASE(CycleTestTrue2) { +BOOST_AUTO_TEST_CASE(CycleTestTrue2, * utf::timeout(5)) { test_single_game("cycle test true 2", Reachability::ResultPrinter::Satisfied); } -BOOST_AUTO_TEST_CASE(CycleTestTrue3) { +BOOST_AUTO_TEST_CASE(CycleTestTrue3, * utf::timeout(5)) { test_single_game("cycle test true 3", Reachability::ResultPrinter::Satisfied); } -BOOST_AUTO_TEST_CASE(Player2LessReduction) { +BOOST_AUTO_TEST_CASE(Player2LessReduction, * utf::timeout(5)) { test_single_game("player 2 less reduction", Reachability::ResultPrinter::NotSatisfied); } -BOOST_AUTO_TEST_CASE(Player2) { +BOOST_AUTO_TEST_CASE(Player2, * utf::timeout(5)) { test_single_game("player 2", Reachability::ResultPrinter::Satisfied); } -BOOST_AUTO_TEST_CASE(SafeTest) { +BOOST_AUTO_TEST_CASE(SafeTest, * utf::timeout(5)) { test_single_game("safe test", Reachability::ResultPrinter::Satisfied); } -BOOST_AUTO_TEST_CASE(UnsafeTest) { +BOOST_AUTO_TEST_CASE(UnsafeTest, * utf::timeout(5)) { test_single_game("unsafe test", Reachability::ResultPrinter::Satisfied); } -BOOST_AUTO_TEST_CASE(AGPorFail) { +BOOST_AUTO_TEST_CASE(AGPorFail, * utf::timeout(5)) { test_single_game("AG_por_fail", Reachability::ResultPrinter::NotSatisfied); } -BOOST_AUTO_TEST_CASE(GenModel0PorSuccFail) { +BOOST_AUTO_TEST_CASE(GenModel0PorSuccFail, * utf::timeout(5)) { test_single_game("gen_model_0", Reachability::ResultPrinter::NotSatisfied); } \ No newline at end of file diff --git a/boost_tests/ltl_test.cpp b/boost_tests/ltl_test.cpp index 876afb4b1..51806f1bf 100644 --- a/boost_tests/ltl_test.cpp +++ b/boost_tests/ltl_test.cpp @@ -27,13 +27,14 @@ using namespace PetriEngine; using namespace PetriEngine::Colored; +namespace utf = boost::unit_test; BOOST_AUTO_TEST_CASE(DirectoryTest) { BOOST_REQUIRE(getenv("TEST_FILES")); } -BOOST_AUTO_TEST_CASE(AngiogenesisPT01LTLCardinality) { +BOOST_AUTO_TEST_CASE(AngiogenesisPT01LTLCardinality, * utf::timeout(300)) { std::set qnums{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; std::vector expected{ @@ -85,7 +86,7 @@ BOOST_AUTO_TEST_CASE(AngiogenesisPT01LTLCardinality) { } } -BOOST_AUTO_TEST_CASE(AngiogenesisPT01ReachabilityFireability) { +BOOST_AUTO_TEST_CASE(AngiogenesisPT01ReachabilityFireability, * utf::timeout(300)) { std::set qnums{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; std::vector expected{ diff --git a/boost_tests/reachability_test.cpp b/boost_tests/reachability_test.cpp index 8178b703b..b91ba50df 100644 --- a/boost_tests/reachability_test.cpp +++ b/boost_tests/reachability_test.cpp @@ -25,12 +25,13 @@ using namespace PetriEngine; using namespace PetriEngine::Colored; +namespace utf = boost::unit_test; BOOST_AUTO_TEST_CASE(DirectoryTest) { BOOST_REQUIRE(getenv("TEST_FILES")); } -BOOST_AUTO_TEST_CASE(AngiogenesisPT01ReachabilityCardinality) { +BOOST_AUTO_TEST_CASE(AngiogenesisPT01ReachabilityCardinality, * utf::timeout(60)) { std::set qnums{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; std::vector expected{ @@ -72,7 +73,7 @@ BOOST_AUTO_TEST_CASE(AngiogenesisPT01ReachabilityCardinality) { } } -BOOST_AUTO_TEST_CASE(AngiogenesisPT01ReachabilityFireability) { +BOOST_AUTO_TEST_CASE(AngiogenesisPT01ReachabilityFireability, * utf::timeout(60)) { std::set qnums{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; std::vector expected{ From 1872b17f243c15c84d51dbd8bd8a9f986c10b8d9 Mon Sep 17 00:00:00 2001 From: pgj Date: Sun, 20 Feb 2022 19:48:03 +0100 Subject: [PATCH 19/41] fixed hashing issue --- include/LTL/Algorithm/TarjanModelChecker.h | 12 +++--- include/LTL/Structures/BitProductStateSet.h | 12 ++---- src/LTL/Algorithm/TarjanModelChecker.cpp | 41 +++++++++------------ 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/include/LTL/Algorithm/TarjanModelChecker.h b/include/LTL/Algorithm/TarjanModelChecker.h index ff19dd46a..93e513eb3 100644 --- a/include/LTL/Algorithm/TarjanModelChecker.h +++ b/include/LTL/Algorithm/TarjanModelChecker.h @@ -85,9 +85,9 @@ namespace LTL { std::array _chash; static_assert(sizeof(_chash) == (1U << 27U)); - static inline idx_t hash(idx_t id) + static inline idx_t hash(idx_t buchi_state, idx_t marking_id) { - return id % _hash_sz; + return (buchi_state xor marking_id) % _hash_sz; } struct plain_centry_t { @@ -126,8 +126,8 @@ namespace LTL { LTLPartialOrder _order = LTLPartialOrder::None; // TODO, instead of this template hell, we should really just have a templated state that we shuffle around. - template - void push(light_deque& cstack, light_deque& dstack, S& successor_generator, State &state, size_t stateid); + template + void push(StateSet& s, light_deque& cstack, light_deque& dstack, S& successor_generator, State &state, size_t stateid); template void pop(S& seen, light_deque& cstack, light_deque& dstack, SuccGen& successorGenerator); @@ -138,8 +138,8 @@ namespace LTL { template bool next_trans(S& seen, light_deque& cstack, SuccGen& successorGenerator, State &state, State &parent, D &delem); - template - void popCStack(light_deque& cstack); + template + void popCStack(StateSet& s, light_deque& cstack); template void build_trace(S& seen, light_deque &&dstack, light_deque& cstack); diff --git a/include/LTL/Structures/BitProductStateSet.h b/include/LTL/Structures/BitProductStateSet.h index 6816078d5..4a533d298 100644 --- a/include/LTL/Structures/BitProductStateSet.h +++ b/include/LTL/Structures/BitProductStateSet.h @@ -31,12 +31,6 @@ namespace LTL { namespace Structures { using stateid_t = size_t; using result_t = std::tuple; - virtual size_t get_buchi_state(stateid_t id) = 0; - - virtual size_t get_marking_id(stateid_t id) = 0; - - virtual stateid_t get_product_id(size_t markingId, size_t buchiState) = 0; - virtual result_t add(const LTL::Structures::ProductState &state) = 0; virtual void decode(LTL::Structures::ProductState &state, stateid_t id) = 0; @@ -72,11 +66,11 @@ namespace LTL { namespace Structures { static_assert(nbits <= 32, "Only up to 2^32 Büchi states supported"); static_assert(sizeof(size_t) >= 8, "Expecting size_t to be at least 8 bytes"); - size_t get_buchi_state(stateid_t id) override { return id & BUCHI_MASK; } + static size_t get_buchi_state(stateid_t id) { return id & BUCHI_MASK; } - size_t get_marking_id(stateid_t id) override { return id >> MARKING_SHIFT; } + static size_t get_marking_id(stateid_t id) { return id >> MARKING_SHIFT; } - stateid_t get_product_id(size_t markingId, size_t buchiState) override + static stateid_t get_product_id(size_t markingId, size_t buchiState) { return (buchiState & BUCHI_MASK) | (markingId << MARKING_SHIFT); } diff --git a/src/LTL/Algorithm/TarjanModelChecker.cpp b/src/LTL/Algorithm/TarjanModelChecker.cpp index 720112478..2ff1bd589 100644 --- a/src/LTL/Algorithm/TarjanModelChecker.cpp +++ b/src/LTL/Algorithm/TarjanModelChecker.cpp @@ -84,11 +84,6 @@ namespace LTL { compute(successorGenerator); } - template - constexpr bool is_spooling() { - return std::is_same_v; - } - template bool TarjanModelChecker::compute(SuccGen& successorGenerator) @@ -113,7 +108,7 @@ namespace LTL { if(_violation) break; const auto res = seen.add(state); if (std::get<0>(res)) { - push(cstack, dstack, successorGenerator, state, std::get<1>(res)); + push(seen, cstack, dstack, successorGenerator, state, std::get<1>(res)); } while (!dstack.empty() && !_violation) { auto &dtop = dstack.back(); @@ -150,20 +145,20 @@ namespace LTL { dtop._sucinfo._last_state = stateid; // lookup successor in 'hash' table - auto suc_pos = _chash[hash(stateid)]; - auto marking = seen.get_marking_id(stateid); + auto marking = StateSet::get_marking_id(stateid); + auto suc_pos = _chash[hash(marking, StateSet::get_buchi_state(stateid))]; while (suc_pos != std::numeric_limits::max() && cstack[suc_pos]._stateid != stateid) { - if constexpr (is_spooling()) { - if (cstack[suc_pos]._dstack && seen.get_marking_id(cstack[suc_pos]._stateid) == marking) { + if constexpr (std::is_same::value) { + if (cstack[suc_pos]._dstack && StateSet::get_marking_id(cstack[suc_pos]._stateid) == marking) { successorGenerator->generate_all(&parent, dtop._sucinfo); } } suc_pos = cstack[suc_pos]._next; } if (suc_pos != std::numeric_limits::max()) { - if constexpr (is_spooling()) { + if constexpr (std::is_same::value) { if (cstack[suc_pos]._dstack) { - successorGenerator->generate_all(&parent, dtop._sucinfo); + successorGenerator.generate_all(&parent, dtop._sucinfo); } } // we found the successor, i.e. there's a loop! @@ -172,7 +167,7 @@ namespace LTL { continue; } if (!_store.exists(stateid).first) { - auto bstate = seen.get_buchi_state(stateid); + auto bstate = StateSet::get_buchi_state(stateid); if(_weakskip && successorGenerator.is_accepting(bstate) && successorGenerator.has_invariant_self_loop(bstate)) @@ -180,7 +175,7 @@ namespace LTL { _violation = true; break; } - push(cstack, dstack, successorGenerator, working, stateid); + push(seen, cstack, dstack, successorGenerator, working, stateid); } } if constexpr (SaveTrace) { @@ -204,10 +199,10 @@ namespace LTL { * Push a state to the various stacks. * @param state */ - template - void TarjanModelChecker::push(light_deque& cstack, light_deque& dstack, S& successor_generator, State &state, size_t stateid) { + template + void TarjanModelChecker::push(StateSet& s, light_deque& cstack, light_deque& dstack, S& successor_generator, State &state, size_t stateid) { const auto ctop = static_cast(cstack.size()); - const auto h = hash(stateid); + const auto h = hash(StateSet::get_marking_id(stateid), StateSet::get_buchi_state(stateid)); cstack.push_back(T{ctop, stateid, _chash[h]}); _chash[h] = ctop; dstack.push_back(D{ctop}); @@ -218,7 +213,7 @@ namespace LTL { _invariant_loop = true; } } - if constexpr (is_spooling()) { + if constexpr (std::is_same::value) { successor_generator.push(); } } @@ -231,7 +226,7 @@ namespace LTL { cstack[p]._dstack = false; if (cstack[p]._lowlink == p) { while (cstack.size() > p) { - popCStack(cstack); + popCStack(seen, cstack); } } if (!_astack.empty() && p == _astack.back()) { @@ -239,16 +234,16 @@ namespace LTL { } if (!dstack.empty()) { update(cstack, dstack, successorGenerator, p); - if constexpr (is_spooling()) { + if constexpr (std::is_same::value) { successorGenerator.pop(dstack.back()._sucinfo); } } } - template - void TarjanModelChecker::popCStack(light_deque& cstack) + template + void TarjanModelChecker::popCStack(StateSet& s, light_deque& cstack) { - auto h = hash(cstack.back()._stateid); + auto h = hash(StateSet::get_marking_id(cstack.back()._stateid), StateSet::get_buchi_state(cstack.back()._stateid)); _store.insert(cstack.back()._stateid); _chash[h] = cstack.back()._next; cstack.pop_back(); From d9643d28722f55acba27ce1195318226136ef448 Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 21 Feb 2022 00:13:17 +0100 Subject: [PATCH 20/41] faster --- include/LTL/Algorithm/TarjanModelChecker.h | 2 +- include/LTL/Structures/BitProductStateSet.h | 2 +- include/utils/structures/light_deque.h | 34 ++++++++++----------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/LTL/Algorithm/TarjanModelChecker.h b/include/LTL/Algorithm/TarjanModelChecker.h index 93e513eb3..5cf4efeb8 100644 --- a/include/LTL/Algorithm/TarjanModelChecker.h +++ b/include/LTL/Algorithm/TarjanModelChecker.h @@ -78,7 +78,7 @@ namespace LTL { // 64 MB hash table static constexpr idx_t _hash_sz = 16777216; - ptrie::set _store; + ptrie::set _store; // rudimentary hash table of state IDs. chash[hash(state)] is the top index in cstack // corresponding to state. Collisions are resolved using linked list via CEntry::next. diff --git a/include/LTL/Structures/BitProductStateSet.h b/include/LTL/Structures/BitProductStateSet.h index 4a533d298..af4214956 100644 --- a/include/LTL/Structures/BitProductStateSet.h +++ b/include/LTL/Structures/BitProductStateSet.h @@ -55,7 +55,7 @@ namespace LTL { namespace Structures { * Allows for a max of 2^nbits Büchi states and 2^(64-nbits) markings without overflow. * @tparam nbits the number of bits to allocate for Büchi state. Defaults to 20-bit. Max is 32-bit. */ - template, uint8_t nbits = 20> + template, uint8_t nbits = 20> class BitProductStateSet : public ProductStateSetInterface { public: explicit BitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) diff --git a/include/utils/structures/light_deque.h b/include/utils/structures/light_deque.h index 96bc1c459..9f6d3078b 100644 --- a/include/utils/structures/light_deque.h +++ b/include/utils/structures/light_deque.h @@ -49,7 +49,7 @@ class light_deque _data = nullptr; } - void push_back(const T& element) + inline void push_back(const T& element) { new (&_data[_back]) T(element); ++_back; @@ -59,7 +59,7 @@ class light_deque } } - void push_back(T&& element) + inline void push_back(T&& element) { new (&_data[_back]) T(std::move(element)); ++_back; @@ -68,35 +68,35 @@ class light_deque } } - bool empty() const + inline bool empty() const { return _front == _back; } - size_t size() const + inline size_t size() const { return _back - _front; } - const T& front() const + inline const T& front() const { return _data[_front]; } - T& front() { + inline T& front() { return _data[_front]; } - const T& back() const + inline const T& back() const { return _data[_back - 1]; } - T& back() { + inline T& back() { return _data[_back - 1]; } - void pop_front() + inline void pop_front() { _data[_front].~T(); ++_front; @@ -106,7 +106,7 @@ class light_deque } } - void pop_back() + inline void pop_back() { if(_back > _front) { @@ -117,34 +117,34 @@ class light_deque clear(); } - void clear() + inline void clear() { for(auto& e : *this) e.~T(); _front = _back = 0; } - T* begin() { + inline T* begin() { return &front(); } - T* end() { + inline T* end() { return &_data[_back]; } - const T* begin() const { + inline const T* begin() const { return &front(); } - const T* end() const { + inline const T* end() const { return &_data[_back]; } - const T& operator[](size_t i) const { + inline const T& operator[](size_t i) const { return *(begin() + i); } - T& operator[](size_t i) { + inline T& operator[](size_t i) { return *(begin() + i); } From ed7008d0776f217b7711aa6b578a54531d37ddaa Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 16:56:32 +0100 Subject: [PATCH 21/41] forwarding simple/trivial LTL/CTL subset directly to LTL engine --- include/PetriEngine/PQL/PredicateCheckers.h | 1 + src/CTL/CTLEngine.cpp | 34 ++++++++++++++++++++- src/LTL/LTLSearch.cpp | 25 ++++++++++++++- src/PetriEngine/PQL/PredicateCheckers.cpp | 3 ++ src/main.cpp | 2 +- 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/include/PetriEngine/PQL/PredicateCheckers.h b/include/PetriEngine/PQL/PredicateCheckers.h index f8d39becd..5c68506b2 100644 --- a/include/PetriEngine/PQL/PredicateCheckers.h +++ b/include/PetriEngine/PQL/PredicateCheckers.h @@ -123,6 +123,7 @@ namespace PetriEngine::PQL { bool containsNext(const Condition_ptr& condition); + bool containsNext(const Condition* condition); class ContainsNextVisitor : public AnyVisitor { void _accept(const XCondition *condition) override; diff --git a/src/CTL/CTLEngine.cpp b/src/CTL/CTLEngine.cpp index eaac8e30e..fa898179b 100644 --- a/src/CTL/CTLEngine.cpp +++ b/src/CTL/CTLEngine.cpp @@ -14,6 +14,7 @@ #include "PetriEngine/PQL/Expressions.h" #include "PetriEngine/PQL/PrepareForReachability.h" #include "PetriEngine/PQL/PredicateCheckers.h" +#include "LTL/LTLSearch.h" #include #include @@ -248,7 +249,38 @@ bool recursiveSolve(Condition* query, PetriEngine::PetriNet* net, } return (res.back() == AbstractHandler::Satisfied) xor query->isInvariant(); } - else + else if(!containsNext(query)) { + // there are probably many more cases w. nested quantifiers we can do + // one instance is E[ non_temp U [E non_temp U ...]] in a chain + // also, this should go into some *neat* visitor to do the check. + auto q = query->shared_from_this(); + bool ok = false; + if(auto* af = dynamic_cast(query)) + { + if(!isTemporal((*af)[0])) + ok = true; + } + else if(auto* eg = dynamic_cast(query)) + { + if(!isTemporal((*eg)[0])) + ok = true; + } + else if(auto* au = dynamic_cast(query)) { + if(!isTemporal((*au)[0]) && !isTemporal((*au)[1])) + ok = true; + } + else if(auto* eu = dynamic_cast(query)) { + if(!isTemporal((*eu)[0]) && !isTemporal((*eu)[1])) + ok = true; + } + if(ok) + { + LTL::LTLSearch search(*net, q, options.buchiOptimization, options.ltl_compress_aps); + return search.solve(false, options.kbound, options.ltlalgorithm, options.ltl_por, + options.strategy, options.ltlHeuristic, options.ltluseweak, options.seed_offset); + } + } + //else { return singleSolve(query, net, algorithmtype, strategytype, partial_order, result); } diff --git a/src/LTL/LTLSearch.cpp b/src/LTL/LTLSearch.cpp index 9ca0c084c..bccbf34ae 100644 --- a/src/LTL/LTLSearch.cpp +++ b/src/LTL/LTLSearch.cpp @@ -54,7 +54,30 @@ namespace LTL { should_negate = true; } else if (auto _formula = dynamic_cast (formula.get())) { converted = (*_formula)[0]; - } else { + } else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); + return to_ltl(f); + } + else { converted = formula; } Visitor::visit(validator, converted); diff --git a/src/PetriEngine/PQL/PredicateCheckers.cpp b/src/PetriEngine/PQL/PredicateCheckers.cpp index eac22debf..7cc60f752 100644 --- a/src/PetriEngine/PQL/PredicateCheckers.cpp +++ b/src/PetriEngine/PQL/PredicateCheckers.cpp @@ -252,6 +252,9 @@ namespace PetriEngine::PQL { /*** Contains Next ***/ bool containsNext(const Condition_ptr& condition) { + return containsNext(condition.get()); + } + bool containsNext(const Condition* condition) { ContainsNextVisitor visitor; Visitor::visit(visitor, condition); return visitor.getReturnValue(); diff --git a/src/main.cpp b/src/main.cpp index 0cc81c732..c5add9ec6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -366,7 +366,7 @@ int main(int argc, const char** argv) { if (!ltl_ids.empty() && options.ltlalgorithm != LTL::Algorithm::None) { options.usedltl = true; - for (auto qid: ltl_ids) { + for (auto qid : ltl_ids) { LTL::LTLSearch search(*net, queries[qid], options.buchiOptimization, options.ltl_compress_aps); auto res = search.solve(options.trace != TraceLevel::None, options.kbound, options.ltlalgorithm, options.stubbornreduction ? options.ltl_por : LTL::LTLPartialOrder::None, From 06135aedf330879ed3ba3ed60ef09014d971a7a6 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 21:44:01 +0100 Subject: [PATCH 22/41] fixed typo in all/exists translation --- src/LTL/LTLSearch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LTL/LTLSearch.cpp b/src/LTL/LTLSearch.cpp index bccbf34ae..7b3355909 100644 --- a/src/LTL/LTLSearch.cpp +++ b/src/LTL/LTLSearch.cpp @@ -74,7 +74,7 @@ namespace LTL { return to_ltl(f); } else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); + auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); return to_ltl(f); } else { From 67cc5ffab7f5f8ec2af771ba73abd5e8882eeb4b Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 21 Feb 2022 13:03:42 +0100 Subject: [PATCH 23/41] forwarding RDFS/BFS directly to CTL engine instead of recursive decomposition --- src/CTL/CTLEngine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CTL/CTLEngine.cpp b/src/CTL/CTLEngine.cpp index fa898179b..c3b62192c 100644 --- a/src/CTL/CTLEngine.cpp +++ b/src/CTL/CTLEngine.cpp @@ -327,7 +327,10 @@ ReturnValue CTLMain(PetriNet* net, result.duration = 0; if(!solved) { - result.result = recursiveSolve(result.query, net, algorithmtype, strategytype, partial_order, result, options); + if(options.strategy == Strategy::BFS || options.strategy == Strategy::RDFS) + result.result = singleSolve(result.query, net, algorithmtype, options.strategy, options.stubbornreduction, result); + else + result.result = recursiveSolve(result.query, net, algorithmtype, strategytype, partial_order, result, options); } result.print(querynames[qnum], printstatistics, qnum, options, std::cout); } From 7565b55d9c85ca6a62d9eda98e6fa05103a10e32 Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 21 Feb 2022 21:35:31 +0100 Subject: [PATCH 24/41] fixed upper-bounds --- include/PetriEngine/PQL/Evaluation.h | 2 ++ src/PetriEngine/PQL/Analyze.cpp | 39 ++++++++++++++++------------ src/PetriEngine/PQL/Evaluation.cpp | 7 +++++ src/PetriEngine/PQL/PushNegation.cpp | 5 +++- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/include/PetriEngine/PQL/Evaluation.h b/include/PetriEngine/PQL/Evaluation.h index 1cb666568..6d440411d 100644 --- a/include/PetriEngine/PQL/Evaluation.h +++ b/include/PetriEngine/PQL/Evaluation.h @@ -112,6 +112,8 @@ namespace PetriEngine { namespace PQL { void _accept(DeadlockCondition *element) override; + void _accept(UpperBoundsCondition *element) override; + void _accept(UnfoldedUpperBoundsCondition *element) override; void _accept(ShallowCondition *element) override; diff --git a/src/PetriEngine/PQL/Analyze.cpp b/src/PetriEngine/PQL/Analyze.cpp index 2798cb6f8..cb3228963 100644 --- a/src/PetriEngine/PQL/Analyze.cpp +++ b/src/PetriEngine/PQL/Analyze.cpp @@ -349,29 +349,34 @@ namespace PetriEngine::PQL { } void AnalyzeVisitor::_accept(UpperBoundsCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); - - auto coloredContext = dynamic_cast(&_context); - if(coloredContext != nullptr && coloredContext->isColored()) + if (element->getCompiled()) + { + Visitor::visit(this, element->getCompiled()); + } + else { - std::vector uplaces; - for(auto& p : element->getPlaces()) + auto coloredContext = dynamic_cast(&_context); + if(coloredContext != nullptr && coloredContext->isColored()) { - std::unordered_map names; - if (!coloredContext->resolvePlace(p, names)) { - throw base_error("Unable to resolve colored identifier \"", p, "\""); - } - - for(auto& id : names) + std::vector uplaces; + for(auto& p : element->getPlaces()) { - uplaces.push_back(names[id.first]); + std::unordered_map names; + if (!coloredContext->resolvePlace(p, names)) { + throw base_error("Unable to resolve colored identifier \"", p, "\""); + } + + for(auto& id : names) + { + uplaces.push_back(names[id.first]); + } } + element->_compiled = std::make_shared(uplaces); + } else { + element->_compiled = std::make_shared(element->getPlaces()); } - element->_compiled = std::make_shared(uplaces); - } else { - element->_compiled = std::make_shared(element->getPlaces()); + Visitor::visit(this, element->_compiled); } - Visitor::visit(this, element->_compiled); } void AnalyzeVisitor::_accept(UnfoldedUpperBoundsCondition *element) { diff --git a/src/PetriEngine/PQL/Evaluation.cpp b/src/PetriEngine/PQL/Evaluation.cpp index 6c18d6456..7bbb3feb3 100644 --- a/src/PetriEngine/PQL/Evaluation.cpp +++ b/src/PetriEngine/PQL/Evaluation.cpp @@ -276,6 +276,13 @@ namespace PetriEngine { namespace PQL { _return_value = {element->getMax() <= element->getBound() ? Condition::RTRUE : Condition::RUNKNOWN}; } + void EvaluateVisitor::_accept(UpperBoundsCondition *element) { + if(element->getCompiled()) + Visitor::visit(this, element->getCompiled()); + else + _return_value = Condition::RUNKNOWN; + } + void EvaluateVisitor::_accept(ShallowCondition *element) { Visitor::visit(this, element->getCompiled()); } diff --git a/src/PetriEngine/PQL/PushNegation.cpp b/src/PetriEngine/PQL/PushNegation.cpp index cbd2ea8f0..f6227d1e9 100644 --- a/src/PetriEngine/PQL/PushNegation.cpp +++ b/src/PetriEngine/PQL/PushNegation.cpp @@ -643,7 +643,10 @@ namespace PetriEngine::PQL { if (negated) { throw base_error("UPPER BOUNDS CANNOT BE NEGATED!"); } - RETURN(element->clone()) + if(element->getCompiled()) + Visitor::visit(this, element->getCompiled()); + else + RETURN(element->clone()) } void PushNegationVisitor::_accept(UnfoldedUpperBoundsCondition *element) { From 724f7bbaffa295d41fe02935f31793eb38bcf51d Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 7 Mar 2022 16:08:11 +0100 Subject: [PATCH 25/41] fixed default handling of testing search heuristics for ltl --- src/LTL/LTLSearch.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/LTL/LTLSearch.cpp b/src/LTL/LTLSearch.cpp index 9ca0c084c..54abf73ac 100644 --- a/src/LTL/LTLSearch.cpp +++ b/src/LTL/LTLSearch.cpp @@ -70,7 +70,7 @@ namespace LTL { const Strategy search_strategy = Strategy::HEUR, const LTLHeuristic heuristics = LTLHeuristic::Automaton, const uint64_t seed = 0) { - if (search_strategy == Strategy::RDFS) { + if (search_strategy == Strategy::RDFS || heuristics == LTLHeuristic::RDFS) { return std::make_unique(seed); } if (search_strategy != Strategy::HEUR && search_strategy != Strategy::DEFAULT) { @@ -83,6 +83,9 @@ namespace LTL { return std::make_unique(&net, automaton); case LTLHeuristic::FireCount: return std::make_unique(net.numberOfTransitions(), 5000); + case LTLHeuristic::DFS: + case LTLHeuristic::RDFS: + return nullptr; default: throw base_error("Unknown LTL heuristics: ", to_underlying(heuristics)); } From 47e2267cd10f9e5a9e60c29e89e22308f4447965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Gj=C3=B8l=20Jensen?= Date: Mon, 7 Mar 2022 17:13:47 +0100 Subject: [PATCH 26/41] Update src/LTL/Algorithm/TarjanModelChecker.cpp Co-authored-by: Nikolaj Jensen Ulrik <10130355+njulrik@users.noreply.github.com> --- src/LTL/Algorithm/TarjanModelChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LTL/Algorithm/TarjanModelChecker.cpp b/src/LTL/Algorithm/TarjanModelChecker.cpp index 2ff1bd589..8b7abd5c5 100644 --- a/src/LTL/Algorithm/TarjanModelChecker.cpp +++ b/src/LTL/Algorithm/TarjanModelChecker.cpp @@ -234,7 +234,7 @@ namespace LTL { } if (!dstack.empty()) { update(cstack, dstack, successorGenerator, p); - if constexpr (std::is_same::value) { + if constexpr (std::is_same::value) { successorGenerator.pop(dstack.back()._sucinfo); } } From f77bba71da97f32365ded6f602b876f31a3a47a5 Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 7 Mar 2022 17:37:30 +0100 Subject: [PATCH 27/41] comments from review & nuked unused interface --- include/LTL/Algorithm/ModelChecker.h | 6 -- .../LTL/Algorithm/NestedDepthFirstSearch.h | 2 +- include/LTL/Structures/BitProductStateSet.h | 59 +++++++------------ src/LTL/Algorithm/NestedDepthFirstSearch.cpp | 6 +- src/LTL/Algorithm/TarjanModelChecker.cpp | 2 +- 5 files changed, 25 insertions(+), 50 deletions(-) diff --git a/include/LTL/Algorithm/ModelChecker.h b/include/LTL/Algorithm/ModelChecker.h index febf514d5..5dc10481e 100644 --- a/include/LTL/Algorithm/ModelChecker.h +++ b/include/LTL/Algorithm/ModelChecker.h @@ -96,17 +96,11 @@ namespace LTL { << "\tmax tokens: " << max_tokens << std::endl; } - virtual void print_stats(std::ostream &os, const LTL::Structures::ProductStateSetInterface &stateSet) const { - print_stats(os, stateSet.discovered(), stateSet.max_tokens()); - } - - const PetriEngine::PetriNet& _net; PetriEngine::PQL::Condition_ptr _formula; Structures::ProductStateFactory _factory; const Structures::BuchiAutomaton& _buchi; bool _shortcircuitweak; - bool _weakskip = false; bool _build_trace = false; Heuristic* _heuristic = nullptr; size_t _loop = std::numeric_limits::max(); diff --git a/include/LTL/Algorithm/NestedDepthFirstSearch.h b/include/LTL/Algorithm/NestedDepthFirstSearch.h index 62dc7d671..14996bc2e 100644 --- a/include/LTL/Algorithm/NestedDepthFirstSearch.h +++ b/include/LTL/Algorithm/NestedDepthFirstSearch.h @@ -57,7 +57,7 @@ namespace LTL { using State = LTL::Structures::ProductState; std::pair mark(State& state, uint8_t); - LTL::Structures::BitProductStateSet> _states; + LTL::Structures::BitProductStateSet> _states; ptrie::map _markers; static constexpr uint8_t MARKER1 = 1; diff --git a/include/LTL/Structures/BitProductStateSet.h b/include/LTL/Structures/BitProductStateSet.h index af4214956..75e4f5d2f 100644 --- a/include/LTL/Structures/BitProductStateSet.h +++ b/include/LTL/Structures/BitProductStateSet.h @@ -26,38 +26,19 @@ namespace LTL { namespace Structures { - class ProductStateSetInterface { - public: - using stateid_t = size_t; - using result_t = std::tuple; - - virtual result_t add(const LTL::Structures::ProductState &state) = 0; - - virtual void decode(LTL::Structures::ProductState &state, stateid_t id) = 0; - - virtual void set_history(stateid_t id, size_t transition) {} - - virtual std::pair get_history(stateid_t stateid) - { - return std::make_pair(std::numeric_limits::max(), std::numeric_limits::max()); - } - - virtual size_t discovered() const = 0; - - virtual size_t max_tokens() const = 0; - - virtual ~ProductStateSetInterface() = default; - - }; /** * Bit-hacking product state set for storing pairs (M, q) compactly in 64 bits. * Allows for a max of 2^nbits Büchi states and 2^(64-nbits) markings without overflow. * @tparam nbits the number of bits to allocate for Büchi state. Defaults to 20-bit. Max is 32-bit. */ - template, uint8_t nbits = 20> - class BitProductStateSet : public ProductStateSetInterface { + using stateid_t = size_t; + using result_t = std::tuple; + + template, uint8_t nbits = 20> + class BitProductStateSet { public: + explicit BitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) : _markings(net, kbound, net.numberOfPlaces()) { @@ -78,9 +59,10 @@ namespace LTL { namespace Structures { /** * Insert a product state into the state set. * @param state the product state to insert. - * @return pair of [success, ID] + * @return tripple of [success, ID, data_id] where data_id can be used + * for quick-access via get_data (constant-time lookup). */ - result_t add(const LTL::Structures::ProductState &state) override + result_t add(const LTL::Structures::ProductState &state) { ++_discovered; const auto res = _markings.add(state); @@ -94,7 +76,11 @@ namespace LTL { namespace Structures { return {is_new, product_id, data_id}; } - + /** + * Gets the associated data of a data_id, constants-time + * @param data_id + * @return the data-object pointed to by data_id (obtained by the add() method). + */ auto& get_data(size_t data_id) { return _states.get_data(data_id); } @@ -105,7 +91,7 @@ namespace LTL { namespace Structures { * @param state Output parameter to write product state to. * @return true if the state was successfully retrieved, false otherwise. */ - void decode(LTL::Structures::ProductState &state, stateid_t id) override + virtual void decode(LTL::Structures::ProductState &state, stateid_t id) { assert(_states.exists(id).first); auto marking_id = get_marking_id(id); @@ -114,9 +100,9 @@ namespace LTL { namespace Structures { state.set_buchi_state(buchi_state); } - size_t discovered() const override { return _discovered; } + size_t discovered() const { return _discovered; } - size_t max_tokens() const override { return _markings.maxTokens(); } + size_t max_tokens() const { return _markings.maxTokens(); } protected: @@ -131,27 +117,26 @@ namespace LTL { namespace Structures { }; template - class TraceableBitProductStateSet : public BitProductStateSet>, nbits> { - using stateid_t = typename BitProductStateSet>, nbits>::stateid_t; + class TraceableBitProductStateSet : public BitProductStateSet>, nbits> { public: explicit TraceableBitProductStateSet(const PetriEngine::PetriNet& net, uint32_t kbound = 0) - : BitProductStateSet>,nbits>(net, kbound) + : BitProductStateSet>,nbits>(net, kbound) { } void decode(ProductState &state, stateid_t id) override { _parent = id; - BitProductStateSet>,nbits>::decode(state, id); + BitProductStateSet>,nbits>::decode(state, id); } - void set_history(stateid_t id, size_t transition) override + void set_history(stateid_t id, size_t transition) { assert(this->_states.exists(id).first); this->_states[id] = {_parent, transition}; } - std::pair get_history(stateid_t stateid) override + std::pair get_history(stateid_t stateid) { assert(this->_states.exists(stateid).first); return this->_states[stateid]; diff --git a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp index 714477ee9..65f006db8 100644 --- a/src/LTL/Algorithm/NestedDepthFirstSearch.cpp +++ b/src/LTL/Algorithm/NestedDepthFirstSearch.cpp @@ -156,11 +156,7 @@ namespace LTL { void NestedDepthFirstSearch::print_stats(std::ostream &os) const { - std::cout << "STATS:\n" - << "\tdiscovered states: " << _states.discovered() << std::endl - << "\tmax tokens: " << _states.max_tokens() << std::endl - << "\texplored states: " << _mark_count[MARKER1] << std::endl - << "\texplored states (nested): " << _mark_count[MARKER2] << std::endl; + ModelChecker::print_stats(os, _states.discovered(), _states.max_tokens()); } diff --git a/src/LTL/Algorithm/TarjanModelChecker.cpp b/src/LTL/Algorithm/TarjanModelChecker.cpp index 2ff1bd589..99a4a849f 100644 --- a/src/LTL/Algorithm/TarjanModelChecker.cpp +++ b/src/LTL/Algorithm/TarjanModelChecker.cpp @@ -168,7 +168,7 @@ namespace LTL { } if (!_store.exists(stateid).first) { auto bstate = StateSet::get_buchi_state(stateid); - if(_weakskip && + if(_shortcircuitweak && successorGenerator.is_accepting(bstate) && successorGenerator.has_invariant_self_loop(bstate)) { From 0bc3b5566cc2b897b0b4fd8b842f08aaf5b344c6 Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 7 Mar 2022 17:40:43 +0100 Subject: [PATCH 28/41] fixed missing argument --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 0cc81c732..c0d8a9b53 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -370,7 +370,7 @@ int main(int argc, const char** argv) { LTL::LTLSearch search(*net, queries[qid], options.buchiOptimization, options.ltl_compress_aps); auto res = search.solve(options.trace != TraceLevel::None, options.kbound, options.ltlalgorithm, options.stubbornreduction ? options.ltl_por : LTL::LTLPartialOrder::None, - options.strategy, options.ltlHeuristic, options.seed_offset); + options.strategy, options.ltlHeuristic, options.ltluseweak, options.seed_offset); if(options.printstatistics) search.print_stats(std::cout); From 0f4149772da50b902c339b974811c923a402dd1f Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 16:56:32 +0100 Subject: [PATCH 29/41] forwarding simple/trivial LTL/CTL subset directly to LTL engine --- include/PetriEngine/PQL/PredicateCheckers.h | 1 + src/CTL/CTLEngine.cpp | 34 ++++++++++++++++++++- src/LTL/LTLSearch.cpp | 25 ++++++++++++++- src/PetriEngine/PQL/PredicateCheckers.cpp | 3 ++ src/main.cpp | 2 +- 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/include/PetriEngine/PQL/PredicateCheckers.h b/include/PetriEngine/PQL/PredicateCheckers.h index f8d39becd..5c68506b2 100644 --- a/include/PetriEngine/PQL/PredicateCheckers.h +++ b/include/PetriEngine/PQL/PredicateCheckers.h @@ -123,6 +123,7 @@ namespace PetriEngine::PQL { bool containsNext(const Condition_ptr& condition); + bool containsNext(const Condition* condition); class ContainsNextVisitor : public AnyVisitor { void _accept(const XCondition *condition) override; diff --git a/src/CTL/CTLEngine.cpp b/src/CTL/CTLEngine.cpp index eaac8e30e..fa898179b 100644 --- a/src/CTL/CTLEngine.cpp +++ b/src/CTL/CTLEngine.cpp @@ -14,6 +14,7 @@ #include "PetriEngine/PQL/Expressions.h" #include "PetriEngine/PQL/PrepareForReachability.h" #include "PetriEngine/PQL/PredicateCheckers.h" +#include "LTL/LTLSearch.h" #include #include @@ -248,7 +249,38 @@ bool recursiveSolve(Condition* query, PetriEngine::PetriNet* net, } return (res.back() == AbstractHandler::Satisfied) xor query->isInvariant(); } - else + else if(!containsNext(query)) { + // there are probably many more cases w. nested quantifiers we can do + // one instance is E[ non_temp U [E non_temp U ...]] in a chain + // also, this should go into some *neat* visitor to do the check. + auto q = query->shared_from_this(); + bool ok = false; + if(auto* af = dynamic_cast(query)) + { + if(!isTemporal((*af)[0])) + ok = true; + } + else if(auto* eg = dynamic_cast(query)) + { + if(!isTemporal((*eg)[0])) + ok = true; + } + else if(auto* au = dynamic_cast(query)) { + if(!isTemporal((*au)[0]) && !isTemporal((*au)[1])) + ok = true; + } + else if(auto* eu = dynamic_cast(query)) { + if(!isTemporal((*eu)[0]) && !isTemporal((*eu)[1])) + ok = true; + } + if(ok) + { + LTL::LTLSearch search(*net, q, options.buchiOptimization, options.ltl_compress_aps); + return search.solve(false, options.kbound, options.ltlalgorithm, options.ltl_por, + options.strategy, options.ltlHeuristic, options.ltluseweak, options.seed_offset); + } + } + //else { return singleSolve(query, net, algorithmtype, strategytype, partial_order, result); } diff --git a/src/LTL/LTLSearch.cpp b/src/LTL/LTLSearch.cpp index 54abf73ac..ec411db5f 100644 --- a/src/LTL/LTLSearch.cpp +++ b/src/LTL/LTLSearch.cpp @@ -54,7 +54,30 @@ namespace LTL { should_negate = true; } else if (auto _formula = dynamic_cast (formula.get())) { converted = (*_formula)[0]; - } else { + } else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); + return to_ltl(f); + } + else if (auto _formula = dynamic_cast (formula.get())) { + auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); + return to_ltl(f); + } + else { converted = formula; } Visitor::visit(validator, converted); diff --git a/src/PetriEngine/PQL/PredicateCheckers.cpp b/src/PetriEngine/PQL/PredicateCheckers.cpp index eac22debf..7cc60f752 100644 --- a/src/PetriEngine/PQL/PredicateCheckers.cpp +++ b/src/PetriEngine/PQL/PredicateCheckers.cpp @@ -252,6 +252,9 @@ namespace PetriEngine::PQL { /*** Contains Next ***/ bool containsNext(const Condition_ptr& condition) { + return containsNext(condition.get()); + } + bool containsNext(const Condition* condition) { ContainsNextVisitor visitor; Visitor::visit(visitor, condition); return visitor.getReturnValue(); diff --git a/src/main.cpp b/src/main.cpp index c0d8a9b53..d46538565 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -366,7 +366,7 @@ int main(int argc, const char** argv) { if (!ltl_ids.empty() && options.ltlalgorithm != LTL::Algorithm::None) { options.usedltl = true; - for (auto qid: ltl_ids) { + for (auto qid : ltl_ids) { LTL::LTLSearch search(*net, queries[qid], options.buchiOptimization, options.ltl_compress_aps); auto res = search.solve(options.trace != TraceLevel::None, options.kbound, options.ltlalgorithm, options.stubbornreduction ? options.ltl_por : LTL::LTLPartialOrder::None, From d2eb2f67b8e99a491500cad7fb04491011049235 Mon Sep 17 00:00:00 2001 From: pgj Date: Sat, 19 Feb 2022 21:44:01 +0100 Subject: [PATCH 30/41] fixed typo in all/exists translation --- src/LTL/LTLSearch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LTL/LTLSearch.cpp b/src/LTL/LTLSearch.cpp index ec411db5f..8176b5906 100644 --- a/src/LTL/LTLSearch.cpp +++ b/src/LTL/LTLSearch.cpp @@ -74,7 +74,7 @@ namespace LTL { return to_ltl(f); } else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); + auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); return to_ltl(f); } else { From 3c80b94b8a5b0e2c10c628e8ea6bf130278c116e Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 21 Feb 2022 13:03:42 +0100 Subject: [PATCH 31/41] forwarding RDFS/BFS directly to CTL engine instead of recursive decomposition --- src/CTL/CTLEngine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CTL/CTLEngine.cpp b/src/CTL/CTLEngine.cpp index fa898179b..c3b62192c 100644 --- a/src/CTL/CTLEngine.cpp +++ b/src/CTL/CTLEngine.cpp @@ -327,7 +327,10 @@ ReturnValue CTLMain(PetriNet* net, result.duration = 0; if(!solved) { - result.result = recursiveSolve(result.query, net, algorithmtype, strategytype, partial_order, result, options); + if(options.strategy == Strategy::BFS || options.strategy == Strategy::RDFS) + result.result = singleSolve(result.query, net, algorithmtype, options.strategy, options.stubbornreduction, result); + else + result.result = recursiveSolve(result.query, net, algorithmtype, strategytype, partial_order, result, options); } result.print(querynames[qnum], printstatistics, qnum, options, std::cout); } From c5e6695f4024a27e37d66cf5225a66cb1d27c2b1 Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 21 Feb 2022 21:35:31 +0100 Subject: [PATCH 32/41] fixed upper-bounds --- include/PetriEngine/PQL/Evaluation.h | 2 ++ src/PetriEngine/PQL/Analyze.cpp | 39 ++++++++++++++++------------ src/PetriEngine/PQL/Evaluation.cpp | 7 +++++ src/PetriEngine/PQL/PushNegation.cpp | 5 +++- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/include/PetriEngine/PQL/Evaluation.h b/include/PetriEngine/PQL/Evaluation.h index 1cb666568..6d440411d 100644 --- a/include/PetriEngine/PQL/Evaluation.h +++ b/include/PetriEngine/PQL/Evaluation.h @@ -112,6 +112,8 @@ namespace PetriEngine { namespace PQL { void _accept(DeadlockCondition *element) override; + void _accept(UpperBoundsCondition *element) override; + void _accept(UnfoldedUpperBoundsCondition *element) override; void _accept(ShallowCondition *element) override; diff --git a/src/PetriEngine/PQL/Analyze.cpp b/src/PetriEngine/PQL/Analyze.cpp index 2798cb6f8..cb3228963 100644 --- a/src/PetriEngine/PQL/Analyze.cpp +++ b/src/PetriEngine/PQL/Analyze.cpp @@ -349,29 +349,34 @@ namespace PetriEngine::PQL { } void AnalyzeVisitor::_accept(UpperBoundsCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); - - auto coloredContext = dynamic_cast(&_context); - if(coloredContext != nullptr && coloredContext->isColored()) + if (element->getCompiled()) + { + Visitor::visit(this, element->getCompiled()); + } + else { - std::vector uplaces; - for(auto& p : element->getPlaces()) + auto coloredContext = dynamic_cast(&_context); + if(coloredContext != nullptr && coloredContext->isColored()) { - std::unordered_map names; - if (!coloredContext->resolvePlace(p, names)) { - throw base_error("Unable to resolve colored identifier \"", p, "\""); - } - - for(auto& id : names) + std::vector uplaces; + for(auto& p : element->getPlaces()) { - uplaces.push_back(names[id.first]); + std::unordered_map names; + if (!coloredContext->resolvePlace(p, names)) { + throw base_error("Unable to resolve colored identifier \"", p, "\""); + } + + for(auto& id : names) + { + uplaces.push_back(names[id.first]); + } } + element->_compiled = std::make_shared(uplaces); + } else { + element->_compiled = std::make_shared(element->getPlaces()); } - element->_compiled = std::make_shared(uplaces); - } else { - element->_compiled = std::make_shared(element->getPlaces()); + Visitor::visit(this, element->_compiled); } - Visitor::visit(this, element->_compiled); } void AnalyzeVisitor::_accept(UnfoldedUpperBoundsCondition *element) { diff --git a/src/PetriEngine/PQL/Evaluation.cpp b/src/PetriEngine/PQL/Evaluation.cpp index 6c18d6456..7bbb3feb3 100644 --- a/src/PetriEngine/PQL/Evaluation.cpp +++ b/src/PetriEngine/PQL/Evaluation.cpp @@ -276,6 +276,13 @@ namespace PetriEngine { namespace PQL { _return_value = {element->getMax() <= element->getBound() ? Condition::RTRUE : Condition::RUNKNOWN}; } + void EvaluateVisitor::_accept(UpperBoundsCondition *element) { + if(element->getCompiled()) + Visitor::visit(this, element->getCompiled()); + else + _return_value = Condition::RUNKNOWN; + } + void EvaluateVisitor::_accept(ShallowCondition *element) { Visitor::visit(this, element->getCompiled()); } diff --git a/src/PetriEngine/PQL/PushNegation.cpp b/src/PetriEngine/PQL/PushNegation.cpp index cbd2ea8f0..f6227d1e9 100644 --- a/src/PetriEngine/PQL/PushNegation.cpp +++ b/src/PetriEngine/PQL/PushNegation.cpp @@ -643,7 +643,10 @@ namespace PetriEngine::PQL { if (negated) { throw base_error("UPPER BOUNDS CANNOT BE NEGATED!"); } - RETURN(element->clone()) + if(element->getCompiled()) + Visitor::visit(this, element->getCompiled()); + else + RETURN(element->clone()) } void PushNegationVisitor::_accept(UnfoldedUpperBoundsCondition *element) { From ff80793ad0d015801d64d16c71fbfe32dc9786cb Mon Sep 17 00:00:00 2001 From: pgj Date: Mon, 7 Mar 2022 21:39:16 +0100 Subject: [PATCH 33/41] skipping initial rewrite if the query is an upperbounds --- include/PetriEngine/PQL/PredicateCheckers.h | 15 +++++++++++++++ src/PetriEngine/PQL/PredicateCheckers.cpp | 9 +++++++++ src/PetriEngine/PQL/PushNegation.cpp | 4 ++-- src/main.cpp | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/PetriEngine/PQL/PredicateCheckers.h b/include/PetriEngine/PQL/PredicateCheckers.h index 5c68506b2..77c8c6e1b 100644 --- a/include/PetriEngine/PQL/PredicateCheckers.h +++ b/include/PetriEngine/PQL/PredicateCheckers.h @@ -144,6 +144,21 @@ namespace PetriEngine::PQL { setConditionFound(); } }; + + class ContainsUpperBoundsVisitor : public AnyVisitor { + void _accept(const UpperBoundsCondition* c) override + { + setConditionFound(); + } + + void _accept(const UnfoldedUpperBoundsCondition* c) override + { + setConditionFound(); + } + }; + + bool containsUpperBounds(const Condition* condition); + bool containsUpperBounds(const Condition_ptr& condition); } #endif //VERIFYPN_PREDICATECHECKERS_H diff --git a/src/PetriEngine/PQL/PredicateCheckers.cpp b/src/PetriEngine/PQL/PredicateCheckers.cpp index 7cc60f752..f7cb82745 100644 --- a/src/PetriEngine/PQL/PredicateCheckers.cpp +++ b/src/PetriEngine/PQL/PredicateCheckers.cpp @@ -272,4 +272,13 @@ namespace PetriEngine::PQL { setConditionFound(); } + bool containsUpperBounds(const Condition_ptr& condition) { + return containsUpperBounds(condition.get()); + } + + bool containsUpperBounds(const Condition* condition) { + ContainsUpperBoundsVisitor visitor; + Visitor::visit(visitor, condition); + return visitor.getReturnValue(); + } } diff --git a/src/PetriEngine/PQL/PushNegation.cpp b/src/PetriEngine/PQL/PushNegation.cpp index f6227d1e9..e181e7915 100644 --- a/src/PetriEngine/PQL/PushNegation.cpp +++ b/src/PetriEngine/PQL/PushNegation.cpp @@ -31,7 +31,7 @@ #define RETURN(x) {return_value = x; return;} #endif -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { Condition_ptr initialMarkingRW(const std::function& func, negstat_t& stats, const EvaluationContext& context, bool _nested, bool _negated, bool initrw) { @@ -703,4 +703,4 @@ namespace PetriEngine::PQL { return return_value; } } -} \ No newline at end of file +} } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d46538565..b6bc3db48 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -177,6 +177,7 @@ int main(int argc, const char** argv) { ContainsFireabilityVisitor has_fireability; Visitor::visit(has_fireability, queries[i]); if(has_fireability.getReturnValue() && options.cpnOverApprox) continue; + if(containsUpperBounds(queries[i])) continue; auto r = PQL::evaluate(queries[i].get(), context); if(r == Condition::RFALSE) { From c5f772846606800c82b5bc1b2d19420c2450f4ea Mon Sep 17 00:00:00 2001 From: pgj Date: Tue, 8 Mar 2022 10:43:28 +0100 Subject: [PATCH 34/41] fixed issue with underflow during lp --- include/PetriEngine/Simplification/LPCache.h | 8 +-- .../Simplification/LinearPrograms.h | 68 +++++++++--------- include/PetriEngine/Simplification/Member.h | 72 +++++++++---------- include/PetriEngine/Simplification/Vector.h | 48 ++++++------- src/PetriEngine/PQL/Simplifier.cpp | 5 +- .../Simplification/LinearProgram.cpp | 19 ++--- 6 files changed, 112 insertions(+), 108 deletions(-) diff --git a/include/PetriEngine/Simplification/LPCache.h b/include/PetriEngine/Simplification/LPCache.h index e113628f9..a3e97f82e 100644 --- a/include/PetriEngine/Simplification/LPCache.h +++ b/include/PetriEngine/Simplification/LPCache.h @@ -1,4 +1,4 @@ -/* +/* * File: LPFactory.h * Author: Peter G. Jensen * @@ -25,7 +25,7 @@ namespace PetriEngine { public: LPCache(); virtual ~LPCache(); - Vector* createAndCache(const std::vector& data) + Vector* createAndCache(const std::vector& data) { auto res = vectors.insert(Vector(data)); Vector& v = const_cast(*res.first); @@ -34,14 +34,14 @@ namespace PetriEngine { // assert(v.refs() > 0); return &v; } - + void invalidate(const Vector& vector) { // vectors.erase(vector); // assert(vector.refs() == 0); } - + private: // unordered_map does not invalidate on insert, only erase std::unordered_set vectors; diff --git a/include/PetriEngine/Simplification/LinearPrograms.h b/include/PetriEngine/Simplification/LinearPrograms.h index a605cfab9..fdbcbc15e 100644 --- a/include/PetriEngine/Simplification/LinearPrograms.h +++ b/include/PetriEngine/Simplification/LinearPrograms.h @@ -3,24 +3,24 @@ #include "LinearProgram.h" #include "../PQL/Contexts.h" #include "../PetriNet.h" - + #include namespace PetriEngine { namespace Simplification { - + class AbstractProgramCollection { protected: enum result_t { UNKNOWN, IMPOSSIBLE, POSSIBLE }; result_t _result = result_t::UNKNOWN; - + virtual void satisfiableImpl(const PQL::SimplificationContext& context, uint32_t solvetime) = 0; bool has_empty = false; public: virtual ~AbstractProgramCollection() {}; bool empty() { return has_empty; } - + virtual bool satisfiable(const PQL::SimplificationContext& context, uint32_t solvetime = std::numeric_limits::max()) { reset(); @@ -36,12 +36,12 @@ namespace PetriEngine { assert(_result != UNKNOWN); return _result == POSSIBLE; } - + bool known_sat() { return _result == POSSIBLE; }; bool known_unsat() { return _result == IMPOSSIBLE; }; - + virtual void clear() = 0; - + virtual bool merge(bool& has_empty, LinearProgram& program, bool dry_run = false) = 0; virtual void reset() = 0; virtual size_t size() const = 0; @@ -55,7 +55,7 @@ namespace PetriEngine { std::vector lps; size_t current = 0; size_t _size = 0; - + virtual void satisfiableImpl(const PQL::SimplificationContext& context, uint32_t solvetime) { for(int i = lps.size() - 1; i >= 0; --i) @@ -76,13 +76,13 @@ namespace PetriEngine { public: UnionCollection(std::vector&& programs) : - AbstractProgramCollection(), lps(std::move(programs)) + AbstractProgramCollection(), lps(std::move(programs)) { for(auto& p : lps) _size += p->size(); } - + UnionCollection(const AbstractProgramCollection_ptr& A, const AbstractProgramCollection_ptr& B) : - AbstractProgramCollection(), lps({A,B}) + AbstractProgramCollection(), lps({A,B}) { has_empty = false; for(auto& lp : lps) @@ -99,7 +99,7 @@ namespace PetriEngine { lps.clear(); current = 0; }; - + virtual void reset() { lps[0]->reset(); @@ -108,18 +108,18 @@ namespace PetriEngine { virtual bool merge(bool& has_empty, LinearProgram& program, bool dry_run = false) { - - if(current >= lps.size()) + + if(current >= lps.size()) { current = 0; } - + if(!lps[current]->merge(has_empty, program, dry_run)) { ++current; if(current < lps.size()) lps[current]->reset(); } - + return current < lps.size(); } virtual size_t size() const @@ -128,7 +128,7 @@ namespace PetriEngine { } }; - + class MergeCollection : public AbstractProgramCollection { protected: @@ -152,7 +152,7 @@ namespace PetriEngine { LinearProgram prog; bool has_empty = false; hasmore = merge(has_empty, prog); - if(has_empty) + if(has_empty) { _result = POSSIBLE; return; @@ -186,15 +186,15 @@ namespace PetriEngine { virtual void reset() { if(right) right->reset(); - + merge_right = true; more_right = true; rempty = false; - + tmp_prog = LinearProgram(); curr = 0; } - + void clear() { left = nullptr; @@ -202,7 +202,7 @@ namespace PetriEngine { }; virtual bool merge(bool& has_empty, LinearProgram& program, bool dry_run = false) - { + { if(program.knownImpossible()) return false; bool lempty = false; bool more_left; @@ -243,9 +243,9 @@ namespace PetriEngine { return _size - nsat; } - + }; - + class SingleProgram : public AbstractProgramCollection { private: LinearProgram program; @@ -257,7 +257,7 @@ namespace PetriEngine { { _result = POSSIBLE; } - else + else { _result = IMPOSSIBLE; } @@ -270,20 +270,20 @@ namespace PetriEngine { { has_empty = true; } - - SingleProgram(LPCache* factory, const Member& lh, int constant, op_t op) + + SingleProgram(LPCache* factory, const Member& lh, int64_t constant, op_t op) : AbstractProgramCollection(), program(factory->createAndCache(lh.variables()), constant, op, factory) { has_empty = program.size() == 0; assert(!has_empty); } - + virtual ~SingleProgram(){ } - + virtual void reset() {} - + virtual bool merge(bool& has_empty, LinearProgram& program, bool dry_run = false) { if(dry_run) return false; @@ -291,17 +291,17 @@ namespace PetriEngine { has_empty = this->program.equations().size() == 0; assert(has_empty == this->has_empty); return false; - } - + } + void clear() { } - + virtual size_t size() const { return 1; } - + }; } } diff --git a/include/PetriEngine/Simplification/Member.h b/include/PetriEngine/Simplification/Member.h index 086c3312e..0a24ce438 100644 --- a/include/PetriEngine/Simplification/Member.h +++ b/include/PetriEngine/Simplification/Member.h @@ -11,47 +11,47 @@ namespace PetriEngine { enum Trivial { False=0, True=1, Indeterminate=2 }; enum MemberType { Constant, Input, Output, Regular }; class Member { - std::vector _variables; - int _constant = 0; + std::vector _variables; + int64_t _constant = 0; bool _canAnalyze = false; public: - Member(std::vector&& vec, int constant, bool canAnalyze = true) + Member(std::vector&& vec, int64_t constant, bool canAnalyze = true) : _variables(vec), _constant(constant), _canAnalyze(canAnalyze) { } - Member(int constant, bool canAnalyse = true) + Member(int constant, bool canAnalyse = true) : _constant(constant), _canAnalyze(canAnalyse) { } Member(){} virtual ~Member(){} - + int constant() const { return _constant; }; bool canAnalyze() const { return _canAnalyze; }; size_t size() const { return _variables.size(); } - std::vector& variables() { return _variables; } - const std::vector& variables() const { return _variables; } - - Member& operator+=(const Member& m) { + std::vector& variables() { return _variables; } + const std::vector& variables() const { return _variables; } + + Member& operator+=(const Member& m) { auto tc = _constant + m._constant; - auto ca = _canAnalyze && m._canAnalyze; + auto ca = _canAnalyze && m._canAnalyze; addVariables(m); _constant = tc; _canAnalyze = ca; return *this; } - - Member& operator-=(const Member& m) { + + Member& operator-=(const Member& m) { auto tc = _constant - m._constant; - auto ca = _canAnalyze && m._canAnalyze; + auto ca = _canAnalyze && m._canAnalyze; subtractVariables(m); _constant = tc; _canAnalyze = ca; return *this; } - - Member& operator*=(const Member& m) { + + Member& operator*=(const Member& m) { if(!isZero() && !m.isZero()){ _canAnalyze = false; _constant = 0; @@ -64,7 +64,7 @@ namespace PetriEngine { _canAnalyze = ca; } return *this; - } + } bool substrationIsZero(const Member& m2) const { @@ -73,7 +73,7 @@ namespace PetriEngine { for(; i < min; i++) { if(_variables[i] != m2._variables[i]) return false; } - + for(; i < _variables.size(); ++i) { if(_variables[i] != 0) return false; @@ -85,19 +85,19 @@ namespace PetriEngine { } return true; } - + bool isZero() const { - for(const int& v : _variables){ + for(const auto v : _variables){ if(v != 0) return false; } return true; } - + MemberType getType() const { bool isConstant = true; bool isInput = true; bool isOutput = true; - for(const int& v : _variables){ + for(const auto v : _variables){ if(v < 0){ isConstant = false; isOutput = false; @@ -111,7 +111,7 @@ namespace PetriEngine { else if(isOutput) return MemberType::Output; else return MemberType::Regular; } - + bool operator==(const Member& m) const { size_t min = std::min(_variables.size(), m.size()); size_t max = std::max(_variables.size(), m.size()); @@ -144,7 +144,7 @@ namespace PetriEngine { Trivial operator>=(const Member& m) const { return m.trivialLessThan(*this, std::less_equal()); } - + private: void addVariables(const Member& m2) { uint32_t size = std::max(_variables.size(), m2._variables.size()); @@ -162,14 +162,14 @@ namespace PetriEngine { void subtractVariables(const Member& m2) { uint32_t size = std::max(_variables.size(), m2._variables.size()); _variables.resize(size, 0); - + for (uint32_t i = 0; i < size; i++) { if (i >= m2._variables.size()) { break; } else { _variables[i] -= m2._variables[i]; } - } + } } void multiply(const Member& m2) { @@ -186,11 +186,11 @@ namespace PetriEngine { } _variables.clear(); } - + Trivial trivialLessThan(const Member& m2, std::function compare) const { MemberType type1 = getType(); MemberType type2 = m2.getType(); - + // self comparison if (*this == m2) return compare(_constant, m2._constant) ? Trivial::True : Trivial::False; @@ -202,23 +202,23 @@ namespace PetriEngine { } else if(type2 == MemberType::Input && !compare(_constant, m2._constant)){ return Trivial::False; - } + } else if(type2 == MemberType::Output && compare(_constant, m2._constant)){ return Trivial::True; - } - } + } + } // input < output/constant - else if (type1 == MemberType::Input - && (type2 == MemberType::Constant || type2 == MemberType::Output) + else if (type1 == MemberType::Input + && (type2 == MemberType::Constant || type2 == MemberType::Output) && compare(_constant, m2._constant)) { return Trivial::True; - } + } // output < input/constant - else if (type1 == MemberType::Output - && (type2 == MemberType::Constant || type2 == MemberType::Input) + else if (type1 == MemberType::Output + && (type2 == MemberType::Constant || type2 == MemberType::Input) && !compare(_constant, m2._constant)) { return Trivial::False; - } + } return Trivial::Indeterminate; } diff --git a/include/PetriEngine/Simplification/Vector.h b/include/PetriEngine/Simplification/Vector.h index d46bdc938..a2d3cf68f 100644 --- a/include/PetriEngine/Simplification/Vector.h +++ b/include/PetriEngine/Simplification/Vector.h @@ -1,4 +1,4 @@ -/* +/* * File: LPFactory.h * Author: Peter G. Jensen * @@ -19,7 +19,7 @@ namespace PetriEngine { namespace Simplification { - enum op_t + enum op_t { OP_EQ, OP_LE, @@ -32,31 +32,31 @@ namespace PetriEngine { class Vector { public: friend LPCache; - + void free(); - + void inc(); - + size_t data_size() const; bool operator ==(const Vector& other) const { return _data == other._data; } - - - + + + const void* raw() const { return _data.data(); } - + size_t refs() const { return ref; } - + std::ostream& print(std::ostream& ss) const { int index = 0; - for(const std::pair& el : _data) + for(const auto& el : _data) { while(index < el.first) { ss << "0 "; ++index; } ss << el.second << " "; @@ -64,12 +64,12 @@ namespace PetriEngine { } return ss; } - + void write(std::vector& dest) const { memset(dest.data(), 0, sizeof (double) * dest.size()); - - for(const std::pair& el : _data) + + for(const auto& el : _data) { dest[el.first + 1] = el.second; } @@ -78,7 +78,7 @@ namespace PetriEngine { size_t write_indir(std::vector& dest, std::vector& indir) const { size_t l = 1; - for(const std::pair& el : _data) + for(const auto& el : _data) { dest[l] = el.second; if(dest[l] != 0) @@ -89,10 +89,10 @@ namespace PetriEngine { } return l; } - - + + private: - Vector(const std::vector& data) + Vector(const std::vector& data) { for(size_t i = 0; i < data.size(); ++i) { @@ -100,11 +100,11 @@ namespace PetriEngine { { _data.emplace_back(i, data[i]); } - } + } } - std::vector> _data; - LPCache* factory = NULL; + std::vector> _data; + LPCache* factory = nullptr; size_t ref = 0; }; } @@ -113,14 +113,14 @@ namespace PetriEngine { namespace std { using namespace PetriEngine::Simplification; - + template <> struct hash { size_t operator()(const Vector& k) const { - return MurmurHash64A(k.raw(), - k.data_size(), + return MurmurHash64A(k.raw(), + k.data_size(), 1337); } }; diff --git a/src/PetriEngine/PQL/Simplifier.cpp b/src/PetriEngine/PQL/Simplifier.cpp index d7f78ce86..62ccf5b44 100644 --- a/src/PetriEngine/PQL/Simplifier.cpp +++ b/src/PetriEngine/PQL/Simplifier.cpp @@ -211,10 +211,11 @@ namespace PetriEngine::PQL { } Member memberForPlace(size_t p, const SimplificationContext &context) { - std::vector row(context.net()->numberOfTransitions(), 0); + std::vector row(context.net()->numberOfTransitions(), 0); row.shrink_to_fit(); for (size_t t = 0; t < context.net()->numberOfTransitions(); t++) { - row[t] = context.net()->outArc(t, p) - context.net()->inArc(p, t); + row[t] = context.net()->outArc(t, p); + row[t] -= context.net()->inArc(p, t); } return Member(std::move(row), context.marking()[p]); } diff --git a/src/PetriEngine/Simplification/LinearProgram.cpp b/src/PetriEngine/Simplification/LinearProgram.cpp index 1dc2ec693..927ec3444 100644 --- a/src/PetriEngine/Simplification/LinearProgram.cpp +++ b/src/PetriEngine/Simplification/LinearProgram.cpp @@ -45,7 +45,7 @@ namespace PetriEngine { } constexpr auto infty = std::numeric_limits::infinity(); - + bool LinearProgram::isImpossible(const PQL::SimplificationContext& context, uint32_t solvetime) { bool use_ilp = true; auto net = context.net(); @@ -72,12 +72,12 @@ namespace PetriEngine { auto lp = context.makeBaseLP(); if(lp == nullptr) return false; - + int rowno = 1 + net->numberOfPlaces(); glp_add_rows(lp, _equations.size()); for(const auto& eq : _equations){ auto l = eq.row->write_indir(row, indir); - assert(!(std::isinf(eq.upper) && std::isinf(eq.lower))); + assert(!(std::isinf(eq.upper) && std::isinf(eq.lower))); glp_set_mat_row(lp, rowno, l-1, indir.data(), row.data()); if(!std::isinf(eq.lower) && !std::isinf(eq.upper)) { @@ -107,7 +107,7 @@ namespace PetriEngine { return false; } } - + // Set objective, kind and bounds for(size_t i = 1; i <= nCol; i++) { glp_set_obj_coef(lp, i, 0); @@ -217,7 +217,8 @@ namespace PetriEngine { p0 = m0[tp]; for (size_t t = 0; t < net->numberOfTransitions(); ++t) { - row[1 + t] = net->outArc(t, tp) - net->inArc(tp, t); + row[1 + t] = net->outArc(t, tp); + row[1 + t] -= net->inArc(tp, t); all_le_zero &= row[1 + t] <= 0; all_zero &= row[1 + t] == 0; } @@ -227,8 +228,10 @@ namespace PetriEngine { for (size_t t = 0; t < net->numberOfTransitions(); ++t) { double cnt = 0; - for(auto tp : places) - cnt += net->outArc(t, tp) - net->inArc(tp, t); + for(auto tp : places) { + cnt += net->outArc(t, tp); + cnt -= net->inArc(tp, t); + } row[1 + t] = cnt; all_le_zero &= row[1 + t] <= 0; all_zero &= row[1 + t] == 0; @@ -253,7 +256,7 @@ namespace PetriEngine { auto tmp_lp = context.makeBaseLP(); if(tmp_lp == nullptr) return result; - + // Max the objective glp_set_obj_dir(tmp_lp, GLP_MAX); From 97697b48eeee68ec6224699293366333abba3162 Mon Sep 17 00:00:00 2001 From: pgj Date: Tue, 8 Mar 2022 14:09:36 +0100 Subject: [PATCH 35/41] missing conversion from 32->64 bit ints --- include/PetriEngine/Simplification/Member.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PetriEngine/Simplification/Member.h b/include/PetriEngine/Simplification/Member.h index 0a24ce438..c30801b5b 100644 --- a/include/PetriEngine/Simplification/Member.h +++ b/include/PetriEngine/Simplification/Member.h @@ -115,7 +115,7 @@ namespace PetriEngine { bool operator==(const Member& m) const { size_t min = std::min(_variables.size(), m.size()); size_t max = std::max(_variables.size(), m.size()); - if(memcmp(_variables.data(), m._variables.data(), sizeof(int)*min) != 0) + if(!std::equal(_variables.begin(), _variables.begin() + min, m._variables.begin())) { return false; } From a9bd79ba9fbdf0ab540f6eeeba09308cc1d13c84 Mon Sep 17 00:00:00 2001 From: pgj Date: Wed, 9 Mar 2022 14:19:57 +0100 Subject: [PATCH 36/41] reduced copying during stubborn computation --- include/LTL/Stubborn/VisibleLTLStubbornSet.h | 4 ++-- src/PetriEngine/Stubborn/StubbornSet.cpp | 4 ++-- src/PetriEngine/Synthesis/GameStubbornSet.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/LTL/Stubborn/VisibleLTLStubbornSet.h b/include/LTL/Stubborn/VisibleLTLStubbornSet.h index 8bee84e38..1d8fc73c3 100644 --- a/include/LTL/Stubborn/VisibleLTLStubbornSet.h +++ b/include/LTL/Stubborn/VisibleLTLStubbornSet.h @@ -67,11 +67,11 @@ namespace LTL { if (_places_seen[place] > 0) return; _places_seen[place] = 1; for (uint32_t t = _places[place].pre; t < _places[place].post; ++t) { - auto tr = _arcs[t]; + const auto& tr = _arcs[t]; _visible[tr.index] = true; } for (uint32_t t = _places.get()[place].post; t < _places.get()[place + 1].pre; t++) { - auto tr = _arcs[t]; + const auto& tr = _arcs[t]; if (tr.direction < 0) _visible[tr.index] = true; } diff --git a/src/PetriEngine/Stubborn/StubbornSet.cpp b/src/PetriEngine/Stubborn/StubbornSet.cpp index 25b511385..b4821a16f 100644 --- a/src/PetriEngine/Stubborn/StubbornSet.cpp +++ b/src/PetriEngine/Stubborn/StubbornSet.cpp @@ -66,7 +66,7 @@ namespace PetriEngine { if ((_places_seen[place] & PresetSeen) != 0) return; _places_seen[place] = _places_seen[place] | PresetSeen; for (uint32_t t = _places[place].pre; t < _places[place].post; t++) { - auto &tr = _arcs[t]; + const auto &tr = _arcs[t]; addToStub(tr.index); } if (make_closure) closure(); @@ -76,7 +76,7 @@ namespace PetriEngine { if ((_places_seen[place] & PostsetSeen) != 0) return; _places_seen[place] = _places_seen[place] | PostsetSeen; for (uint32_t t = _places[place].post; t < _places[place + 1].pre; t++) { - auto tr = _arcs[t]; + const auto& tr = _arcs[t]; if (tr.direction < 0) addToStub(tr.index); } diff --git a/src/PetriEngine/Synthesis/GameStubbornSet.cpp b/src/PetriEngine/Synthesis/GameStubbornSet.cpp index 2c53729d8..72f284b13 100644 --- a/src/PetriEngine/Synthesis/GameStubbornSet.cpp +++ b/src/PetriEngine/Synthesis/GameStubbornSet.cpp @@ -162,7 +162,7 @@ namespace PetriEngine { // place loop uint64_t sum = 0; for (auto ti = _places[p].pre; ti != _places[p].post; ++ti) { - trans_t& arc = _arcs[ti]; + const auto& arc = _arcs[ti]; if (arc.direction <= 0 || _fireing_bounds[arc.index] == 0) continue; @@ -200,7 +200,7 @@ namespace PetriEngine { for (size_t p = 0; p < _net.numberOfPlaces(); ++p) { uint32_t ub = (*_parent)[p]; for (auto ti = _places[p].pre; ti != _places[p].post; ++ti) { - trans_t& arc = _arcs[ti]; + const auto& arc = _arcs[ti]; if (arc.direction <= 0 || !_future_enabled[arc.index]) continue; ub = std::numeric_limits::max(); From e68717cfc60543c650b700a8a7210ebe36d8b980 Mon Sep 17 00:00:00 2001 From: pgj Date: Wed, 9 Mar 2022 14:28:23 +0100 Subject: [PATCH 37/41] fixed missing fall-through on shallow conditions --- include/PetriEngine/PQL/Analyze.h | 4 +-- include/PetriEngine/PQL/Contexts.h | 2 +- src/PetriEngine/PQL/Analyze.cpp | 45 +++++++++++++++++++++++------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/include/PetriEngine/PQL/Analyze.h b/include/PetriEngine/PQL/Analyze.h index 7f7f20cf7..987d331cf 100644 --- a/include/PetriEngine/PQL/Analyze.h +++ b/include/PetriEngine/PQL/Analyze.h @@ -22,7 +22,7 @@ #include "PetriEngine/PQL/MutatingVisitor.h" -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { void analyze(Condition* condition, AnalysisContext& context); void analyze(Condition_ptr condition, AnalysisContext& context); @@ -79,6 +79,6 @@ namespace PetriEngine::PQL { void _accept(SimpleQuantifierCondition *element) override; }; -} +} } #endif //VERIFYPN_ANALYZE_H diff --git a/include/PetriEngine/PQL/Contexts.h b/include/PetriEngine/PQL/Contexts.h index 2e2e6fc95..4b3cc82c1 100644 --- a/include/PetriEngine/PQL/Contexts.h +++ b/include/PetriEngine/PQL/Contexts.h @@ -40,7 +40,7 @@ namespace PetriEngine { protected: const std::unordered_map& _placeNames; const std::unordered_map& _transitionNames; - const PetriNet* _net; + const PetriNet* _net = nullptr; public: /** A resolution result */ diff --git a/src/PetriEngine/PQL/Analyze.cpp b/src/PetriEngine/PQL/Analyze.cpp index cb3228963..f0dce160a 100644 --- a/src/PetriEngine/PQL/Analyze.cpp +++ b/src/PetriEngine/PQL/Analyze.cpp @@ -20,7 +20,7 @@ #include "PetriEngine/PQL/Analyze.h" -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { void analyze(Condition *condition, AnalysisContext& context) { AnalyzeVisitor visitor(context); Visitor::visit(visitor, condition); @@ -132,7 +132,11 @@ namespace PetriEngine::PQL { } void AnalyzeVisitor::_accept(UnfoldedFireableCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); + if (element->getCompiled()) + { + Visitor::visit(this, element->getCompiled()); + return; + } std::vector conds; AnalysisContext::ResolutionResult result = _context.resolve(element->getName(), false); @@ -160,16 +164,21 @@ namespace PetriEngine::PQL { conds.emplace_back(std::make_shared(id, lit)); } } - if(conds.size() == 1) element->_compiled = conds[0]; + if(conds.size() == 1) + element->_compiled = conds[0]; else if (conds.empty()) { element->_compiled = BooleanCondition::TRUE_CONSTANT; } - else element->_compiled = std::make_shared(conds); + else + element->_compiled = std::make_shared(conds); Visitor::visit(this, element->_compiled); } void AnalyzeVisitor::_accept(FireableCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); + if (element->getCompiled()) { + Visitor::visit(this, element->getCompiled()); + return; + } auto coloredContext = dynamic_cast(&_context); if(coloredContext != nullptr && coloredContext->isColored()) { @@ -234,7 +243,11 @@ namespace PetriEngine::PQL { } void AnalyzeVisitor::_accept(KSafeCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); + if (element->getCompiled()) + { + Visitor::visit(this, element->getCompiled()); + return; + } auto coloredContext = dynamic_cast(&_context); std::vector k_safe; @@ -258,7 +271,11 @@ namespace PetriEngine::PQL { } void AnalyzeVisitor::_accept(QuasiLivenessCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); + if (element->getCompiled()) + { + Visitor::visit(this, element->getCompiled()); + return; + } auto coloredContext = dynamic_cast(&_context); std::vector quasi; @@ -284,7 +301,11 @@ namespace PetriEngine::PQL { } void AnalyzeVisitor::_accept(LivenessCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); + if (element->getCompiled()) + { + Visitor::visit(this, element->getCompiled()); + return; + } auto coloredContext = dynamic_cast(&_context); std::vector liveness; @@ -310,7 +331,11 @@ namespace PetriEngine::PQL { } void AnalyzeVisitor::_accept(StableMarkingCondition *element) { - if (element->getCompiled()) Visitor::visit(this, element->getCompiled()); + if (element->getCompiled()) + { + Visitor::visit(this, element->getCompiled()); + return; + } auto coloredContext = dynamic_cast(&_context); std::vector stable_check; @@ -390,4 +415,4 @@ namespace PetriEngine::PQL { } std::sort(element->_places.begin(), element->_places.end()); } -} +} } From 94f4f00380e9e60b694c2db708d66c2adf0b30d8 Mon Sep 17 00:00:00 2001 From: pgj Date: Wed, 9 Mar 2022 20:22:42 +0100 Subject: [PATCH 38/41] fixed index typo --- src/PetriEngine/PQL/Expressions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PetriEngine/PQL/Expressions.cpp b/src/PetriEngine/PQL/Expressions.cpp index ad2fff7dd..d457f2389 100644 --- a/src/PetriEngine/PQL/Expressions.cpp +++ b/src/PetriEngine/PQL/Expressions.cpp @@ -335,7 +335,7 @@ namespace PetriEngine { if (cond->type() == type_id()) { auto ucond = static_cast(cond); context.negate(); - res = (*ucond)[0]->distance(context) + (*ucond)[0]->distance(context); + res = (*ucond)[0]->distance(context) + (*ucond)[1]->distance(context); context.negate(); } else if (cond->type() == type_id()) { context.negate(); From dc776daa2cdd97c494361d679f5bcfb2e2a8c713 Mon Sep 17 00:00:00 2001 From: pgj Date: Wed, 9 Mar 2022 21:23:24 +0100 Subject: [PATCH 39/41] updating CTL/LTL translation --- include/LTL/LTLValidator.h | 19 +- include/PetriEngine/PQL/Contexts.h | 2 +- include/PetriEngine/PQL/Simplifier.h | 7 + include/PetriEngine/Simplification/Member.h | 2 +- src/CTL/CTLEngine.cpp | 24 +- src/LTL/LTLSearch.cpp | 34 +-- src/PetriEngine/PQL/PredicateCheckers.cpp | 8 - src/PetriEngine/PQL/Simplifier.cpp | 230 ++++++-------------- 8 files changed, 97 insertions(+), 229 deletions(-) diff --git a/include/LTL/LTLValidator.h b/include/LTL/LTLValidator.h index 7770af280..a02342de7 100644 --- a/include/LTL/LTLValidator.h +++ b/include/LTL/LTLValidator.h @@ -27,15 +27,20 @@ namespace LTL { operator bool() const { return !bad(); } - bool isLTL(const PetriEngine::PQL::Condition_ptr& condition) { - std::shared_ptr quantifierCondition; - if ((quantifierCondition = std::dynamic_pointer_cast(condition)) != nullptr || - (quantifierCondition = std::dynamic_pointer_cast(condition)) != nullptr ){ - Visitor::visit(this, (*quantifierCondition)[0]); + static inline bool isLTL(const PetriEngine::PQL::Condition_ptr& condition) + { + return isLTL(condition.get()); + } + static inline bool isLTL(const PetriEngine::PQL::Condition* condition) { + LTLValidator v; + const PetriEngine::PQL::SimpleQuantifierCondition* quantifierCondition; + if ((quantifierCondition = dynamic_cast(condition)) != nullptr || + (quantifierCondition = dynamic_cast(condition)) != nullptr ){ + Visitor::visit(&v, (*quantifierCondition)[0]); } else { - Visitor::visit(this, condition); + Visitor::visit(&v, condition); } - return !bad(); + return !v.bad(); } protected: diff --git a/include/PetriEngine/PQL/Contexts.h b/include/PetriEngine/PQL/Contexts.h index 4b3cc82c1..c6d8bd991 100644 --- a/include/PetriEngine/PQL/Contexts.h +++ b/include/PetriEngine/PQL/Contexts.h @@ -195,7 +195,7 @@ namespace PetriEngine { _negated = !_negated; } - bool negated() const { + [[nodiscard]] bool negated() const { return _negated; } diff --git a/include/PetriEngine/PQL/Simplifier.h b/include/PetriEngine/PQL/Simplifier.h index 29b06a1e6..f19f12255 100644 --- a/include/PetriEngine/PQL/Simplifier.h +++ b/include/PetriEngine/PQL/Simplifier.h @@ -47,6 +47,13 @@ namespace PetriEngine::PQL { template Retval simplify_simple_quantifier(Retval &r); + void simplify_until(const Condition_ptr& cond1, const Condition_ptr& cond2); + void simplify_equal(const Expr_ptr& e1, const Expr_ptr& e2); + void simplify_less(const Expr_ptr& e1, const Expr_ptr& e2); + + void simplify_finally(const Condition_ptr& cond); + void simplify_exists(const Condition_ptr& cond); + void _accept(const NotCondition *element) override; void _accept(const AndCondition *element) override; diff --git a/include/PetriEngine/Simplification/Member.h b/include/PetriEngine/Simplification/Member.h index c30801b5b..84430ccc6 100644 --- a/include/PetriEngine/Simplification/Member.h +++ b/include/PetriEngine/Simplification/Member.h @@ -27,7 +27,7 @@ namespace PetriEngine { virtual ~Member(){} - int constant() const { return _constant; }; + int64_t constant() const { return _constant; }; bool canAnalyze() const { return _canAnalyze; }; size_t size() const { return _variables.size(); } std::vector& variables() { return _variables; } diff --git a/src/CTL/CTLEngine.cpp b/src/CTL/CTLEngine.cpp index c3b62192c..3c3452c0b 100644 --- a/src/CTL/CTLEngine.cpp +++ b/src/CTL/CTLEngine.cpp @@ -15,6 +15,7 @@ #include "PetriEngine/PQL/PrepareForReachability.h" #include "PetriEngine/PQL/PredicateCheckers.h" #include "LTL/LTLSearch.h" +#include "LTL/LTLValidator.h" #include #include @@ -253,28 +254,9 @@ bool recursiveSolve(Condition* query, PetriEngine::PetriNet* net, // there are probably many more cases w. nested quantifiers we can do // one instance is E[ non_temp U [E non_temp U ...]] in a chain // also, this should go into some *neat* visitor to do the check. - auto q = query->shared_from_this(); - bool ok = false; - if(auto* af = dynamic_cast(query)) - { - if(!isTemporal((*af)[0])) - ok = true; - } - else if(auto* eg = dynamic_cast(query)) - { - if(!isTemporal((*eg)[0])) - ok = true; - } - else if(auto* au = dynamic_cast(query)) { - if(!isTemporal((*au)[0]) && !isTemporal((*au)[1])) - ok = true; - } - else if(auto* eu = dynamic_cast(query)) { - if(!isTemporal((*eu)[0]) && !isTemporal((*eu)[1])) - ok = true; - } - if(ok) + if(LTL::LTLValidator::isLTL(query)) { + auto q = query->shared_from_this(); LTL::LTLSearch search(*net, q, options.buchiOptimization, options.ltl_compress_aps); return search.solve(false, options.kbound, options.ltlalgorithm, options.ltl_por, options.strategy, options.ltlHeuristic, options.ltluseweak, options.seed_offset); diff --git a/src/LTL/LTLSearch.cpp b/src/LTL/LTLSearch.cpp index 8176b5906..23af18543 100644 --- a/src/LTL/LTLSearch.cpp +++ b/src/LTL/LTLSearch.cpp @@ -46,43 +46,21 @@ namespace LTL { * should_negate indicates whether the returned formula is negated (in the case the parameter was E f) */ std::tuple to_ltl(const Condition_ptr &formula) { - LTL::LTLValidator validator; bool should_negate = false; Condition_ptr converted; + if (!LTLValidator::isLTL(formula)) { + converted = nullptr; + } if (auto _formula = dynamic_cast (formula.get())) { converted = std::make_shared((*_formula)[0]); should_negate = true; } else if (auto _formula = dynamic_cast (formula.get())) { converted = (*_formula)[0]; - } else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0])); - return to_ltl(f); - } else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0])); - return to_ltl(f); - } - else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0])); - return to_ltl(f); - } - else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0])); - return to_ltl(f); - } - else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); - return to_ltl(f); - } - else if (auto _formula = dynamic_cast (formula.get())) { - auto f = std::make_shared(std::make_shared((*_formula)[0], (*_formula)[1])); - return to_ltl(f); } else { - converted = formula; - } - Visitor::visit(validator, converted); - if (validator.bad()) { - converted = nullptr; + std::stringstream ss; + formula->toString(ss); + throw base_error("Unexpected formula for LTL engine: ", ss.str()); } return std::make_pair(converted, should_negate); } diff --git a/src/PetriEngine/PQL/PredicateCheckers.cpp b/src/PetriEngine/PQL/PredicateCheckers.cpp index 682fc2fb9..75a173629 100644 --- a/src/PetriEngine/PQL/PredicateCheckers.cpp +++ b/src/PetriEngine/PQL/PredicateCheckers.cpp @@ -226,14 +226,6 @@ namespace PetriEngine::PQL { setConditionFound(); } - void ContainsNextVisitor::_accept(const EXCondition* condition) { - setConditionFound(); - } - - void ContainsNextVisitor::_accept(const AXCondition* condition) { - setConditionFound(); - } - bool containsUpperBounds(const Condition_ptr& condition) { return containsUpperBounds(condition.get()); } diff --git a/src/PetriEngine/PQL/Simplifier.cpp b/src/PetriEngine/PQL/Simplifier.cpp index da5290eda..40d2e548c 100644 --- a/src/PetriEngine/PQL/Simplifier.cpp +++ b/src/PetriEngine/PQL/Simplifier.cpp @@ -21,7 +21,7 @@ #define RETURN(x) {_return_value = x; return;} -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { Retval simplify(const std::shared_ptr element, SimplificationContext& context) { Simplifier query_simplifier(context); @@ -291,9 +291,10 @@ namespace PetriEngine::PQL { } } - void Simplifier::_accept(const LessThanCondition *element) { - Member m1 = constraint((*element)[0].get(), _context); - Member m2 = constraint((*element)[1].get(), _context); + void Simplifier::simplify_less(const Expr_ptr& e1, const Expr_ptr& e2) + { + Member m1 = constraint(e1.get(), _context); + Member m2 = constraint(e2.get(), _context); AbstractProgramCollection_ptr lps, neglps; if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { // test for trivial comparison @@ -322,69 +323,36 @@ namespace PetriEngine::PQL { RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) } else { if (_context.negated()) { - RETURN(Retval(std::make_shared((*element)[1], (*element)[0]), + RETURN(Retval(std::make_shared(e2, e1), std::move(lps), std::move(neglps))) } else { - RETURN(Retval(std::make_shared((*element)[0], (*element)[1]), std::move(lps), + RETURN(Retval(std::make_shared(e1, e2), std::move(lps), std::move(neglps))) } } } - void Simplifier::_accept(const LessThanOrEqualCondition *element) { - Member m1 = constraint((*element)[0].get(), _context); - Member m2 = constraint((*element)[1].get(), _context); - - AbstractProgramCollection_ptr lps, neglps; - if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { - // test for trivial comparison - Trivial eval = _context.negated() ? m1 > m2 : m1 <= m2; - if (eval != Trivial::Indeterminate) { - RETURN(Retval(BooleanCondition::getShared(eval == Trivial::True))) - } else { // if no trivial case - int constant = m2.constant() - m1.constant(); - m1 -= m2; - m2 = m1; - lps = std::make_shared(_context.cache(), std::move(m1), constant, - (_context.negated() ? Simplification::OP_GT - : Simplification::OP_LE)); - neglps = std::make_shared(_context.cache(), std::move(m2), constant, - (_context.negated() ? Simplification::OP_LE - : Simplification::OP_GT)); - } - } else { - lps = std::make_shared(); - neglps = std::make_shared(); - } - - assert(lps); - assert(neglps); + void Simplifier::_accept(const LessThanCondition *element) { + simplify_less((*element)[0], (*element)[1]); + } - if (!_context.timeout() && !neglps->satisfiable(_context)) { - RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) - } else if (!_context.timeout() && !lps->satisfiable(_context)) { - RETURN(Retval(BooleanCondition::FALSE_CONSTANT)) - } else { - if (_context.negated()) { - RETURN(Retval(std::make_shared( - (*element)[1], (*element)[0]), std::move(lps), std::move(neglps))) - } else { - RETURN(Retval(std::make_shared( - (*element)[0], (*element)[1]), std::move(lps), std::move(neglps))) - } - } + void Simplifier::_accept(const LessThanOrEqualCondition *element) { + _context.negate(); + simplify_less((*element)[1], (*element)[0]); + _context.negate(); } - void Simplifier::_accept(const EqualCondition *element) { - Member m1 = constraint((*element)[0].get(), _context); - Member m2 = constraint((*element)[1].get(), _context); + void Simplifier::simplify_equal(const Expr_ptr& e1, const Expr_ptr& e2) + { + Member m1 = constraint(e1.get(), _context); + Member m2 = constraint(e2.get(), _context); std::shared_ptr lps, neglps; if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { if ((m1.isZero() && m2.isZero()) || m1.substrationIsZero(m2)) { RETURN(Retval(BooleanCondition::getShared( _context.negated() ? (m1.constant() != m2.constant()) : (m1.constant() == m2.constant())))) } else { - int constant = m2.constant() - m1.constant(); + int64_t constant = m2.constant() - m1.constant(); m1 -= m2; m2 = m1; neglps = @@ -409,56 +377,23 @@ namespace PetriEngine::PQL { RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) } else { if (_context.negated()) { - RETURN(Retval(std::make_shared((*element)[0], (*element)[1]), std::move(lps), + RETURN(Retval(std::make_shared(e1, e2), std::move(lps), std::move(neglps))) } else { - RETURN(Retval(std::make_shared((*element)[0], (*element)[1]), std::move(lps), + RETURN(Retval(std::make_shared(e1, e2), std::move(lps), std::move(neglps))) } } } - void Simplifier::_accept(const NotEqualCondition *element) { - Member m1 = constraint((*element)[0].get(), _context); - Member m2 = constraint((*element)[1].get(), _context); - std::shared_ptr lps, neglps; - if (!_context.timeout() && m1.canAnalyze() && m2.canAnalyze()) { - if ((m1.isZero() && m2.isZero()) || m1.substrationIsZero(m2)) { - RETURN(Retval(std::make_shared( - _context.negated() ? (m1.constant() == m2.constant()) : (m1.constant() != m2.constant())))) - } else { - int constant = m2.constant() - m1.constant(); - m1 -= m2; - m2 = m1; - lps = - std::make_shared( - std::make_shared(_context.cache(), std::move(m1), constant, - Simplification::OP_GT), - std::make_shared(_context.cache(), std::move(m2), constant, - Simplification::OP_LT)); - Member m3 = m2; - neglps = std::make_shared(_context.cache(), std::move(m3), constant, - Simplification::OP_EQ); + void Simplifier::_accept(const EqualCondition *element) { + simplify_equal((*element)[0], (*element)[1]); + } - if (_context.negated()) lps.swap(neglps); - } - } else { - lps = std::make_shared(); - neglps = std::make_shared(); - } - if (!_context.timeout() && !lps->satisfiable(_context)) { - RETURN(Retval(BooleanCondition::FALSE_CONSTANT)) - } else if (!_context.timeout() && !neglps->satisfiable(_context)) { - RETURN(Retval(BooleanCondition::TRUE_CONSTANT)) - } else { - if (_context.negated()) { - RETURN(Retval(std::make_shared((*element)[0], (*element)[1]), std::move(lps), - std::move(neglps))) - } else { - RETURN(Retval(std::make_shared((*element)[0], (*element)[1]), std::move(lps), - std::move(neglps))) - } - } + void Simplifier::_accept(const NotEqualCondition *element) { + _context.negate(); + simplify_equal((*element)[0], (*element)[1]); + _context.negate(); } void Simplifier::_accept(const DeadlockCondition *element) { @@ -662,16 +597,15 @@ namespace PetriEngine::PQL { { RETURN(Retval(std::make_shared(_context.negated() ? std::make_shared(_return_value.formula) : - _return_value.formula - ))) + _return_value.formula))) } } - void Simplifier::_accept(const UntilCondition *condition) { - bool neg = _context.negated(); + void Simplifier::simplify_until(const Condition_ptr& cond1, const Condition_ptr& cond2) + { + const bool neg = _context.negated(); _context.setNegate(false); - - Visitor::visit(this, condition->getCond2()); + Visitor::visit(this, cond2); Retval r2 = std::move(_return_value); if (r2.formula->isTriviallyTrue() || !r2.neglps->satisfiable(_context)) { _context.setNegate(neg); @@ -684,7 +618,7 @@ namespace PetriEngine::PQL { Retval(BooleanCondition::TRUE_CONSTANT) : Retval(BooleanCondition::FALSE_CONSTANT)) } - Visitor::visit(this, condition->getCond1()); + Visitor::visit(this, cond1); Retval r1 = std::move(_return_value); _context.setNegate(neg); @@ -696,8 +630,7 @@ namespace PetriEngine::PQL { } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(_context)) { RETURN(Retval(std::make_shared(r2.formula))) } else { - RETURN(Retval(std::make_shared( - std::make_shared(r1.formula, r2.formula)))) + RETURN(Retval(std::make_shared(r1.formula, r2.formula))) } } else { if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(_context)) { @@ -710,78 +643,53 @@ namespace PetriEngine::PQL { } } - void Simplifier::_accept(const ReleaseCondition *condition) { - bool neg = _context.negated(); - _context.setNegate(false); - - Visitor::visit(this, condition->getCond2()); - Retval r2 = std::move(_return_value); - if (r2.formula->isTriviallyTrue() || !r2.neglps->satisfiable(_context)) { - _context.setNegate(neg); - RETURN(neg ? - Retval(BooleanCondition::FALSE_CONSTANT) : - Retval(BooleanCondition::TRUE_CONSTANT)) - } else if (r2.formula->isTriviallyFalse() || !r2.lps->satisfiable(_context)) { - _context.setNegate(neg); - RETURN(neg ? - Retval(BooleanCondition::TRUE_CONSTANT) : - Retval(BooleanCondition::FALSE_CONSTANT)) - } - Visitor::visit(this, condition->getCond1()); - Retval r1 = std::move(_return_value); - - _context.setNegate(neg); + void Simplifier::_accept(const UntilCondition *condition) { + simplify_until(condition->getCond1(), condition->getCond2()); + } - if (_context.negated()) { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(_context)) { - RETURN(Retval(std::make_shared(r2.formula))) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(_context)) { - RETURN(Retval(std::make_shared(std::make_shared(r2.formula)))) - } else { - RETURN(Retval(std::make_shared( - std::make_shared(r1.formula, r2.formula)))) - } - } else { - if (r1.formula->isTriviallyTrue() || !r1.neglps->satisfiable(_context)) { - RETURN(std::move(r2)) - } else if (r1.formula->isTriviallyFalse() || !r1.lps->satisfiable(_context)) { - RETURN(Retval(std::make_shared(r2.formula))) - } else { - RETURN(Retval(std::make_shared(r1.formula, r2.formula))) - } - } + void Simplifier::_accept(const ReleaseCondition *condition) { + _context.negate(); + simplify_until(condition->getCond1(), condition->getCond2()); + _context.negate(); } - void Simplifier::_accept(const ECondition *condition) { - if (const std::shared_ptr xcond = std::dynamic_pointer_cast((*condition)[0])) { + + void Simplifier::simplify_exists(const Condition_ptr& cond) + { + if (const std::shared_ptr xcond = std::dynamic_pointer_cast(cond)) { Visitor::visit(*this, (*xcond)[0]); RETURN(_context.negated() ? simplifyAX(_return_value) : simplifyEX(_return_value)); } - Visitor::visit(this, condition->getCond()); + Visitor::visit(this, cond); RETURN(_context.negated() ? simplify_simple_quantifier(_return_value) : simplify_simple_quantifier(_return_value)) } + void Simplifier::_accept(const ECondition *condition) { + simplify_exists((*condition)[0]); + } + void Simplifier::_accept(const ACondition *condition) { - if (const std::shared_ptr xcond = std::dynamic_pointer_cast((*condition)[0])) { - Visitor::visit(*this, (*xcond)[0]); - RETURN(_context.negated() ? simplifyEX(_return_value) : simplifyAX(_return_value)) - } - Visitor::visit(this, condition->getCond()); - RETURN(_context.negated() ? simplify_simple_quantifier(_return_value) - : simplify_simple_quantifier(_return_value)) + _context.negate(); + simplify_exists((*condition)[0]); + _context.negate(); } - void Simplifier::_accept(const FCondition *condition) { - Visitor::visit(this, condition->getCond()); + void Simplifier::simplify_finally(const Condition_ptr& cond) + { + Visitor::visit(this, cond); RETURN(_context.negated() ? simplify_simple_quantifier(_return_value) - : simplify_simple_quantifier(_return_value)) + : simplify_simple_quantifier(_return_value)) + } + + void Simplifier::_accept(const FCondition *condition) { + simplify_finally((*condition)[0]); } void Simplifier::_accept(const GCondition *condition) { - Visitor::visit(this, condition->getCond()); - RETURN(_context.negated() ? simplify_simple_quantifier(_return_value) - : simplify_simple_quantifier(_return_value)) + _context.negate(); + simplify_finally((*condition)[0]); + _context.negate(); } void Simplifier::_accept(const XCondition *condition) { @@ -790,10 +698,6 @@ namespace PetriEngine::PQL { } void Simplifier::_accept(const BooleanCondition *condition) { - if (_context.negated()) { - RETURN(Retval(BooleanCondition::getShared(!condition->value))) - } else { - RETURN(Retval(BooleanCondition::getShared(condition->value))) - } + RETURN(Retval(BooleanCondition::getShared(condition->value xor _context.negated()))) } -} \ No newline at end of file +} } \ No newline at end of file From 3d78c48bed00769b7025d374a20a9cfb5fe8bd9a Mon Sep 17 00:00:00 2001 From: pgj Date: Wed, 9 Mar 2022 22:43:36 +0100 Subject: [PATCH 40/41] implementing missing visitors --- include/LTL/LTLToBuchi.h | 2 ++ include/LTL/LTLValidator.h | 4 ++++ include/LTL/Stubborn/VisibleTransitionVisitor.h | 1 + include/PetriEngine/PQL/Analyze.h | 3 ++- include/PetriEngine/PQL/BinaryPrinter.h | 6 ++++-- include/PetriEngine/PQL/CTLVisitor.h | 11 ++++++----- include/PetriEngine/PQL/Evaluation.h | 7 ++++--- include/PetriEngine/PQL/FormulaSize.h | 4 ++-- include/PetriEngine/PQL/PredicateCheckers.h | 4 ++++ include/PetriEngine/PQL/PushNegation.h | 3 ++- include/PetriEngine/PQL/Simplifier.h | 3 ++- include/PetriEngine/PQL/Visitor.h | 5 +++++ include/PetriEngine/PQL/XMLPrinter.h | 4 ++-- src/LTL/Algorithm/LTLToBuchi.cpp | 7 +++++++ src/LTL/Simplification/SpotToPQL.cpp | 7 ++++--- src/LTL/Stubborn/VisibleTransitionVisitor.cpp | 5 +++++ src/PetriEngine/PQL/BinaryPrinter.cpp | 13 +++++++++++-- src/PetriEngine/PQL/CTLVisitor.cpp | 4 ++-- src/PetriEngine/PQL/Evaluation.cpp | 10 ++++++++-- src/PetriEngine/PQL/Expressions.cpp | 3 +++ src/PetriEngine/PQL/PQLQueryParser.y | 4 +++- src/PetriEngine/PQL/PQLQueryTokens.l | 1 + src/PetriEngine/PQL/PredicateCheckers.cpp | 11 +++++++++-- src/PetriParse/QueryBinaryParser.cpp | 15 +++++++++++++++ 24 files changed, 108 insertions(+), 29 deletions(-) diff --git a/include/LTL/LTLToBuchi.h b/include/LTL/LTLToBuchi.h index 2a3c15ad6..c7191489c 100644 --- a/include/LTL/LTLToBuchi.h +++ b/include/LTL/LTLToBuchi.h @@ -95,6 +95,8 @@ namespace LTL { void _accept(const PetriEngine::PQL::UntilCondition *condition) override; + void _accept(const PetriEngine::PQL::ReleaseCondition *condition) override; + public: explicit FormulaToSpotSyntax(APCompression compress_aps = APCompression::Choose) diff --git a/include/LTL/LTLValidator.h b/include/LTL/LTLValidator.h index a02342de7..1470bf047 100644 --- a/include/LTL/LTLValidator.h +++ b/include/LTL/LTLValidator.h @@ -119,6 +119,10 @@ namespace LTL { Visitor::visit(this, (*condition)[0]); } + void _accept(const PetriEngine::PQL::ReleaseCondition *condition) override { + Visitor::visit(this, (*condition)[0]); + } + void _accept(const PetriEngine::PQL::UnfoldedFireableCondition *element) override { } diff --git a/include/LTL/Stubborn/VisibleTransitionVisitor.h b/include/LTL/Stubborn/VisibleTransitionVisitor.h index 292931786..2a24d00ff 100644 --- a/include/LTL/Stubborn/VisibleTransitionVisitor.h +++ b/include/LTL/Stubborn/VisibleTransitionVisitor.h @@ -73,6 +73,7 @@ namespace LTL { void _accept(const PetriEngine::PQL::UntilCondition *condition) override; + void _accept(const PetriEngine::PQL::ReleaseCondition *condition) override; private: std::unique_ptr &_places; }; diff --git a/include/PetriEngine/PQL/Analyze.h b/include/PetriEngine/PQL/Analyze.h index 66e92eb8a..4972cb959 100644 --- a/include/PetriEngine/PQL/Analyze.h +++ b/include/PetriEngine/PQL/Analyze.h @@ -77,9 +77,10 @@ namespace PetriEngine { namespace PQL { void _accept(UntilCondition *element) override; + void _accept(ReleaseCondition *element); + void _accept(SimpleQuantifierCondition *element) override; - void _accept(ReleaseCondition *element); }; } } diff --git a/include/PetriEngine/PQL/BinaryPrinter.h b/include/PetriEngine/PQL/BinaryPrinter.h index cdf5dc1ca..2776aebb4 100644 --- a/include/PetriEngine/PQL/BinaryPrinter.h +++ b/include/PetriEngine/PQL/BinaryPrinter.h @@ -19,7 +19,7 @@ #include "Visitor.h" -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { class BinaryPrinter : public Visitor { public: explicit BinaryPrinter(std::ostream& os) : @@ -38,6 +38,8 @@ namespace PetriEngine::PQL { void _accept(const UntilCondition *condition) override; + void _accept(const ReleaseCondition *condition) override; + void _accept(const BooleanCondition *element) override; void _accept(const UnfoldedIdentifierExpr *element) override; @@ -61,7 +63,7 @@ namespace PetriEngine::PQL { void _accept(const ShallowCondition *condition) override; }; -} +} } #endif //VERIFYPN_BINARYPRINTER_H diff --git a/include/PetriEngine/PQL/CTLVisitor.h b/include/PetriEngine/PQL/CTLVisitor.h index 29f302884..4d1619211 100644 --- a/include/PetriEngine/PQL/CTLVisitor.h +++ b/include/PetriEngine/PQL/CTLVisitor.h @@ -46,6 +46,12 @@ namespace PetriEngine::PQL { void _accept(const UntilCondition *condition) override; + void _accept(const ReleaseCondition *condition); + + void _accept(const LogicalCondition *element); + + void _accept(const CompareCondition *element); + void _accept(const UnfoldedFireableCondition *element) override; void _accept(const FireableCondition *element) override; @@ -79,11 +85,6 @@ namespace PetriEngine::PQL { private: CTLSyntaxType _cur_type; - void _accept(const LogicalCondition *element); - - void _accept(const CompareCondition *element); - - void _accept(const ReleaseCondition *condition); }; } diff --git a/include/PetriEngine/PQL/Evaluation.h b/include/PetriEngine/PQL/Evaluation.h index 9b8d47894..c69c88554 100644 --- a/include/PetriEngine/PQL/Evaluation.h +++ b/include/PetriEngine/PQL/Evaluation.h @@ -84,6 +84,8 @@ namespace PetriEngine { namespace PQL { void _accept(UntilCondition *element) override; + void _accept(ReleaseCondition *element) override; + void _accept(AndCondition *element) override; void _accept(OrCondition *element) override; @@ -109,8 +111,6 @@ namespace PetriEngine { namespace PQL { void _accept(UnfoldedUpperBoundsCondition *element) override; void _accept(ShallowCondition *element) override; - - void _accept(ReleaseCondition *element) override; }; Condition::Result evaluateAndSet(Condition *element, const EvaluationContext &context); @@ -131,6 +131,8 @@ namespace PetriEngine { namespace PQL { void _accept(UntilCondition *element) override; + void _accept(ReleaseCondition *element) override; + void _accept(AndCondition *element) override; void _accept(OrCondition *element) override; @@ -155,7 +157,6 @@ namespace PetriEngine { namespace PQL { void _accept(ShallowCondition *element) override; - void _accept(ReleaseCondition *element) override; }; } } diff --git a/include/PetriEngine/PQL/FormulaSize.h b/include/PetriEngine/PQL/FormulaSize.h index 577c1604e..68b9ae62f 100644 --- a/include/PetriEngine/PQL/FormulaSize.h +++ b/include/PetriEngine/PQL/FormulaSize.h @@ -73,9 +73,9 @@ namespace PetriEngine { namespace PQL { void _accept(const UntilCondition *condition) override; - void _accept(const LogicalCondition *condition) override; + void _accept(const ReleaseCondition *condition) override; - void _accept(const ReleaseCondition *condition); + void _accept(const LogicalCondition *condition) override; }; } } #endif //VERIFYPN_FORMULASIZE_H diff --git a/include/PetriEngine/PQL/PredicateCheckers.h b/include/PetriEngine/PQL/PredicateCheckers.h index 8a48b39a8..409673155 100644 --- a/include/PetriEngine/PQL/PredicateCheckers.h +++ b/include/PetriEngine/PQL/PredicateCheckers.h @@ -47,6 +47,8 @@ namespace PetriEngine::PQL { void _accept(const SimpleQuantifierCondition *condition) override; void _accept(const UntilCondition *condition) override; + void _accept(const ReleaseCondition *condition) override; + }; @@ -88,6 +90,8 @@ namespace PetriEngine::PQL { void _accept(const UntilCondition *element) override; + void _accept(const ReleaseCondition *element) override; + void _accept(const CompareConjunction *element) override; }; diff --git a/include/PetriEngine/PQL/PushNegation.h b/include/PetriEngine/PQL/PushNegation.h index 28901623c..27c5a0a2b 100644 --- a/include/PetriEngine/PQL/PushNegation.h +++ b/include/PetriEngine/PQL/PushNegation.h @@ -95,6 +95,8 @@ namespace PetriEngine::PQL { void _accept(UntilCondition *condition) override; + void _accept(ReleaseCondition *condition) override; + void _accept(UnfoldedFireableCondition *element) override; void _accept(BooleanCondition *element) override; @@ -127,7 +129,6 @@ namespace PetriEngine::PQL { Condition_ptr pushneg_EU(UntilCondition *element); - void _accept(ReleaseCondition *element); }; } diff --git a/include/PetriEngine/PQL/Simplifier.h b/include/PetriEngine/PQL/Simplifier.h index f19f12255..efba5c925 100644 --- a/include/PetriEngine/PQL/Simplifier.h +++ b/include/PetriEngine/PQL/Simplifier.h @@ -88,9 +88,10 @@ namespace PetriEngine::PQL { void _accept(const UntilCondition *condition) override; + void _accept(const ReleaseCondition *condition) override; + void _accept(const BooleanCondition *element) override; - void _accept(const ReleaseCondition *condition); }; Member constraint(const Expr *element, const SimplificationContext &context); diff --git a/include/PetriEngine/PQL/Visitor.h b/include/PetriEngine/PQL/Visitor.h index bc023bf3f..5161cf98d 100644 --- a/include/PetriEngine/PQL/Visitor.h +++ b/include/PetriEngine/PQL/Visitor.h @@ -484,6 +484,11 @@ namespace PetriEngine { visit(this, (*condition)[1]); } + void _accept(const ReleaseCondition *condition) override { + visit(this, (*condition)[0]); + visit(this, (*condition)[1]); + } + void _accept(const ShallowCondition *element) override { if (const auto &compiled = element->getCompiled()) visit(this, compiled); diff --git a/include/PetriEngine/PQL/XMLPrinter.h b/include/PetriEngine/PQL/XMLPrinter.h index b4db7b8bb..e8d7ff003 100644 --- a/include/PetriEngine/PQL/XMLPrinter.h +++ b/include/PetriEngine/PQL/XMLPrinter.h @@ -85,6 +85,8 @@ namespace PetriEngine { void _accept(const UntilCondition *condition) override; + void _accept(const ReleaseCondition *condition) override; + void _accept(const UnfoldedFireableCondition *element) override; void _accept(const BooleanCondition *element) override; @@ -122,8 +124,6 @@ namespace PetriEngine { _printer->closeXmlTag(_tag); } }; - - void _accept(const ReleaseCondition *element); }; } } diff --git a/src/LTL/Algorithm/LTLToBuchi.cpp b/src/LTL/Algorithm/LTLToBuchi.cpp index d6ef8b902..df6e74435 100644 --- a/src/LTL/Algorithm/LTLToBuchi.cpp +++ b/src/LTL/Algorithm/LTLToBuchi.cpp @@ -80,6 +80,13 @@ namespace LTL { _formula = spot::formula::U(lhs, _formula); } + void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::ReleaseCondition *element) { + Visitor::visit(this, (*element)[0]); + auto lhs = _formula; + Visitor::visit(this, (*element)[1]); + _formula = spot::formula::R(lhs, _formula); + } + void FormulaToSpotSyntax::_accept(const PetriEngine::PQL::LessThanCondition *element) { _formula = make_atomic_prop(std::make_shared(*element)); } diff --git a/src/LTL/Simplification/SpotToPQL.cpp b/src/LTL/Simplification/SpotToPQL.cpp index d770899d0..3569db87d 100644 --- a/src/LTL/Simplification/SpotToPQL.cpp +++ b/src/LTL/Simplification/SpotToPQL.cpp @@ -58,6 +58,9 @@ namespace LTL { case spot::op::U: return std::make_shared( toPQL(formula[0], apinfo), toPQL(formula[1], apinfo)); + case spot::op::R: + return std::make_shared( + toPQL(formula[0], apinfo), toPQL(formula[1], apinfo)); case spot::op::Or: { std::vector conds; std::transform(std::begin(formula), std::end(formula), std::back_insert_iterator(conds), @@ -70,8 +73,6 @@ namespace LTL { [&](auto f) { return toPQL(f, apinfo); }); return std::make_shared(conds); } - case spot::op::R: - throw base_error("R not implemented"); case spot::op::W: throw base_error("W not implemented"); case spot::op::M: @@ -132,7 +133,7 @@ namespace LTL { spot::tl_simplifier simplifier{static_cast(optimization)}; f = simplifier.simplify(f); // spot simplifies using unsupported operators R, W, and M, which we now remove. - f = spot::unabbreviate(f, "RWM"); + f = spot::unabbreviate(f, "WM"); return toPQL(f, apinfo); } } // namespace LTL diff --git a/src/LTL/Stubborn/VisibleTransitionVisitor.cpp b/src/LTL/Stubborn/VisibleTransitionVisitor.cpp index 108669f0d..beafad422 100644 --- a/src/LTL/Stubborn/VisibleTransitionVisitor.cpp +++ b/src/LTL/Stubborn/VisibleTransitionVisitor.cpp @@ -129,4 +129,9 @@ namespace LTL { Visitor::visit(this, condition->getCond2()); } + void VisibleTransitionVisitor::_accept(const PetriEngine::PQL::ReleaseCondition *condition) { + Visitor::visit(this, condition->getCond1()); + Visitor::visit(this, condition->getCond2()); + } + } \ No newline at end of file diff --git a/src/PetriEngine/PQL/BinaryPrinter.cpp b/src/PetriEngine/PQL/BinaryPrinter.cpp index 6473e240b..42511db59 100644 --- a/src/PetriEngine/PQL/BinaryPrinter.cpp +++ b/src/PetriEngine/PQL/BinaryPrinter.cpp @@ -16,7 +16,7 @@ #include "PetriEngine/PQL/BinaryPrinter.h" -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { void BinaryPrinter::_accept(const LiteralExpr *element){ os.write("l", sizeof(char)); int temp = element->value(); @@ -78,6 +78,15 @@ namespace PetriEngine::PQL { Visitor::visit(this, (*condition)[1]); } + void BinaryPrinter::_accept(const ReleaseCondition *condition){ + auto path = condition->getPath(); + auto quant = condition->getQuantifier(); + os.write(reinterpret_cast(&path), sizeof(Path)); + os.write(reinterpret_cast(&quant), sizeof(Quantifier)); + Visitor::visit(this, (*condition)[0]); + Visitor::visit(this, (*condition)[1]); + } + void BinaryPrinter::_accept(const LogicalCondition *condition){ auto path = condition->getPath(); auto quant = condition->getQuantifier(); @@ -166,4 +175,4 @@ namespace PetriEngine::PQL { void BinaryPrinter::_accept(const ShallowCondition *condition) { Visitor::visit(this, condition->getCompiled()); } -} +} } diff --git a/src/PetriEngine/PQL/CTLVisitor.cpp b/src/PetriEngine/PQL/CTLVisitor.cpp index 03e197ca4..d9df08170 100644 --- a/src/PetriEngine/PQL/CTLVisitor.cpp +++ b/src/PetriEngine/PQL/CTLVisitor.cpp @@ -18,7 +18,7 @@ #include -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { void IsCTLVisitor::_accept(const NotCondition *element) { Visitor::visit(this, (*element)[0]); if (_cur_type != CTLSyntaxType::BOOLEAN) @@ -194,4 +194,4 @@ namespace PetriEngine::PQL { void IsCTLVisitor::_accept(const IdentifierExpr *element) { _cur_type = CTLSyntaxType::BOOLEAN; } -} \ No newline at end of file +} } \ No newline at end of file diff --git a/src/PetriEngine/PQL/Evaluation.cpp b/src/PetriEngine/PQL/Evaluation.cpp index 381462e83..be2417d58 100644 --- a/src/PetriEngine/PQL/Evaluation.cpp +++ b/src/PetriEngine/PQL/Evaluation.cpp @@ -126,7 +126,10 @@ namespace PetriEngine { namespace PQL { void EvaluateVisitor::_accept(ACondition *element) { auto cond = (*element)[0]; Visitor::visit(this, cond); - if (cond->type() == type_id() || cond->type() == type_id() || cond->type() == type_id()) + if (cond->type() == type_id() || + cond->type() == type_id() || + cond->type() == type_id() || + cond->type() == type_id()) return; if (_return_value == Condition::RFALSE) _return_value = {Condition::RFALSE}; @@ -136,7 +139,10 @@ namespace PetriEngine { namespace PQL { void EvaluateVisitor::_accept(ECondition *element) { auto cond = (*element)[0]; Visitor::visit(this, cond); - if (cond->type() == type_id() || cond->type() == type_id() || cond->type() == type_id()) + if (cond->type() == type_id() || + cond->type() == type_id() || + cond->type() == type_id() || + cond->type() == type_id()) return; if (_return_value == Condition::RTRUE) _return_value = {Condition::RTRUE}; diff --git a/src/PetriEngine/PQL/Expressions.cpp b/src/PetriEngine/PQL/Expressions.cpp index d457f2389..cbbb8ebd3 100644 --- a/src/PetriEngine/PQL/Expressions.cpp +++ b/src/PetriEngine/PQL/Expressions.cpp @@ -337,6 +337,9 @@ namespace PetriEngine { context.negate(); res = (*ucond)[0]->distance(context) + (*ucond)[1]->distance(context); context.negate(); + } else if (cond->type() == type_id()) { + auto ucond = static_cast(cond); + res = (*ucond)[0]->distance(context) + (*ucond)[1]->distance(context); } else if (cond->type() == type_id()) { context.negate(); res = static_cast(cond)->distance(context); diff --git a/src/PetriEngine/PQL/PQLQueryParser.y b/src/PetriEngine/PQL/PQLQueryParser.y index 30448e6fb..252e51cbf 100644 --- a/src/PetriEngine/PQL/PQLQueryParser.y +++ b/src/PetriEngine/PQL/PQLQueryParser.y @@ -27,7 +27,7 @@ void pqlqerror(const char *s) {printf("ERROR: %s\n", s);} /* Terminal type definition */ %token ID INT -%token A E X F G U EF EG AF AG EX AX CONTROL +%token A E X F G U R EF EG AF AG EX AX CONTROL %token DEADLOCK TRUE FALSE %token LPAREN RPAREN %token AND OR NOT @@ -91,6 +91,8 @@ atomic_formula : TRUE { $$ = new BooleanCondition(true);} path_formula : X state_formula { $$ = new XCondition(Condition_ptr($2)); } | F state_formula { $$ = new FCondition(Condition_ptr($2)); } | G state_formula { $$ = new GCondition(Condition_ptr($2)); } + | LPAREN state_formula RPAREN R LPAREN state_formula RPAREN + { $$ = new ReleaseCondition(Condition_ptr($2), Condition_ptr($6)); }; | LPAREN state_formula RPAREN U LPAREN state_formula RPAREN { $$ = new UntilCondition(Condition_ptr($2), Condition_ptr($6)); }; ; diff --git a/src/PetriEngine/PQL/PQLQueryTokens.l b/src/PetriEngine/PQL/PQLQueryTokens.l index 319ac975c..1102b8a7b 100644 --- a/src/PetriEngine/PQL/PQLQueryTokens.l +++ b/src/PetriEngine/PQL/PQLQueryTokens.l @@ -48,6 +48,7 @@ letter [a-zA-Z_] "F" {return TOKEN(F);} "G" {return TOKEN(G);} "U" {return TOKEN(U);} +"R" {return TOKEN(R);} "control" {return TOKEN(CONTROL);} "NOT" {return TOKEN(NOT);} {letter}({letter}|{digit})* {SAVE_TOKEN; return ID;} diff --git a/src/PetriEngine/PQL/PredicateCheckers.cpp b/src/PetriEngine/PQL/PredicateCheckers.cpp index 75a173629..96a6bb239 100644 --- a/src/PetriEngine/PQL/PredicateCheckers.cpp +++ b/src/PetriEngine/PQL/PredicateCheckers.cpp @@ -20,7 +20,7 @@ #include "PetriEngine/PQL/PredicateCheckers.h" -namespace PetriEngine::PQL { +namespace PetriEngine { namespace PQL { /*** Nested Deadlock ***/ @@ -67,6 +67,9 @@ namespace PetriEngine::PQL { setConditionFound(); } + void IsTemporalVisitor::_accept(const ReleaseCondition *condition) { + setConditionFound(); + } /*** Is Reachability ***/ bool isReachability(const Condition* condition) { @@ -89,6 +92,10 @@ namespace PetriEngine::PQL { setConditionFound(); } + void IsNotReachabilityVisitor::_accept(const ReleaseCondition *element) { + setConditionFound(); + } + void IsNotReachabilityVisitor::_accept(const ECondition *element) { if (!_is_nested) { if ((*element)[0]->type() == type_id()) { @@ -235,4 +242,4 @@ namespace PetriEngine::PQL { Visitor::visit(visitor, condition); return visitor.getReturnValue(); } -} +} } diff --git a/src/PetriParse/QueryBinaryParser.cpp b/src/PetriParse/QueryBinaryParser.cpp index d5bb0302a..c45f9bbb3 100644 --- a/src/PetriParse/QueryBinaryParser.cpp +++ b/src/PetriParse/QueryBinaryParser.cpp @@ -224,6 +224,21 @@ Condition_ptr QueryBinaryParser::parseQuery(std::istream& binary, const std::vec else return std::make_shared(std::make_shared(cond1, cond2)); } + else if(p == Path::R) + { + auto cond2 = parseQuery(binary, names); + if(cond2 == nullptr) + { + assert(false); + return nullptr; + } + if (q == Quantifier::EMPTY) + return std::make_shared(cond1, cond2); + else if(q == Quantifier::A) + return std::make_shared(std::make_shared(cond1, cond2)); + else + return std::make_shared(std::make_shared(cond1, cond2)); + } else if(p == Path::PControl) { return std::make_shared(cond1); From b6fcce56eccbfa781a6c6bb5df93b98b0f51ac45 Mon Sep 17 00:00:00 2001 From: pgj Date: Thu, 10 Mar 2022 09:06:25 +0100 Subject: [PATCH 41/41] flipping negation on accept on release --- src/PetriEngine/PQL/PushNegation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PetriEngine/PQL/PushNegation.cpp b/src/PetriEngine/PQL/PushNegation.cpp index 8c8369096..261b2eebf 100644 --- a/src/PetriEngine/PQL/PushNegation.cpp +++ b/src/PetriEngine/PQL/PushNegation.cpp @@ -355,7 +355,7 @@ namespace PetriEngine { namespace PQL { if (negated) return std::make_shared(std::make_shared(a, b)); - else + else return std::make_shared(std::make_shared(a, b)); }, stats, context, nested, negated, initrw); return cond; @@ -439,8 +439,8 @@ namespace PetriEngine { namespace PQL { void PushNegationVisitor::_accept(ReleaseCondition* element) { auto cond = initialMarkingRW([&]() -> Condition_ptr { // Push negation and convert this to a UntilCondition if it is negated - auto b = subvisit(element->getCond2(), true, negated); - auto a = subvisit(element->getCond1(), true, negated); + auto b = subvisit(element->getCond2(), true, !negated); + auto a = subvisit(element->getCond1(), true, !negated); if (auto cond = std::dynamic_pointer_cast(b)) { static_assert(negstat_t::nrules >= 35);