spot 2.13
formula.hh
Go to the documentation of this file.
1// -*- coding: utf-8 -*-
2// Copyright (C) by the Spot authors, see the AUTHORS file for details.
3//
4// This file is part of Spot, a model checking library.
5//
6// Spot is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 3 of the License, or
9// (at your option) any later version.
10//
11// Spot is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14// License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
21#pragma once
22
29
32
35
38
41
44
45#include <spot/misc/common.hh>
46#include <memory>
47#include <cstdint>
48#include <initializer_list>
49#include <cassert>
50#include <vector>
51#include <string>
52#include <iterator>
53#include <iosfwd>
54#include <sstream>
55#include <list>
56#include <cstddef>
57#include <limits>
58
59// The strong_X operator was introduced in Spot 2.8.2 to fix an issue
60// with from_ltlf(). As adding a new operator is a backward
61// incompatibility, causing new warnings from the compiler.
62#if defined(SPOT_BUILD) || defined(SPOT_USES_STRONG_X)
63// Use #if SPOT_HAS_STRONG_X in code that need to be backward
64// compatible with older Spot versions.
65# define SPOT_HAS_STRONG_X 1
66// You may #define SPOT_WANT_STRONG_X yourself before including
67// this file to force the use of STRONG_X
68# define SPOT_WANT_STRONG_X 1
69#endif
70
71namespace spot
72{
73
74
77 enum class op: uint8_t
78 {
79 ff,
80 tt,
81 eword,
82 ap,
83 // unary operators
84 Not,
85 X,
86 F,
87 G,
88 Closure,
91 // binary operators
92 Xor,
93 Implies,
94 Equiv,
95 U,
96 R,
97 W,
98 M,
99 EConcat,
101 UConcat,
102 // n-ary operators
103 Or,
104 OrRat,
105 And,
106 AndRat,
107 AndNLM,
108 Concat,
109 Fusion,
110 // star-like operators
111 Star,
112 FStar,
114#ifdef SPOT_WANT_STRONG_X
115 strong_X,
116#endif
117 };
118
119#ifndef SWIG
126 class SPOT_API fnode final
127 {
128 public:
133 const fnode* clone() const
134 {
135 // Saturate.
136 ++refs_;
137 if (SPOT_UNLIKELY(!refs_))
138 saturated_ = 1;
139 return this;
140 }
141
147 void destroy() const
148 {
149 if (SPOT_LIKELY(refs_))
150 --refs_;
151 else if (SPOT_LIKELY(!saturated_))
152 // last reference to a node that is not a constant
153 destroy_aux();
154 }
155
157 static constexpr uint8_t unbounded()
158 {
159 return UINT8_MAX;
160 }
161
163 static const fnode* ap(const std::string& name);
165 static const fnode* unop(op o, const fnode* f);
167 static const fnode* binop(op o, const fnode* f, const fnode* g);
169 static const fnode* multop(op o, std::vector<const fnode*> l);
171 static const fnode* bunop(op o, const fnode* f,
172 unsigned min, unsigned max = unbounded());
173
175 static const fnode* nested_unop_range(op uo, op bo, unsigned min,
176 unsigned max, const fnode* f);
177
179 op kind() const
180 {
181 return op_;
182 }
183
185 std::string kindstr() const;
186
189 bool is(op o) const
190 {
191 return op_ == o;
192 }
193
194 bool is(op o1, op o2) const
195 {
196 return op_ == o1 || op_ == o2;
197 }
198
199 bool is(op o1, op o2, op o3) const
200 {
201 return op_ == o1 || op_ == o2 || op_ == o3;
202 }
203
204 bool is(op o1, op o2, op o3, op o4) const
205 {
206 return op_ == o1 || op_ == o2 || op_ == o3 || op_ == o4;
207 }
208
209 bool is(std::initializer_list<op> l) const
210 {
211 const fnode* n = this;
212 for (auto o: l)
213 {
214 if (!n->is(o))
215 return false;
216 n = n->nth(0);
217 }
218 return true;
219 }
221
223 const fnode* get_child_of(op o) const
224 {
225 if (op_ != o)
226 return nullptr;
227 if (SPOT_UNLIKELY(size_ != 1))
228 report_get_child_of_expecting_single_child_node();
229 return nth(0);
230 }
231
233 const fnode* get_child_of(std::initializer_list<op> l) const
234 {
235 auto c = this;
236 for (auto o: l)
237 {
238 c = c->get_child_of(o);
239 if (c == nullptr)
240 return c;
241 }
242 return c;
243 }
244
246 unsigned min() const
247 {
248 if (SPOT_UNLIKELY(op_ != op::FStar && op_ != op::Star))
249 report_min_invalid_arg();
250 return min_;
251 }
252
254 unsigned max() const
255 {
256 if (SPOT_UNLIKELY(op_ != op::FStar && op_ != op::Star))
257 report_max_invalid_arg();
258 return max_;
259 }
260
262 unsigned size() const
263 {
264 return size_;
265 }
266
268 bool is_leaf() const
269 {
270 return size_ == 0;
271 }
272
274 size_t id() const
275 {
276 return id_;
277 }
278
280 const fnode*const* begin() const
281 {
282 return children;
283 }
284
286 const fnode*const* end() const
287 {
288 return children + size();
289 }
290
292 const fnode* nth(unsigned i) const
293 {
294 if (SPOT_UNLIKELY(i >= size()))
295 report_non_existing_child();
296 const fnode* c = children[i];
297 SPOT_ASSUME(c != nullptr);
298 return c;
299 }
300
302 static const fnode* ff()
303 {
304 return ff_;
305 }
306
308 bool is_ff() const
309 {
310 return op_ == op::ff;
311 }
312
314 static const fnode* tt()
315 {
316 return tt_;
317 }
318
320 bool is_tt() const
321 {
322 return op_ == op::tt;
323 }
324
326 static const fnode* eword()
327 {
328 return ew_;
329 }
330
332 bool is_eword() const
333 {
334 return op_ == op::eword;
335 }
336
338 bool is_constant() const
339 {
340 return op_ == op::ff || op_ == op::tt || op_ == op::eword;
341 }
342
344 bool is_Kleene_star() const
345 {
346 if (op_ != op::Star)
347 return false;
348 return min_ == 0 && max_ == unbounded();
349 }
350
352 static const fnode* one_star()
353 {
354 if (!one_star_)
355 one_star_ = new fnode(op::Star, tt_, 0, unbounded(), true);
356 return one_star_;
357 }
358
360 static const fnode* one_plus()
361 {
362 if (!one_plus_)
363 one_plus_ = new fnode(op::Star, tt_, 1, unbounded(), true);
364 return one_plus_;
365 }
366
368 const std::string& ap_name() const;
369
371 std::ostream& dump(std::ostream& os) const;
372
374 const fnode* all_but(unsigned i) const;
375
377 unsigned boolean_count() const
378 {
379 unsigned pos = 0;
380 unsigned s = size();
381 while (pos < s && children[pos]->is_boolean())
382 ++pos;
383 return pos;
384 }
385
387 const fnode* boolean_operands(unsigned* width = nullptr) const;
388
399 static bool instances_check();
400
402 // Properties //
404
406 bool is_boolean() const
407 {
408 return is_.boolean;
409 }
410
413 {
414 return is_.sugar_free_boolean;
415 }
416
418 bool is_in_nenoform() const
419 {
420 return is_.in_nenoform;
421 }
422
425 {
426 return is_.syntactic_si;
427 }
428
430 bool is_sugar_free_ltl() const
431 {
432 return is_.sugar_free_ltl;
433 }
434
436 bool is_ltl_formula() const
437 {
438 return is_.ltl_formula;
439 }
440
442 bool is_psl_formula() const
443 {
444 return is_.psl_formula;
445 }
446
448 bool is_sere_formula() const
449 {
450 return is_.sere_formula;
451 }
452
454 bool is_finite() const
455 {
456 return is_.finite;
457 }
458
460 bool is_eventual() const
461 {
462 return is_.eventual;
463 }
464
466 bool is_universal() const
467 {
468 return is_.universal;
469 }
470
473 {
474 return is_.syntactic_safety;
475 }
476
479 {
480 return is_.syntactic_guarantee;
481 }
482
485 {
486 return is_.syntactic_obligation;
487 }
488
491 {
492 return is_.syntactic_recurrence;
493 }
494
497 {
498 return is_.syntactic_persistence;
499 }
500
502 bool is_marked() const
503 {
504 return !is_.not_marked;
505 }
506
508 bool accepts_eword() const
509 {
510 return is_.accepting_eword;
511 }
512
515 {
516 return is_.lbt_atomic_props;
517 }
518
521 {
522 return is_.spin_atomic_props;
523 }
524
526 bool is_sigma2() const
527 {
528 return is_.sigma2;
529 }
530
532 bool is_pi2() const
533 {
534 return is_.pi2;
535 }
536
538 bool is_delta1() const
539 {
540 return is_.delta1;
541 }
542
544 bool is_delta2() const
545 {
546 return is_.delta2;
547 }
548
549 private:
550 static size_t bump_next_id();
551 void setup_props(op o);
552 void destroy_aux() const;
553
554 [[noreturn]] static void report_non_existing_child();
555 [[noreturn]] static void report_too_many_children();
556 [[noreturn]] static void
557 report_get_child_of_expecting_single_child_node();
558 [[noreturn]] static void report_min_invalid_arg();
559 [[noreturn]] static void report_max_invalid_arg();
560
561 static const fnode* unique(fnode*);
562
563 // Destruction may only happen via destroy().
564 ~fnode() = default;
565 // Disallow copies.
566 fnode(const fnode&) = delete;
567 fnode& operator=(const fnode&) = delete;
568
569
570
571 template<class iter>
572 fnode(op o, iter begin, iter end, bool saturated = false)
573 // Clang has some optimization where is it able to combine the
574 // 4 movb initializing op_,min_,max_,saturated_ into a single
575 // movl. Also it can optimize the three byte-comparisons of
576 // is_Kleene_star() into a single masked 32-bit comparison.
577 // The latter optimization triggers warnings from valgrind if
578 // min_ and max_ are not initialized. So to benefit from the
579 // initialization optimization and the is_Kleene_star()
580 // optimization in Clang, we always initialize min_ and max_
581 // with this compiler. Do not do it the rest of the time,
582 // since the optimization is not done.
583 : op_(o),
584#if __llvm__
585 min_(0), max_(0),
586#endif
587 saturated_(saturated)
588 {
589 size_t s = std::distance(begin, end);
590 if (SPOT_UNLIKELY(s > (size_t) UINT16_MAX))
591 report_too_many_children();
592 size_ = s;
593 auto pos = children;
594 for (auto i = begin; i != end; ++i)
595 *pos++ = *i;
596 setup_props(o);
597 }
598
599 fnode(op o, std::initializer_list<const fnode*> l,
600 bool saturated = false)
601 : fnode(o, l.begin(), l.end(), saturated)
602 {
603 }
604
605 fnode(op o, const fnode* f, uint8_t min, uint8_t max,
606 bool saturated = false)
607 : op_(o), min_(min), max_(max), saturated_(saturated), size_(1)
608 {
609 children[0] = f;
610 setup_props(o);
611 }
612
613 static const fnode* ff_;
614 static const fnode* tt_;
615 static const fnode* ew_;
616 static const fnode* one_star_;
617 static const fnode* one_plus_;
618
619 op op_; // operator
620 uint8_t min_; // range minimum (for star-like operators)
621 uint8_t max_; // range maximum;
622 mutable uint8_t saturated_;
623 uint16_t size_; // number of children
624 mutable uint16_t refs_ = 0; // reference count - 1;
625 size_t id_; // Also used as hash.
626 static size_t next_id_;
627
628 struct ltl_prop
629 {
630 // All properties here should be expressed in such a a way
631 // that property(f && g) is just property(f)&property(g).
632 // This allows us to compute all properties of a compound
633 // formula in one operation.
634 //
635 // For instance we do not use a property that says "has
636 // temporal operator", because it would require an OR between
637 // the two arguments. Instead we have a property that
638 // says "no temporal operator", and that one is computed
639 // with an AND between the arguments.
640 //
641 // Also choose a name that makes sense when prefixed with
642 // "the formula is".
643 bool boolean:1; // No temporal operators.
644 bool sugar_free_boolean:1; // Only AND, OR, and NOT operators.
645 bool in_nenoform:1; // Negative Normal Form.
646 bool syntactic_si:1; // LTL-X or siPSL
647 bool sugar_free_ltl:1; // No F and G operators.
648 bool ltl_formula:1; // Only LTL operators.
649 bool psl_formula:1; // Only PSL operators.
650 bool sere_formula:1; // Only SERE operators.
651 bool finite:1; // Finite SERE formulae, or Bool+X forms.
652 bool eventual:1; // Purely eventual formula.
653 bool universal:1; // Purely universal formula.
654 bool syntactic_safety:1; // Syntactic Safety Property (S).
655 bool syntactic_guarantee:1; // Syntactic Guarantee Property (G).
656 bool syntactic_obligation:1; // Syntactic Obligation Property (O).
657 bool syntactic_recurrence:1; // Syntactic Recurrence Property (R).
658 bool syntactic_persistence:1; // Syntactic Persistence Property (P).
659 bool not_marked:1; // No occurrence of EConcatMarked.
660 bool accepting_eword:1; // Accepts the empty word.
661 bool lbt_atomic_props:1; // Use only atomic propositions like p42.
662 bool spin_atomic_props:1; // Use only spin-compatible atomic props.
663 bool delta1:1; // Boolean combination of (S) and (G).
664 bool sigma2:1; // Boolean comb. of (S) with X/F/U/M possibly applied.
665 bool pi2:1; // Boolean comb. of (G) with X/G/R/W possibly applied.
666 bool delta2:1; // Boolean combination of (Σ₂) and (Π₂).
667 };
668 union
669 {
670 // Use an unsigned for fast computation of all properties.
671 unsigned props;
672 ltl_prop is_;
673 };
674
675 const fnode* children[1];
676 };
677
679 SPOT_API
680 int atomic_prop_cmp(const fnode* f, const fnode* g);
681
682 class SPOT_API formula;
683
685 {
686 bool
687 operator()(const fnode* left, const fnode* right) const
688 {
689 SPOT_ASSERT(left);
690 SPOT_ASSERT(right);
691 if (left == right)
692 return false;
693
694 // We want Boolean formulae first.
695 bool lib = left->is_boolean();
696 if (lib != right->is_boolean())
697 return lib;
698
699 // We have two Boolean formulae
700 if (lib)
701 {
702 bool lconst = left->is_constant();
703 if (lconst != right->is_constant())
704 return lconst;
705 if (!lconst)
706 {
707 auto get_literal = [](const fnode* f) -> const fnode*
708 {
709 if (f->is(op::Not))
710 f = f->nth(0);
711 if (f->is(op::ap))
712 return f;
713 return nullptr;
714 };
715 // Literals should come first
716 const fnode* litl = get_literal(left);
717 const fnode* litr = get_literal(right);
718 if (!litl != !litr)
719 return litl;
720 if (litl)
721 {
722 // And they should be sorted alphabetically
723 int cmp = atomic_prop_cmp(litl, litr);
724 if (cmp)
725 return cmp < 0;
726 }
727 }
728 }
729
730 size_t l = left->id();
731 size_t r = right->id();
732 if (l != r)
733 return l < r;
734 // Because the hash code assigned to each formula is the
735 // number of formulae constructed so far, it is very unlikely
736 // that we will ever reach a case were two different formulae
737 // have the same hash. This will happen only ever with have
738 // produced 256**sizeof(size_t) formulae (i.e. max_count has
739 // looped back to 0 and started over). In that case we can
740 // order two formulas by looking at their text representation.
741 // We could be more efficient and look at their AST, but it's
742 // not worth the burden. (Also ordering pointers is ruled out
743 // because it breaks the determinism of the implementation.)
744 std::ostringstream old;
745 left->dump(old);
746 std::ostringstream ord;
747 right->dump(ord);
748 return old.str() < ord.str();
749 }
750
751 SPOT_API bool
752 operator()(const formula& left, const formula& right) const;
753};
754
755#endif // SWIG
756
759 class SPOT_API formula final
760 {
762 const fnode* ptr_;
763 public:
768 explicit formula(const fnode* f) noexcept
769 : ptr_(f)
770 {
771 }
772
778 formula(std::nullptr_t) noexcept
779 : ptr_(nullptr)
780 {
781 }
782
784 formula() noexcept
785 : ptr_(nullptr)
786 {
787 }
788
790 formula(const formula& f) noexcept
791 : ptr_(f.ptr_)
792 {
793 if (ptr_)
794 ptr_->clone();
795 }
796
798 formula(formula&& f) noexcept
799 : ptr_(f.ptr_)
800 {
801 f.ptr_ = nullptr;
802 }
803
806 {
807 if (ptr_)
808 ptr_->destroy();
809 }
810
818 const formula& operator=(std::nullptr_t)
819 {
820 this->~formula();
821 ptr_ = nullptr;
822 return *this;
823 }
824
825 const formula& operator=(const formula& f)
826 {
827 this->~formula();
828 if ((ptr_ = f.ptr_))
829 ptr_->clone();
830 return *this;
831 }
832
833 const formula& operator=(formula&& f) noexcept
834 {
835 std::swap(f.ptr_, ptr_);
836 return *this;
837 }
838
839 bool operator<(const formula& other) const noexcept
840 {
841 if (SPOT_UNLIKELY(!other.ptr_))
842 return false;
843 if (SPOT_UNLIKELY(!ptr_))
844 return true;
845 if (id() < other.id())
846 return true;
847 if (id() > other.id())
848 return false;
849 // The case where id()==other.id() but ptr_ != other.ptr_ is
850 // very unlikely (we would need to build more than UINT_MAX
851 // formulas), so let's just compare pointers, and ignore the
852 // fact that it may introduce some nondeterminism.
853 return ptr_ < other.ptr_;
854 }
855
856 bool operator<=(const formula& other) const noexcept
857 {
858 return *this == other || *this < other;
859 }
860
861 bool operator>(const formula& other) const noexcept
862 {
863 return !(*this <= other);
864 }
865
866 bool operator>=(const formula& other) const noexcept
867 {
868 return !(*this < other);
869 }
870
871 bool operator==(const formula& other) const noexcept
872 {
873 return other.ptr_ == ptr_;
874 }
875
876 bool operator==(std::nullptr_t) const noexcept
877 {
878 return ptr_ == nullptr;
879 }
880
881 bool operator!=(const formula& other) const noexcept
882 {
883 return other.ptr_ != ptr_;
884 }
885
886 bool operator!=(std::nullptr_t) const noexcept
887 {
888 return ptr_ != nullptr;
889 }
890
891 explicit operator bool() const noexcept
892 {
893 return ptr_ != nullptr;
894 }
895
897 // Forwarded functions //
899
901 static constexpr uint8_t unbounded()
902 {
903 return fnode::unbounded();
904 }
905
907 static formula ap(const std::string& name)
908 {
909 return formula(fnode::ap(name));
910 }
911
917 static formula ap(const formula& a)
918 {
919 if (SPOT_UNLIKELY(a.kind() != op::ap))
920 report_ap_invalid_arg();
921 return a;
922 }
923
928 static formula unop(op o, const formula& f)
929 {
930 return formula(fnode::unop(o, f.ptr_->clone()));
931 }
932
933#ifndef SWIG
934 static formula unop(op o, formula&& f)
935 {
936 return formula(fnode::unop(o, f.to_node_()));
937 }
938#endif // !SWIG
940
941#ifdef SWIG
942#define SPOT_DEF_UNOP(Name) \
943 static formula Name(const formula& f) \
944 { \
945 return unop(op::Name, f); \
946 }
947#else // !SWIG
948#define SPOT_DEF_UNOP(Name) \
949 static formula Name(const formula& f) \
950 { \
951 return unop(op::Name, f); \
952 } \
953 static formula Name(formula&& f) \
954 { \
955 return unop(op::Name, std::move(f)); \
956 }
957#endif // !SWIG
960 SPOT_DEF_UNOP(Not);
962
965 SPOT_DEF_UNOP(X);
967
971 static formula X(unsigned level, const formula& f)
972 {
973 return nested_unop_range(op::X, op::Or /* unused */, level, level, f);
974 }
975
976#if SPOT_WANT_STRONG_X
979 SPOT_DEF_UNOP(strong_X);
981
985 static formula strong_X(unsigned level, const formula& f)
986 {
987 return nested_unop_range(op::strong_X, op::Or /* unused */,
988 level, level, f);
989 }
990#endif
991
994 SPOT_DEF_UNOP(F);
996
1003 static formula F(unsigned min_level, unsigned max_level, const formula& f)
1004 {
1005 return nested_unop_range(op::X, op::Or, min_level, max_level, f);
1006 }
1007
1014 static formula G(unsigned min_level, unsigned max_level, const formula& f)
1015 {
1016 return nested_unop_range(op::X, op::And, min_level, max_level, f);
1017 }
1018
1021 SPOT_DEF_UNOP(G);
1023
1026 SPOT_DEF_UNOP(Closure);
1028
1031 SPOT_DEF_UNOP(NegClosure);
1033
1036 SPOT_DEF_UNOP(NegClosureMarked);
1038
1041 SPOT_DEF_UNOP(first_match);
1043#undef SPOT_DEF_UNOP
1044
1050 static formula binop(op o, const formula& f, const formula& g)
1051 {
1052 return formula(fnode::binop(o, f.ptr_->clone(), g.ptr_->clone()));
1053 }
1054
1055#ifndef SWIG
1056 static formula binop(op o, const formula& f, formula&& g)
1057 {
1058 return formula(fnode::binop(o, f.ptr_->clone(), g.to_node_()));
1059 }
1060
1061 static formula binop(op o, formula&& f, const formula& g)
1062 {
1063 return formula(fnode::binop(o, f.to_node_(), g.ptr_->clone()));
1064 }
1065
1066 static formula binop(op o, formula&& f, formula&& g)
1067 {
1068 return formula(fnode::binop(o, f.to_node_(), g.to_node_()));
1069 }
1071
1072#endif //SWIG
1073
1074#ifdef SWIG
1075#define SPOT_DEF_BINOP(Name) \
1076 static formula Name(const formula& f, const formula& g) \
1077 { \
1078 return binop(op::Name, f, g); \
1079 }
1080#else // !SWIG
1081#define SPOT_DEF_BINOP(Name) \
1082 static formula Name(const formula& f, const formula& g) \
1083 { \
1084 return binop(op::Name, f, g); \
1085 } \
1086 static formula Name(const formula& f, formula&& g) \
1087 { \
1088 return binop(op::Name, f, std::move(g)); \
1089 } \
1090 static formula Name(formula&& f, const formula& g) \
1091 { \
1092 return binop(op::Name, std::move(f), g); \
1093 } \
1094 static formula Name(formula&& f, formula&& g) \
1095 { \
1096 return binop(op::Name, std::move(f), std::move(g)); \
1097 }
1098#endif // !SWIG
1101 SPOT_DEF_BINOP(Xor);
1103
1106 SPOT_DEF_BINOP(Implies);
1108
1111 SPOT_DEF_BINOP(Equiv);
1113
1116 SPOT_DEF_BINOP(U);
1118
1121 SPOT_DEF_BINOP(R);
1123
1126 SPOT_DEF_BINOP(W);
1128
1131 SPOT_DEF_BINOP(M);
1133
1136 SPOT_DEF_BINOP(EConcat);
1138
1141 SPOT_DEF_BINOP(EConcatMarked);
1143
1146 SPOT_DEF_BINOP(UConcat);
1148#undef SPOT_DEF_BINOP
1149
1155 static formula multop(op o, const std::vector<formula>& l)
1156 {
1157 std::vector<const fnode*> tmp;
1158 tmp.reserve(l.size());
1159 for (auto f: l)
1160 if (f.ptr_)
1161 tmp.emplace_back(f.ptr_->clone());
1162 return formula(fnode::multop(o, std::move(tmp)));
1163 }
1164
1165#ifndef SWIG
1166 static formula multop(op o, std::vector<formula>&& l)
1167 {
1168 std::vector<const fnode*> tmp;
1169 tmp.reserve(l.size());
1170 for (auto f: l)
1171 if (f.ptr_)
1172 tmp.emplace_back(f.to_node_());
1173 return formula(fnode::multop(o, std::move(tmp)));
1174 }
1175#endif // !SWIG
1177
1178#ifdef SWIG
1179#define SPOT_DEF_MULTOP(Name) \
1180 static formula Name(const std::vector<formula>& l) \
1181 { \
1182 return multop(op::Name, l); \
1183 }
1184#else // !SWIG
1185#define SPOT_DEF_MULTOP(Name) \
1186 static formula Name(const std::vector<formula>& l) \
1187 { \
1188 return multop(op::Name, l); \
1189 } \
1190 \
1191 static formula Name(std::vector<formula>&& l) \
1192 { \
1193 return multop(op::Name, std::move(l)); \
1194 }
1195#endif // !SWIG
1198 SPOT_DEF_MULTOP(Or);
1200
1203 SPOT_DEF_MULTOP(OrRat);
1205
1208 SPOT_DEF_MULTOP(And);
1210
1213 SPOT_DEF_MULTOP(AndRat);
1215
1218 SPOT_DEF_MULTOP(AndNLM);
1220
1223 SPOT_DEF_MULTOP(Concat);
1225
1228 SPOT_DEF_MULTOP(Fusion);
1230#undef SPOT_DEF_MULTOP
1231
1236 static formula bunop(op o, const formula& f,
1237 unsigned min = 0U,
1238 unsigned max = unbounded())
1239 {
1240 return formula(fnode::bunop(o, f.ptr_->clone(), min, max));
1241 }
1242
1243#ifndef SWIG
1244 static formula bunop(op o, formula&& f,
1245 unsigned min = 0U,
1246 unsigned max = unbounded())
1247 {
1248 return formula(fnode::bunop(o, f.to_node_(), min, max));
1249 }
1250#endif // !SWIG
1252
1253#if SWIG
1254#define SPOT_DEF_BUNOP(Name) \
1255 static formula Name(const formula& f, \
1256 unsigned min = 0U, \
1257 unsigned max = unbounded()) \
1258 { \
1259 return bunop(op::Name, f, min, max); \
1260 }
1261#else // !SWIG
1262#define SPOT_DEF_BUNOP(Name) \
1263 static formula Name(const formula& f, \
1264 unsigned min = 0U, \
1265 unsigned max = unbounded()) \
1266 { \
1267 return bunop(op::Name, f, min, max); \
1268 } \
1269 static formula Name(formula&& f, \
1270 unsigned min = 0U, \
1271 unsigned max = unbounded()) \
1272 { \
1273 return bunop(op::Name, std::move(f), min, max); \
1274 }
1275#endif
1278 SPOT_DEF_BUNOP(Star);
1280
1286 SPOT_DEF_BUNOP(FStar);
1288#undef SPOT_DEF_BUNOP
1289
1301 static const formula nested_unop_range(op uo, op bo, unsigned min,
1302 unsigned max, formula f)
1303 {
1304 return formula(fnode::nested_unop_range(uo, bo, min, max,
1305 f.ptr_->clone()));
1306 }
1307
1313 static formula sugar_goto(const formula& b, unsigned min, unsigned max);
1314
1320 static formula sugar_equal(const formula& b, unsigned min, unsigned max);
1321
1343 static formula sugar_delay(const formula& a, const formula& b,
1344 unsigned min, unsigned max);
1345 static formula sugar_delay(const formula& b,
1346 unsigned min, unsigned max);
1348
1349#ifndef SWIG
1360 {
1361 auto tmp = ptr_;
1362 ptr_ = nullptr;
1363 return tmp;
1364 }
1365#endif
1366
1368 op kind() const
1369 {
1370 return ptr_->kind();
1371 }
1372
1374 std::string kindstr() const
1375 {
1376 return ptr_->kindstr();
1377 }
1378
1380 bool is(op o) const
1381 {
1382 return ptr_->is(o);
1383 }
1384
1385#ifndef SWIG
1387 bool is(op o1, op o2) const
1388 {
1389 return ptr_->is(o1, o2);
1390 }
1391
1393 bool is(op o1, op o2, op o3) const
1394 {
1395 return ptr_->is(o1, o2, o3);
1396 }
1397
1400 bool is(op o1, op o2, op o3, op o4) const
1401 {
1402 return ptr_->is(o1, o2, o3, o4);
1403 }
1404
1406 bool is(std::initializer_list<op> l) const
1407 {
1408 return ptr_->is(l);
1409 }
1410#endif
1411
1416 {
1417 auto f = ptr_->get_child_of(o);
1418 if (f)
1419 f->clone();
1420 return formula(f);
1421 }
1422
1423#ifndef SWIG
1430 formula get_child_of(std::initializer_list<op> l) const
1431 {
1432 auto f = ptr_->get_child_of(l);
1433 if (f)
1434 f->clone();
1435 return formula(f);
1436 }
1437#endif
1438
1442 unsigned min() const
1443 {
1444 return ptr_->min();
1445 }
1446
1450 unsigned max() const
1451 {
1452 return ptr_->max();
1453 }
1454
1456 unsigned size() const
1457 {
1458 return ptr_->size();
1459 }
1460
1465 bool is_leaf() const
1466 {
1467 return ptr_->is_leaf();
1468 }
1469
1478 size_t id() const
1479 {
1480 return ptr_->id();
1481 }
1482
1483#ifndef SWIG
1485 class SPOT_API formula_child_iterator final
1486 {
1487 const fnode*const* ptr_;
1488 public:
1490 : ptr_(nullptr)
1491 {
1492 }
1493
1494 formula_child_iterator(const fnode*const* f)
1495 : ptr_(f)
1496 {
1497 }
1498
1499 bool operator==(formula_child_iterator o)
1500 {
1501 return ptr_ == o.ptr_;
1502 }
1503
1504 bool operator!=(formula_child_iterator o)
1505 {
1506 return ptr_ != o.ptr_;
1507 }
1508
1509 formula operator*()
1510 {
1511 return formula((*ptr_)->clone());
1512 }
1513
1514 formula_child_iterator operator++()
1515 {
1516 ++ptr_;
1517 return *this;
1518 }
1519
1520 formula_child_iterator operator++(int)
1521 {
1522 auto tmp = *this;
1523 ++ptr_;
1524 return tmp;
1525 }
1526 };
1527
1530 {
1531 return ptr_->begin();
1532 }
1533
1536 {
1537 return ptr_->end();
1538 }
1539
1541 formula operator[](unsigned i) const
1542 {
1543 return formula(ptr_->nth(i)->clone());
1544 }
1545#endif
1546
1548 static formula ff()
1549 {
1550 return formula(fnode::ff());
1551 }
1552
1554 bool is_ff() const
1555 {
1556 return ptr_->is_ff();
1557 }
1558
1560 static formula tt()
1561 {
1562 return formula(fnode::tt());
1563 }
1564
1566 bool is_tt() const
1567 {
1568 return ptr_->is_tt();
1569 }
1570
1573 {
1574 return formula(fnode::eword());
1575 }
1576
1578 bool is_eword() const
1579 {
1580 return ptr_->is_eword();
1581 }
1582
1584 bool is_constant() const
1585 {
1586 return ptr_->is_constant();
1587 }
1588
1593 bool is_Kleene_star() const
1594 {
1595 return ptr_->is_Kleene_star();
1596 }
1597
1600 {
1601 // no need to clone, 1[*] is not reference counted
1602 return formula(fnode::one_star());
1603 }
1604
1607 {
1608 // no need to clone, 1[+] is not reference counted
1609 return formula(fnode::one_plus());
1610 }
1611
1614 bool is_literal() const
1615 {
1616 return (is(op::ap) ||
1617 // If f is in nenoform, Not can only occur in front of
1618 // an atomic proposition. So this way we do not have
1619 // to check the type of the child.
1620 (is(op::Not) && is_boolean() && is_in_nenoform()));
1621 }
1622
1626 const std::string& ap_name() const
1627 {
1628 return ptr_->ap_name();
1629 }
1630
1635 std::ostream& dump(std::ostream& os) const
1636 {
1637 return ptr_->dump(os);
1638 }
1639
1645 formula all_but(unsigned i) const
1646 {
1647 return formula(ptr_->all_but(i));
1648 }
1649
1659 unsigned boolean_count() const
1660 {
1661 return ptr_->boolean_count();
1662 }
1663
1677 formula boolean_operands(unsigned* width = nullptr) const
1678 {
1679 return formula(ptr_->boolean_operands(width));
1680 }
1681
1682#define SPOT_DEF_PROP(Name) \
1683 bool Name() const \
1684 { \
1685 return ptr_->Name(); \
1686 }
1688 // Properties //
1690
1692 SPOT_DEF_PROP(is_boolean);
1694 SPOT_DEF_PROP(is_sugar_free_boolean);
1699 SPOT_DEF_PROP(is_in_nenoform);
1701 SPOT_DEF_PROP(is_syntactic_stutter_invariant);
1703 SPOT_DEF_PROP(is_sugar_free_ltl);
1705 SPOT_DEF_PROP(is_ltl_formula);
1707 SPOT_DEF_PROP(is_psl_formula);
1709 SPOT_DEF_PROP(is_sere_formula);
1712 SPOT_DEF_PROP(is_finite);
1720 SPOT_DEF_PROP(is_eventual);
1728 SPOT_DEF_PROP(is_universal);
1732 SPOT_DEF_PROP(is_syntactic_safety);
1736 SPOT_DEF_PROP(is_syntactic_guarantee);
1741 SPOT_DEF_PROP(is_delta1);
1746 SPOT_DEF_PROP(is_syntactic_obligation);
1748 SPOT_DEF_PROP(is_sigma2);
1750 SPOT_DEF_PROP(is_pi2);
1755 SPOT_DEF_PROP(is_syntactic_recurrence);
1760 SPOT_DEF_PROP(is_syntactic_persistence);
1765 SPOT_DEF_PROP(is_delta2);
1768 SPOT_DEF_PROP(is_marked);
1770 SPOT_DEF_PROP(accepts_eword);
1776 SPOT_DEF_PROP(has_lbt_atomic_props);
1785 SPOT_DEF_PROP(has_spin_atomic_props);
1786#undef SPOT_DEF_PROP
1787
1791 template<typename Trans, typename... Args>
1792 formula map(Trans trans, Args&&... args)
1793 {
1794 switch (op o = kind())
1795 {
1796 case op::ff:
1797 case op::tt:
1798 case op::eword:
1799 case op::ap:
1800 return *this;
1801 case op::Not:
1802 case op::X:
1803#if SPOT_HAS_STRONG_X
1804 case op::strong_X:
1805#endif
1806 case op::F:
1807 case op::G:
1808 case op::Closure:
1809 case op::NegClosure:
1811 case op::first_match:
1812 return unop(o, trans((*this)[0], std::forward<Args>(args)...));
1813 case op::Xor:
1814 case op::Implies:
1815 case op::Equiv:
1816 case op::U:
1817 case op::R:
1818 case op::W:
1819 case op::M:
1820 case op::EConcat:
1821 case op::EConcatMarked:
1822 case op::UConcat:
1823 {
1824 formula tmp = trans((*this)[0], std::forward<Args>(args)...);
1825 return binop(o, tmp,
1826 trans((*this)[1], std::forward<Args>(args)...));
1827 }
1828 case op::Or:
1829 case op::OrRat:
1830 case op::And:
1831 case op::AndRat:
1832 case op::AndNLM:
1833 case op::Concat:
1834 case op::Fusion:
1835 {
1836 std::vector<formula> tmp;
1837 tmp.reserve(size());
1838 for (auto f: *this)
1839 tmp.emplace_back(trans(f, std::forward<Args>(args)...));
1840 return multop(o, std::move(tmp));
1841 }
1842 case op::Star:
1843 case op::FStar:
1844 return bunop(o, trans((*this)[0], std::forward<Args>(args)...),
1845 min(), max());
1846 }
1847 SPOT_UNREACHABLE();
1848 }
1849
1858 template<typename Func, typename... Args>
1859 void traverse(Func func, Args&&... args)
1860 {
1861 if (func(*this, std::forward<Args>(args)...))
1862 return;
1863 for (auto f: *this)
1864 f.traverse(func, std::forward<Args>(args)...);
1865 }
1866
1867 private:
1868#ifndef SWIG
1869 [[noreturn]] static void report_ap_invalid_arg();
1870#endif
1871 };
1872
1874 SPOT_API
1875 std::ostream& print_formula_props(std::ostream& out, const formula& f,
1876 bool abbreviated = false);
1877
1879 SPOT_API
1880 std::list<std::string> list_formula_props(const formula& f);
1881
1883 SPOT_API
1884 std::ostream& operator<<(std::ostream& os, const formula& f);
1885}
1886
1887#ifndef SWIG
1888namespace std
1889{
1890 template <>
1891 struct hash<spot::formula>
1892 {
1893 size_t operator()(const spot::formula& x) const noexcept
1894 {
1895 return x.id();
1896 }
1897 };
1898}
1899#endif
Actual storage for formula nodes.
Definition: formula.hh:127
bool is_pi2() const
Definition: formula.hh:532
std::string kindstr() const
const fnode * boolean_operands(unsigned *width=nullptr) const
bool is_boolean() const
Definition: formula.hh:406
size_t id() const
Definition: formula.hh:274
bool is_ff() const
Definition: formula.hh:308
bool is_sugar_free_boolean() const
Definition: formula.hh:412
bool is_Kleene_star() const
Definition: formula.hh:344
static const fnode * nested_unop_range(op uo, op bo, unsigned min, unsigned max, const fnode *f)
const fnode *const * end() const
Definition: formula.hh:286
unsigned min() const
Definition: formula.hh:246
bool is_syntactic_safety() const
Definition: formula.hh:472
bool is_syntactic_stutter_invariant() const
Definition: formula.hh:424
static const fnode * binop(op o, const fnode *f, const fnode *g)
bool is_delta2() const
Definition: formula.hh:544
unsigned size() const
Definition: formula.hh:262
static constexpr uint8_t unbounded()
Definition: formula.hh:157
const fnode * get_child_of(std::initializer_list< op > l) const
Definition: formula.hh:233
unsigned max() const
Definition: formula.hh:254
const fnode * get_child_of(op o) const
Definition: formula.hh:223
const fnode * all_but(unsigned i) const
bool accepts_eword() const
Definition: formula.hh:508
bool is_eventual() const
Definition: formula.hh:460
bool is(op o1, op o2, op o3, op o4) const
Definition: formula.hh:204
static bool instances_check()
safety check for the reference counters
bool is_leaf() const
Definition: formula.hh:268
bool has_spin_atomic_props() const
Definition: formula.hh:520
bool is_eword() const
Definition: formula.hh:332
bool is(op o1, op o2, op o3) const
Definition: formula.hh:199
op kind() const
Definition: formula.hh:179
const fnode * clone() const
Clone an fnode.
Definition: formula.hh:133
bool has_lbt_atomic_props() const
Definition: formula.hh:514
bool is_sugar_free_ltl() const
Definition: formula.hh:430
const std::string & ap_name() const
bool is_syntactic_persistence() const
Definition: formula.hh:496
unsigned boolean_count() const
Definition: formula.hh:377
static const fnode * tt()
Definition: formula.hh:314
bool is_universal() const
Definition: formula.hh:466
bool is_tt() const
Definition: formula.hh:320
bool is_constant() const
Definition: formula.hh:338
bool is_syntactic_recurrence() const
Definition: formula.hh:490
bool is(std::initializer_list< op > l) const
Definition: formula.hh:209
bool is_syntactic_obligation() const
Definition: formula.hh:484
static const fnode * unop(op o, const fnode *f)
const fnode * nth(unsigned i) const
Definition: formula.hh:292
bool is_ltl_formula() const
Definition: formula.hh:436
static const fnode * ff()
Definition: formula.hh:302
bool is_finite() const
Definition: formula.hh:454
bool is_sigma2() const
Definition: formula.hh:526
bool is_psl_formula() const
Definition: formula.hh:442
bool is_delta1() const
Definition: formula.hh:538
static const fnode * eword()
Definition: formula.hh:326
bool is_marked() const
Definition: formula.hh:502
std::ostream & dump(std::ostream &os) const
void destroy() const
Dereference an fnode.
Definition: formula.hh:147
static const fnode * one_plus()
Definition: formula.hh:360
static const fnode * ap(const std::string &name)
bool is(op o1, op o2) const
Definition: formula.hh:194
bool is_in_nenoform() const
Definition: formula.hh:418
static const fnode * bunop(op o, const fnode *f, unsigned min, unsigned max=unbounded())
bool is_syntactic_guarantee() const
Definition: formula.hh:478
static const fnode * multop(op o, std::vector< const fnode * > l)
bool is_sere_formula() const
Definition: formula.hh:448
static const fnode * one_star()
Definition: formula.hh:352
const fnode *const * begin() const
Definition: formula.hh:280
bool is(op o) const
Definition: formula.hh:189
Allow iterating over children.
Definition: formula.hh:1486
Main class for temporal logic formula.
Definition: formula.hh:760
std::ostream & dump(std::ostream &os) const
Print the formula for debugging.
Definition: formula.hh:1635
unsigned boolean_count() const
number of Boolean children
Definition: formula.hh:1659
bool is_leaf() const
Whether the formula is a leaf.
Definition: formula.hh:1465
size_t id() const
Return the id of a formula.
Definition: formula.hh:1478
static formula bunop(op o, formula &&f, unsigned min=0U, unsigned max=unbounded())
Define a bounded unary-operator (i.e. star-like)
Definition: formula.hh:1244
formula map(Trans trans, Args &&... args)
Clone this node after applying trans to its children.
Definition: formula.hh:1792
static formula bunop(op o, const formula &f, unsigned min=0U, unsigned max=unbounded())
Define a bounded unary-operator (i.e. star-like)
Definition: formula.hh:1236
static formula G(unsigned min_level, unsigned max_level, const formula &f)
Construct G[n:m].
Definition: formula.hh:1014
static formula binop(op o, const formula &f, const formula &g)
Construct a binary operator.
Definition: formula.hh:1050
bool is(op o) const
Return true if the formula is of kind o.
Definition: formula.hh:1380
static formula multop(op o, std::vector< formula > &&l)
Construct an n-ary operator.
Definition: formula.hh:1166
formula(formula &&f) noexcept
Move-construct a formula.
Definition: formula.hh:798
formula(const fnode *f) noexcept
Create a formula from an fnode.
Definition: formula.hh:768
bool is(op o1, op o2) const
Return true if the formula is of kind o1 or o2.
Definition: formula.hh:1387
static formula one_plus()
Return a copy of the formula 1[+].
Definition: formula.hh:1606
static formula sugar_delay(const formula &b, unsigned min, unsigned max)
Create the SERE a ##[n:m] b
static formula one_star()
Return a copy of the formula 1[*].
Definition: formula.hh:1599
unsigned min() const
Return start of the range for star-like operators.
Definition: formula.hh:1442
static constexpr uint8_t unbounded()
Unbounded constant to use as end of range for bounded operators.
Definition: formula.hh:901
static formula unop(op o, formula &&f)
Build a unary operator.
Definition: formula.hh:934
static formula eword()
Return the empty word constant.
Definition: formula.hh:1572
formula all_but(unsigned i) const
clone this formula, omitting child i
Definition: formula.hh:1645
static formula ff()
Return the false constant.
Definition: formula.hh:1548
static formula binop(op o, const formula &f, formula &&g)
Construct a binary operator.
Definition: formula.hh:1056
const formula & operator=(std::nullptr_t)
Reset a formula to null.
Definition: formula.hh:818
op kind() const
Return top-most operator.
Definition: formula.hh:1368
const std::string & ap_name() const
Print the name of an atomic proposition.
Definition: formula.hh:1626
static formula multop(op o, const std::vector< formula > &l)
Construct an n-ary operator.
Definition: formula.hh:1155
unsigned size() const
Return the number of children.
Definition: formula.hh:1456
static formula sugar_goto(const formula &b, unsigned min, unsigned max)
Create a SERE equivalent to b[->min..max]
bool is_tt() const
Whether the formula is the true constant.
Definition: formula.hh:1566
bool is(op o1, op o2, op o3, op o4) const
Definition: formula.hh:1400
std::string kindstr() const
Return the name of the top-most operator.
Definition: formula.hh:1374
formula(const formula &f) noexcept
Clone a formula.
Definition: formula.hh:790
formula_child_iterator end() const
Allow iterating over children.
Definition: formula.hh:1535
const fnode * to_node_()
Return the underlying pointer to the formula.
Definition: formula.hh:1359
static formula binop(op o, formula &&f, formula &&g)
Construct a binary operator.
Definition: formula.hh:1066
static formula ap(const formula &a)
Build an atomic proposition from... an atomic proposition.
Definition: formula.hh:917
formula get_child_of(std::initializer_list< op > l) const
Remove all operators in l and return the child.
Definition: formula.hh:1430
bool is_eword() const
Whether the formula is the empty word constant.
Definition: formula.hh:1578
static formula sugar_delay(const formula &a, const formula &b, unsigned min, unsigned max)
Create the SERE a ##[n:m] b
void traverse(Func func, Args &&... args)
Apply func to each subformula.
Definition: formula.hh:1859
static formula F(unsigned min_level, unsigned max_level, const formula &f)
Construct F[n:m].
Definition: formula.hh:1003
formula(std::nullptr_t) noexcept
Create a null formula.
Definition: formula.hh:778
static formula ap(const std::string &name)
Build an atomic proposition.
Definition: formula.hh:907
bool is(op o1, op o2, op o3) const
Return true if the formula is of kind o1 or o2 or o3.
Definition: formula.hh:1393
unsigned max() const
Return end of the range for star-like operators.
Definition: formula.hh:1450
static formula X(unsigned level, const formula &f)
Construct an X[n].
Definition: formula.hh:971
bool is_ff() const
Whether the formula is the false constant.
Definition: formula.hh:1554
formula_child_iterator begin() const
Allow iterating over children.
Definition: formula.hh:1529
bool is_constant() const
Whether the formula is op::ff, op::tt, or op::eword.
Definition: formula.hh:1584
~formula()
Destroy a formula.
Definition: formula.hh:805
formula get_child_of(op o) const
Remove operator o and return the child.
Definition: formula.hh:1415
bool is(std::initializer_list< op > l) const
Return true if the formulas nests all the operators in l.
Definition: formula.hh:1406
formula operator[](unsigned i) const
Return children number i.
Definition: formula.hh:1541
bool is_Kleene_star() const
Test whether the formula represent a Kleene star.
Definition: formula.hh:1593
static formula binop(op o, formula &&f, const formula &g)
Construct a binary operator.
Definition: formula.hh:1061
bool is_literal() const
Whether the formula is an atomic proposition or its negation.
Definition: formula.hh:1614
static formula tt()
Return the true constant.
Definition: formula.hh:1560
formula() noexcept
Default initialize a formula to nullptr.
Definition: formula.hh:784
static formula sugar_equal(const formula &b, unsigned min, unsigned max)
Create the SERE b[=min..max]
static formula unop(op o, const formula &f)
Build a unary operator.
Definition: formula.hh:928
formula boolean_operands(unsigned *width=nullptr) const
return a clone of the current node, restricted to its Boolean children
Definition: formula.hh:1677
static const formula nested_unop_range(op uo, op bo, unsigned min, unsigned max, formula f)
Nested operator construction (syntactic sugar).
Definition: formula.hh:1301
op
Operator types.
Definition: formula.hh:78
@ X
Next.
@ first_match
first_match(sere)
@ EConcatMarked
Seq, Marked.
@ Star
Star.
@ UConcat
Triggers.
@ Or
(omega-Rational) Or
@ Equiv
Equivalence.
@ NegClosure
Negated PSL Closure.
@ U
until
@ EConcat
Seq.
@ FStar
Fustion Star.
@ W
weak until
@ ap
Atomic proposition.
@ ff
False.
@ M
strong release (dual of weak until)
@ NegClosureMarked
marked version of the Negated PSL Closure
@ Xor
Exclusive Or.
@ F
Eventually.
@ OrRat
Rational Or.
@ Not
Negation.
@ tt
True.
@ Fusion
Fusion.
@ Closure
PSL Closure.
@ And
(omega-Rational) And
@ AndNLM
Non-Length-Matching Rational-And.
@ eword
Empty word.
@ AndRat
Rational And.
@ G
Globally.
@ R
release (dual of until)
@ Concat
Concatenation.
@ Implies
Implication.
bool is_universal(const const_twa_graph_ptr &aut)
Return true iff aut is universal.
Definition: automata.hh:26
int atomic_prop_cmp(const fnode *f, const fnode *g)
Order two atomic propositions.
std::list< std::string > list_formula_props(const formula &f)
List the properties of formula f.
std::ostream & print_formula_props(std::ostream &out, const formula &f, bool abbreviated=false)
Print the properties of formula f on stream out.
Definition: formula.hh:685

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Fri Feb 27 2015 10:00:07 for spot by doxygen 1.9.4