spot  2.11.6
formula.hh
Go to the documentation of this file.
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2015-2022 Laboratoire de Recherche et Développement
3 // de l'Epita (LRDE).
4 //
5 // This file is part of Spot, a model checking library.
6 //
7 // Spot is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // Spot is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 
22 #pragma once
23 
30 
33 
36 
39 
42 
45 
46 #include <spot/misc/common.hh>
47 #include <memory>
48 #include <cstdint>
49 #include <initializer_list>
50 #include <cassert>
51 #include <vector>
52 #include <string>
53 #include <iterator>
54 #include <iosfwd>
55 #include <sstream>
56 #include <list>
57 #include <cstddef>
58 #include <limits>
59 
60 // The strong_X operator was introduced in Spot 2.8.2 to fix an issue
61 // with from_ltlf(). As adding a new operator is a backward
62 // incompatibility, causing new warnings from the compiler.
63 #if defined(SPOT_BUILD) or defined(SPOT_USES_STRONG_X)
64 // Use #if SPOT_HAS_STRONG_X in code that need to be backward
65 // compatible with older Spot versions.
66 # define SPOT_HAS_STRONG_X 1
67 // You me #define SPOT_WANT_STRONG_X yourself before including
68 // this file to force the use of STRONG_X
69 # define SPOT_WANT_STRONG_X 1
70 #endif
71 
72 namespace spot
73 {
74 
75 
78  enum class op: uint8_t
79  {
80  ff,
81  tt,
82  eword,
83  ap,
84  // unary operators
85  Not,
86  X,
87  F,
88  G,
89  Closure,
90  NegClosure,
92  // binary operators
93  Xor,
94  Implies,
95  Equiv,
96  U,
97  R,
98  W,
99  M,
100  EConcat,
101  EConcatMarked,
102  UConcat,
103  // n-ary operators
104  Or,
105  OrRat,
106  And,
107  AndRat,
108  AndNLM,
109  Concat,
110  Fusion,
111  // star-like operators
112  Star,
113  FStar,
114  first_match,
115 #ifdef SPOT_WANT_STRONG_X
116  strong_X,
117 #endif
118  };
119 
120 #ifndef SWIG
127  class SPOT_API fnode final
128  {
129  public:
134  const fnode* clone() const
135  {
136  // Saturate.
137  ++refs_;
138  if (SPOT_UNLIKELY(!refs_))
139  saturated_ = 1;
140  return this;
141  }
142 
148  void destroy() const
149  {
150  if (SPOT_LIKELY(refs_))
151  --refs_;
152  else if (SPOT_LIKELY(id_ > 2) && SPOT_LIKELY(!saturated_))
153  // last reference to a node that is not a constant
154  destroy_aux();
155  }
156 
158  static constexpr uint8_t unbounded()
159  {
160  return UINT8_MAX;
161  }
162 
164  static const fnode* ap(const std::string& name);
166  static const fnode* unop(op o, const fnode* f);
168  static const fnode* binop(op o, const fnode* f, const fnode* g);
170  static const fnode* multop(op o, std::vector<const fnode*> l);
172  static const fnode* bunop(op o, const fnode* f,
173  unsigned min, unsigned max = unbounded());
174 
176  static const fnode* nested_unop_range(op uo, op bo, unsigned min,
177  unsigned max, const fnode* f);
178 
180  op kind() const
181  {
182  return op_;
183  }
184 
186  std::string kindstr() const;
187 
190  bool is(op o) const
191  {
192  return op_ == o;
193  }
194 
195  bool is(op o1, op o2) const
196  {
197  return op_ == o1 || op_ == o2;
198  }
199 
200  bool is(op o1, op o2, op o3) const
201  {
202  return op_ == o1 || op_ == o2 || op_ == o3;
203  }
204 
205  bool is(op o1, op o2, op o3, op o4) const
206  {
207  return op_ == o1 || op_ == o2 || op_ == o3 || op_ == o4;
208  }
209 
210  bool is(std::initializer_list<op> l) const
211  {
212  const fnode* n = this;
213  for (auto o: l)
214  {
215  if (!n->is(o))
216  return false;
217  n = n->nth(0);
218  }
219  return true;
220  }
222 
224  const fnode* get_child_of(op o) const
225  {
226  if (op_ != o)
227  return nullptr;
228  if (SPOT_UNLIKELY(size_ != 1))
229  report_get_child_of_expecting_single_child_node();
230  return nth(0);
231  }
232 
234  const fnode* get_child_of(std::initializer_list<op> l) const
235  {
236  auto c = this;
237  for (auto o: l)
238  {
239  c = c->get_child_of(o);
240  if (c == nullptr)
241  return c;
242  }
243  return c;
244  }
245 
247  unsigned min() const
248  {
249  if (SPOT_UNLIKELY(op_ != op::FStar && op_ != op::Star))
250  report_min_invalid_arg();
251  return min_;
252  }
253 
255  unsigned max() const
256  {
257  if (SPOT_UNLIKELY(op_ != op::FStar && op_ != op::Star))
258  report_max_invalid_arg();
259  return max_;
260  }
261 
263  unsigned size() const
264  {
265  return size_;
266  }
267 
269  bool is_leaf() const
270  {
271  return size_ == 0;
272  }
273 
275  size_t id() const
276  {
277  return id_;
278  }
279 
281  const fnode*const* begin() const
282  {
283  return children;
284  }
285 
287  const fnode*const* end() const
288  {
289  return children + size();
290  }
291 
293  const fnode* nth(unsigned i) const
294  {
295  if (SPOT_UNLIKELY(i >= size()))
296  report_non_existing_child();
297  const fnode* c = children[i];
298  SPOT_ASSUME(c != nullptr);
299  return c;
300  }
301 
303  static const fnode* ff()
304  {
305  return ff_;
306  }
307 
309  bool is_ff() const
310  {
311  return op_ == op::ff;
312  }
313 
315  static const fnode* tt()
316  {
317  return tt_;
318  }
319 
321  bool is_tt() const
322  {
323  return op_ == op::tt;
324  }
325 
327  static const fnode* eword()
328  {
329  return ew_;
330  }
331 
333  bool is_eword() const
334  {
335  return op_ == op::eword;
336  }
337 
339  bool is_constant() const
340  {
341  return op_ == op::ff || op_ == op::tt || op_ == op::eword;
342  }
343 
345  bool is_Kleene_star() const
346  {
347  if (op_ != op::Star)
348  return false;
349  return min_ == 0 && max_ == unbounded();
350  }
351 
353  static const fnode* one_star()
354  {
355  if (!one_star_)
356  one_star_ = bunop(op::Star, tt(), 0);
357  return one_star_;
358  }
359 
361  const std::string& ap_name() const;
362 
364  std::ostream& dump(std::ostream& os) const;
365 
367  const fnode* all_but(unsigned i) const;
368 
370  unsigned boolean_count() const
371  {
372  unsigned pos = 0;
373  unsigned s = size();
374  while (pos < s && children[pos]->is_boolean())
375  ++pos;
376  return pos;
377  }
378 
380  const fnode* boolean_operands(unsigned* width = nullptr) const;
381 
392  static bool instances_check();
393 
395  // Properties //
397 
399  bool is_boolean() const
400  {
401  return is_.boolean;
402  }
403 
406  {
407  return is_.sugar_free_boolean;
408  }
409 
411  bool is_in_nenoform() const
412  {
413  return is_.in_nenoform;
414  }
415 
418  {
419  return is_.syntactic_si;
420  }
421 
423  bool is_sugar_free_ltl() const
424  {
425  return is_.sugar_free_ltl;
426  }
427 
429  bool is_ltl_formula() const
430  {
431  return is_.ltl_formula;
432  }
433 
435  bool is_psl_formula() const
436  {
437  return is_.psl_formula;
438  }
439 
441  bool is_sere_formula() const
442  {
443  return is_.sere_formula;
444  }
445 
447  bool is_finite() const
448  {
449  return is_.finite;
450  }
451 
453  bool is_eventual() const
454  {
455  return is_.eventual;
456  }
457 
459  bool is_universal() const
460  {
461  return is_.universal;
462  }
463 
465  bool is_syntactic_safety() const
466  {
467  return is_.syntactic_safety;
468  }
469 
472  {
473  return is_.syntactic_guarantee;
474  }
475 
478  {
479  return is_.syntactic_obligation;
480  }
481 
484  {
485  return is_.syntactic_recurrence;
486  }
487 
490  {
491  return is_.syntactic_persistence;
492  }
493 
495  bool is_marked() const
496  {
497  return !is_.not_marked;
498  }
499 
501  bool accepts_eword() const
502  {
503  return is_.accepting_eword;
504  }
505 
507  bool has_lbt_atomic_props() const
508  {
509  return is_.lbt_atomic_props;
510  }
511 
514  {
515  return is_.spin_atomic_props;
516  }
517 
518  private:
519  static size_t bump_next_id();
520  void setup_props(op o);
521  void destroy_aux() const;
522 
523  [[noreturn]] static void report_non_existing_child();
524  [[noreturn]] static void report_too_many_children();
525  [[noreturn]] static void
526  report_get_child_of_expecting_single_child_node();
527  [[noreturn]] static void report_min_invalid_arg();
528  [[noreturn]] static void report_max_invalid_arg();
529 
530  static const fnode* unique(fnode*);
531 
532  // Destruction may only happen via destroy().
533  ~fnode() = default;
534  // Disallow copies.
535  fnode(const fnode&) = delete;
536  fnode& operator=(const fnode&) = delete;
537 
538 
539 
540  template<class iter>
541  fnode(op o, iter begin, iter end)
542  // Clang has some optimization where is it able to combine the
543  // 4 movb initializing op_,min_,max_,saturated_ into a single
544  // movl. Also it can optimize the three byte-comparisons of
545  // is_Kleene_star() into a single masked 32-bit comparison.
546  // The latter optimization triggers warnings from valgrind if
547  // min_ and max_ are not initialized. So to benefit from the
548  // initialization optimization and the is_Kleene_star()
549  // optimization in Clang, we always initialize min_ and max_
550  // with this compiler. Do not do it the rest of the time,
551  // since the optimization is not done.
552  : op_(o),
553 #if __llvm__
554  min_(0), max_(0),
555 #endif
556  saturated_(0)
557  {
558  size_t s = std::distance(begin, end);
559  if (SPOT_UNLIKELY(s > (size_t) UINT16_MAX))
560  report_too_many_children();
561  size_ = s;
562  auto pos = children;
563  for (auto i = begin; i != end; ++i)
564  *pos++ = *i;
565  setup_props(o);
566  }
567 
568  fnode(op o, std::initializer_list<const fnode*> l)
569  : fnode(o, l.begin(), l.end())
570  {
571  }
572 
573  fnode(op o, const fnode* f, uint8_t min, uint8_t max)
574  : op_(o), min_(min), max_(max), saturated_(0), size_(1)
575  {
576  children[0] = f;
577  setup_props(o);
578  }
579 
580  static const fnode* ff_;
581  static const fnode* tt_;
582  static const fnode* ew_;
583  static const fnode* one_star_;
584 
585  op op_; // operator
586  uint8_t min_; // range minimum (for star-like operators)
587  uint8_t max_; // range maximum;
588  mutable uint8_t saturated_;
589  uint16_t size_; // number of children
590  mutable uint16_t refs_ = 0; // reference count - 1;
591  size_t id_; // Also used as hash.
592  static size_t next_id_;
593 
594  struct ltl_prop
595  {
596  // All properties here should be expressed in such a a way
597  // that property(f && g) is just property(f)&property(g).
598  // This allows us to compute all properties of a compound
599  // formula in one operation.
600  //
601  // For instance we do not use a property that says "has
602  // temporal operator", because it would require an OR between
603  // the two arguments. Instead we have a property that
604  // says "no temporal operator", and that one is computed
605  // with an AND between the arguments.
606  //
607  // Also choose a name that makes sense when prefixed with
608  // "the formula is".
609  bool boolean:1; // No temporal operators.
610  bool sugar_free_boolean:1; // Only AND, OR, and NOT operators.
611  bool in_nenoform:1; // Negative Normal Form.
612  bool syntactic_si:1; // LTL-X or siPSL
613  bool sugar_free_ltl:1; // No F and G operators.
614  bool ltl_formula:1; // Only LTL operators.
615  bool psl_formula:1; // Only PSL operators.
616  bool sere_formula:1; // Only SERE operators.
617  bool finite:1; // Finite SERE formulae, or Bool+X forms.
618  bool eventual:1; // Purely eventual formula.
619  bool universal:1; // Purely universal formula.
620  bool syntactic_safety:1; // Syntactic Safety Property.
621  bool syntactic_guarantee:1; // Syntactic Guarantee Property.
622  bool syntactic_obligation:1; // Syntactic Obligation Property.
623  bool syntactic_recurrence:1; // Syntactic Recurrence Property.
624  bool syntactic_persistence:1; // Syntactic Persistence Property.
625  bool not_marked:1; // No occurrence of EConcatMarked.
626  bool accepting_eword:1; // Accepts the empty word.
627  bool lbt_atomic_props:1; // Use only atomic propositions like p42.
628  bool spin_atomic_props:1; // Use only spin-compatible atomic props.
629  };
630  union
631  {
632  // Use an unsigned for fast computation of all properties.
633  unsigned props;
634  ltl_prop is_;
635  };
636 
637  const fnode* children[1];
638  };
639 
641  SPOT_API
642  int atomic_prop_cmp(const fnode* f, const fnode* g);
643 
645  {
646  bool
647  operator()(const fnode* left, const fnode* right) const
648  {
649  SPOT_ASSERT(left);
650  SPOT_ASSERT(right);
651  if (left == right)
652  return false;
653 
654  // We want Boolean formulae first.
655  bool lib = left->is_boolean();
656  if (lib != right->is_boolean())
657  return lib;
658 
659  // We have two Boolean formulae
660  if (lib)
661  {
662  bool lconst = left->is_constant();
663  if (lconst != right->is_constant())
664  return lconst;
665  if (!lconst)
666  {
667  auto get_literal = [](const fnode* f) -> const fnode*
668  {
669  if (f->is(op::Not))
670  f = f->nth(0);
671  if (f->is(op::ap))
672  return f;
673  return nullptr;
674  };
675  // Literals should come first
676  const fnode* litl = get_literal(left);
677  const fnode* litr = get_literal(right);
678  if (!litl != !litr)
679  return litl;
680  if (litl)
681  {
682  // And they should be sorted alphabetically
683  int cmp = atomic_prop_cmp(litl, litr);
684  if (cmp)
685  return cmp < 0;
686  }
687  }
688  }
689 
690  size_t l = left->id();
691  size_t r = right->id();
692  if (l != r)
693  return l < r;
694  // Because the hash code assigned to each formula is the
695  // number of formulae constructed so far, it is very unlikely
696  // that we will ever reach a case were two different formulae
697  // have the same hash. This will happen only ever with have
698  // produced 256**sizeof(size_t) formulae (i.e. max_count has
699  // looped back to 0 and started over). In that case we can
700  // order two formulas by looking at their text representation.
701  // We could be more efficient and look at their AST, but it's
702  // not worth the burden. (Also ordering pointers is ruled out
703  // because it breaks the determinism of the implementation.)
704  std::ostringstream old;
705  left->dump(old);
706  std::ostringstream ord;
707  right->dump(ord);
708  return old.str() < ord.str();
709  }
710  };
711 
712 #endif // SWIG
713 
716  class SPOT_API formula final
717  {
718  const fnode* ptr_;
719  public:
724  explicit formula(const fnode* f) noexcept
725  : ptr_(f)
726  {
727  }
728 
734  formula(std::nullptr_t) noexcept
735  : ptr_(nullptr)
736  {
737  }
738 
740  formula() noexcept
741  : ptr_(nullptr)
742  {
743  }
744 
746  formula(const formula& f) noexcept
747  : ptr_(f.ptr_)
748  {
749  if (ptr_)
750  ptr_->clone();
751  }
752 
754  formula(formula&& f) noexcept
755  : ptr_(f.ptr_)
756  {
757  f.ptr_ = nullptr;
758  }
759 
762  {
763  if (ptr_)
764  ptr_->destroy();
765  }
766 
774  const formula& operator=(std::nullptr_t)
775  {
776  this->~formula();
777  ptr_ = nullptr;
778  return *this;
779  }
780 
781  const formula& operator=(const formula& f)
782  {
783  this->~formula();
784  if ((ptr_ = f.ptr_))
785  ptr_->clone();
786  return *this;
787  }
788 
789  const formula& operator=(formula&& f) noexcept
790  {
791  std::swap(f.ptr_, ptr_);
792  return *this;
793  }
794 
795  bool operator<(const formula& other) const noexcept
796  {
797  if (SPOT_UNLIKELY(!other.ptr_))
798  return false;
799  if (SPOT_UNLIKELY(!ptr_))
800  return true;
801  if (id() < other.id())
802  return true;
803  if (id() > other.id())
804  return false;
805  // The case where id()==other.id() but ptr_ != other.ptr_ is
806  // very unlikely (we would need to build more than UINT_MAX
807  // formulas), so let's just compare pointers, and ignore the
808  // fact that it may introduce some nondeterminism.
809  return ptr_ < other.ptr_;
810  }
811 
812  bool operator<=(const formula& other) const noexcept
813  {
814  return *this == other || *this < other;
815  }
816 
817  bool operator>(const formula& other) const noexcept
818  {
819  return !(*this <= other);
820  }
821 
822  bool operator>=(const formula& other) const noexcept
823  {
824  return !(*this < other);
825  }
826 
827  bool operator==(const formula& other) const noexcept
828  {
829  return other.ptr_ == ptr_;
830  }
831 
832  bool operator==(std::nullptr_t) const noexcept
833  {
834  return ptr_ == nullptr;
835  }
836 
837  bool operator!=(const formula& other) const noexcept
838  {
839  return other.ptr_ != ptr_;
840  }
841 
842  bool operator!=(std::nullptr_t) const noexcept
843  {
844  return ptr_ != nullptr;
845  }
846 
847  explicit operator bool() const noexcept
848  {
849  return ptr_ != nullptr;
850  }
851 
853  // Forwarded functions //
855 
857  static constexpr uint8_t unbounded()
858  {
859  return fnode::unbounded();
860  }
861 
863  static formula ap(const std::string& name)
864  {
865  return formula(fnode::ap(name));
866  }
867 
873  static formula ap(const formula& a)
874  {
875  if (SPOT_UNLIKELY(a.kind() != op::ap))
876  report_ap_invalid_arg();
877  return a;
878  }
879 
884  static formula unop(op o, const formula& f)
885  {
886  return formula(fnode::unop(o, f.ptr_->clone()));
887  }
888 
889 #ifndef SWIG
890  static formula unop(op o, formula&& f)
891  {
892  return formula(fnode::unop(o, f.to_node_()));
893  }
894 #endif // !SWIG
896 
897 #ifdef SWIG
898 #define SPOT_DEF_UNOP(Name) \
899  static formula Name(const formula& f) \
900  { \
901  return unop(op::Name, f); \
902  }
903 #else // !SWIG
904 #define SPOT_DEF_UNOP(Name) \
905  static formula Name(const formula& f) \
906  { \
907  return unop(op::Name, f); \
908  } \
909  static formula Name(formula&& f) \
910  { \
911  return unop(op::Name, std::move(f)); \
912  }
913 #endif // !SWIG
916  SPOT_DEF_UNOP(Not);
918 
921  SPOT_DEF_UNOP(X);
923 
927  static formula X(unsigned level, const formula& f)
928  {
929  return nested_unop_range(op::X, op::Or /* unused */, level, level, f);
930  }
931 
932 #if SPOT_WANT_STRONG_X
935  SPOT_DEF_UNOP(strong_X);
937 
941  static formula strong_X(unsigned level, const formula& f)
942  {
943  return nested_unop_range(op::strong_X, op::Or /* unused */,
944  level, level, f);
945  }
946 #endif
947 
950  SPOT_DEF_UNOP(F);
952 
959  static formula F(unsigned min_level, unsigned max_level, const formula& f)
960  {
961  return nested_unop_range(op::X, op::Or, min_level, max_level, f);
962  }
963 
970  static formula G(unsigned min_level, unsigned max_level, const formula& f)
971  {
972  return nested_unop_range(op::X, op::And, min_level, max_level, f);
973  }
974 
977  SPOT_DEF_UNOP(G);
979 
982  SPOT_DEF_UNOP(Closure);
984 
987  SPOT_DEF_UNOP(NegClosure);
989 
992  SPOT_DEF_UNOP(NegClosureMarked);
994 
997  SPOT_DEF_UNOP(first_match);
999 #undef SPOT_DEF_UNOP
1000 
1006  static formula binop(op o, const formula& f, const formula& g)
1007  {
1008  return formula(fnode::binop(o, f.ptr_->clone(), g.ptr_->clone()));
1009  }
1010 
1011 #ifndef SWIG
1012  static formula binop(op o, const formula& f, formula&& g)
1013  {
1014  return formula(fnode::binop(o, f.ptr_->clone(), g.to_node_()));
1015  }
1016 
1017  static formula binop(op o, formula&& f, const formula& g)
1018  {
1019  return formula(fnode::binop(o, f.to_node_(), g.ptr_->clone()));
1020  }
1021 
1022  static formula binop(op o, formula&& f, formula&& g)
1023  {
1024  return formula(fnode::binop(o, f.to_node_(), g.to_node_()));
1025  }
1027 
1028 #endif //SWIG
1029 
1030 #ifdef SWIG
1031 #define SPOT_DEF_BINOP(Name) \
1032  static formula Name(const formula& f, const formula& g) \
1033  { \
1034  return binop(op::Name, f, g); \
1035  }
1036 #else // !SWIG
1037 #define SPOT_DEF_BINOP(Name) \
1038  static formula Name(const formula& f, const formula& g) \
1039  { \
1040  return binop(op::Name, f, g); \
1041  } \
1042  static formula Name(const formula& f, formula&& g) \
1043  { \
1044  return binop(op::Name, f, std::move(g)); \
1045  } \
1046  static formula Name(formula&& f, const formula& g) \
1047  { \
1048  return binop(op::Name, std::move(f), g); \
1049  } \
1050  static formula Name(formula&& f, formula&& g) \
1051  { \
1052  return binop(op::Name, std::move(f), std::move(g)); \
1053  }
1054 #endif // !SWIG
1057  SPOT_DEF_BINOP(Xor);
1059 
1062  SPOT_DEF_BINOP(Implies);
1064 
1067  SPOT_DEF_BINOP(Equiv);
1069 
1072  SPOT_DEF_BINOP(U);
1074 
1077  SPOT_DEF_BINOP(R);
1079 
1082  SPOT_DEF_BINOP(W);
1084 
1087  SPOT_DEF_BINOP(M);
1089 
1092  SPOT_DEF_BINOP(EConcat);
1094 
1097  SPOT_DEF_BINOP(EConcatMarked);
1099 
1102  SPOT_DEF_BINOP(UConcat);
1104 #undef SPOT_DEF_BINOP
1105 
1111  static formula multop(op o, const std::vector<formula>& l)
1112  {
1113  std::vector<const fnode*> tmp;
1114  tmp.reserve(l.size());
1115  for (auto f: l)
1116  if (f.ptr_)
1117  tmp.emplace_back(f.ptr_->clone());
1118  return formula(fnode::multop(o, std::move(tmp)));
1119  }
1120 
1121 #ifndef SWIG
1122  static formula multop(op o, std::vector<formula>&& l)
1123  {
1124  std::vector<const fnode*> tmp;
1125  tmp.reserve(l.size());
1126  for (auto f: l)
1127  if (f.ptr_)
1128  tmp.emplace_back(f.to_node_());
1129  return formula(fnode::multop(o, std::move(tmp)));
1130  }
1131 #endif // !SWIG
1133 
1134 #ifdef SWIG
1135 #define SPOT_DEF_MULTOP(Name) \
1136  static formula Name(const std::vector<formula>& l) \
1137  { \
1138  return multop(op::Name, l); \
1139  }
1140 #else // !SWIG
1141 #define SPOT_DEF_MULTOP(Name) \
1142  static formula Name(const std::vector<formula>& l) \
1143  { \
1144  return multop(op::Name, l); \
1145  } \
1146  \
1147  static formula Name(std::vector<formula>&& l) \
1148  { \
1149  return multop(op::Name, std::move(l)); \
1150  }
1151 #endif // !SWIG
1154  SPOT_DEF_MULTOP(Or);
1156 
1159  SPOT_DEF_MULTOP(OrRat);
1161 
1164  SPOT_DEF_MULTOP(And);
1166 
1169  SPOT_DEF_MULTOP(AndRat);
1171 
1174  SPOT_DEF_MULTOP(AndNLM);
1176 
1179  SPOT_DEF_MULTOP(Concat);
1181 
1184  SPOT_DEF_MULTOP(Fusion);
1186 #undef SPOT_DEF_MULTOP
1187 
1192  static formula bunop(op o, const formula& f,
1193  unsigned min = 0U,
1194  unsigned max = unbounded())
1195  {
1196  return formula(fnode::bunop(o, f.ptr_->clone(), min, max));
1197  }
1198 
1199 #ifndef SWIG
1200  static formula bunop(op o, formula&& f,
1201  unsigned min = 0U,
1202  unsigned max = unbounded())
1203  {
1204  return formula(fnode::bunop(o, f.to_node_(), min, max));
1205  }
1206 #endif // !SWIG
1208 
1209 #if SWIG
1210 #define SPOT_DEF_BUNOP(Name) \
1211  static formula Name(const formula& f, \
1212  unsigned min = 0U, \
1213  unsigned max = unbounded()) \
1214  { \
1215  return bunop(op::Name, f, min, max); \
1216  }
1217 #else // !SWIG
1218 #define SPOT_DEF_BUNOP(Name) \
1219  static formula Name(const formula& f, \
1220  unsigned min = 0U, \
1221  unsigned max = unbounded()) \
1222  { \
1223  return bunop(op::Name, f, min, max); \
1224  } \
1225  static formula Name(formula&& f, \
1226  unsigned min = 0U, \
1227  unsigned max = unbounded()) \
1228  { \
1229  return bunop(op::Name, std::move(f), min, max); \
1230  }
1231 #endif
1234  SPOT_DEF_BUNOP(Star);
1236 
1242  SPOT_DEF_BUNOP(FStar);
1244 #undef SPOT_DEF_BUNOP
1245 
1257  static const formula nested_unop_range(op uo, op bo, unsigned min,
1258  unsigned max, formula f)
1259  {
1260  return formula(fnode::nested_unop_range(uo, bo, min, max,
1261  f.ptr_->clone()));
1262  }
1263 
1269  static formula sugar_goto(const formula& b, unsigned min, unsigned max);
1270 
1276  static formula sugar_equal(const formula& b, unsigned min, unsigned max);
1277 
1299  static formula sugar_delay(const formula& a, const formula& b,
1300  unsigned min, unsigned max);
1301  static formula sugar_delay(const formula& b,
1302  unsigned min, unsigned max);
1304 
1305 #ifndef SWIG
1315  const fnode* to_node_()
1316  {
1317  auto tmp = ptr_;
1318  ptr_ = nullptr;
1319  return tmp;
1320  }
1321 #endif
1322 
1324  op kind() const
1325  {
1326  return ptr_->kind();
1327  }
1328 
1330  std::string kindstr() const
1331  {
1332  return ptr_->kindstr();
1333  }
1334 
1336  bool is(op o) const
1337  {
1338  return ptr_->is(o);
1339  }
1340 
1341 #ifndef SWIG
1343  bool is(op o1, op o2) const
1344  {
1345  return ptr_->is(o1, o2);
1346  }
1347 
1349  bool is(op o1, op o2, op o3) const
1350  {
1351  return ptr_->is(o1, o2, o3);
1352  }
1353 
1356  bool is(op o1, op o2, op o3, op o4) const
1357  {
1358  return ptr_->is(o1, o2, o3, o4);
1359  }
1360 
1362  bool is(std::initializer_list<op> l) const
1363  {
1364  return ptr_->is(l);
1365  }
1366 #endif
1367 
1372  {
1373  auto f = ptr_->get_child_of(o);
1374  if (f)
1375  f->clone();
1376  return formula(f);
1377  }
1378 
1379 #ifndef SWIG
1386  formula get_child_of(std::initializer_list<op> l) const
1387  {
1388  auto f = ptr_->get_child_of(l);
1389  if (f)
1390  f->clone();
1391  return formula(f);
1392  }
1393 #endif
1394 
1398  unsigned min() const
1399  {
1400  return ptr_->min();
1401  }
1402 
1406  unsigned max() const
1407  {
1408  return ptr_->max();
1409  }
1410 
1412  unsigned size() const
1413  {
1414  return ptr_->size();
1415  }
1416 
1421  bool is_leaf() const
1422  {
1423  return ptr_->is_leaf();
1424  }
1425 
1434  size_t id() const
1435  {
1436  return ptr_->id();
1437  }
1438 
1439 #ifndef SWIG
1441  class SPOT_API formula_child_iterator final
1442  {
1443  const fnode*const* ptr_;
1444  public:
1446  : ptr_(nullptr)
1447  {
1448  }
1449 
1450  formula_child_iterator(const fnode*const* f)
1451  : ptr_(f)
1452  {
1453  }
1454 
1455  bool operator==(formula_child_iterator o)
1456  {
1457  return ptr_ == o.ptr_;
1458  }
1459 
1460  bool operator!=(formula_child_iterator o)
1461  {
1462  return ptr_ != o.ptr_;
1463  }
1464 
1465  formula operator*()
1466  {
1467  return formula((*ptr_)->clone());
1468  }
1469 
1470  formula_child_iterator operator++()
1471  {
1472  ++ptr_;
1473  return *this;
1474  }
1475 
1476  formula_child_iterator operator++(int)
1477  {
1478  auto tmp = *this;
1479  ++ptr_;
1480  return tmp;
1481  }
1482  };
1483 
1486  {
1487  return ptr_->begin();
1488  }
1489 
1492  {
1493  return ptr_->end();
1494  }
1495 
1497  formula operator[](unsigned i) const
1498  {
1499  return formula(ptr_->nth(i)->clone());
1500  }
1501 #endif
1502 
1504  static formula ff()
1505  {
1506  return formula(fnode::ff());
1507  }
1508 
1510  bool is_ff() const
1511  {
1512  return ptr_->is_ff();
1513  }
1514 
1516  static formula tt()
1517  {
1518  return formula(fnode::tt());
1519  }
1520 
1522  bool is_tt() const
1523  {
1524  return ptr_->is_tt();
1525  }
1526 
1528  static formula eword()
1529  {
1530  return formula(fnode::eword());
1531  }
1532 
1534  bool is_eword() const
1535  {
1536  return ptr_->is_eword();
1537  }
1538 
1540  bool is_constant() const
1541  {
1542  return ptr_->is_constant();
1543  }
1544 
1549  bool is_Kleene_star() const
1550  {
1551  return ptr_->is_Kleene_star();
1552  }
1553 
1556  {
1557  return formula(fnode::one_star()->clone());
1558  }
1559 
1562  bool is_literal() const
1563  {
1564  return (is(op::ap) ||
1565  // If f is in nenoform, Not can only occur in front of
1566  // an atomic proposition. So this way we do not have
1567  // to check the type of the child.
1568  (is(op::Not) && is_boolean() && is_in_nenoform()));
1569  }
1570 
1574  const std::string& ap_name() const
1575  {
1576  return ptr_->ap_name();
1577  }
1578 
1583  std::ostream& dump(std::ostream& os) const
1584  {
1585  return ptr_->dump(os);
1586  }
1587 
1593  formula all_but(unsigned i) const
1594  {
1595  return formula(ptr_->all_but(i));
1596  }
1597 
1607  unsigned boolean_count() const
1608  {
1609  return ptr_->boolean_count();
1610  }
1611 
1625  formula boolean_operands(unsigned* width = nullptr) const
1626  {
1627  return formula(ptr_->boolean_operands(width));
1628  }
1629 
1630 #define SPOT_DEF_PROP(Name) \
1631  bool Name() const \
1632  { \
1633  return ptr_->Name(); \
1634  }
1636  // Properties //
1638 
1640  SPOT_DEF_PROP(is_boolean);
1642  SPOT_DEF_PROP(is_sugar_free_boolean);
1647  SPOT_DEF_PROP(is_in_nenoform);
1649  SPOT_DEF_PROP(is_syntactic_stutter_invariant);
1651  SPOT_DEF_PROP(is_sugar_free_ltl);
1653  SPOT_DEF_PROP(is_ltl_formula);
1655  SPOT_DEF_PROP(is_psl_formula);
1657  SPOT_DEF_PROP(is_sere_formula);
1660  SPOT_DEF_PROP(is_finite);
1668  SPOT_DEF_PROP(is_eventual);
1676  SPOT_DEF_PROP(is_universal);
1678  SPOT_DEF_PROP(is_syntactic_safety);
1680  SPOT_DEF_PROP(is_syntactic_guarantee);
1682  SPOT_DEF_PROP(is_syntactic_obligation);
1684  SPOT_DEF_PROP(is_syntactic_recurrence);
1686  SPOT_DEF_PROP(is_syntactic_persistence);
1689  SPOT_DEF_PROP(is_marked);
1691  SPOT_DEF_PROP(accepts_eword);
1697  SPOT_DEF_PROP(has_lbt_atomic_props);
1706  SPOT_DEF_PROP(has_spin_atomic_props);
1707 #undef SPOT_DEF_PROP
1708 
1712  template<typename Trans, typename... Args>
1713  formula map(Trans trans, Args&&... args)
1714  {
1715  switch (op o = kind())
1716  {
1717  case op::ff:
1718  case op::tt:
1719  case op::eword:
1720  case op::ap:
1721  return *this;
1722  case op::Not:
1723  case op::X:
1724 #if SPOT_HAS_STRONG_X
1725  case op::strong_X:
1726 #endif
1727  case op::F:
1728  case op::G:
1729  case op::Closure:
1730  case op::NegClosure:
1731  case op::NegClosureMarked:
1732  case op::first_match:
1733  return unop(o, trans((*this)[0], std::forward<Args>(args)...));
1734  case op::Xor:
1735  case op::Implies:
1736  case op::Equiv:
1737  case op::U:
1738  case op::R:
1739  case op::W:
1740  case op::M:
1741  case op::EConcat:
1742  case op::EConcatMarked:
1743  case op::UConcat:
1744  {
1745  formula tmp = trans((*this)[0], std::forward<Args>(args)...);
1746  return binop(o, tmp,
1747  trans((*this)[1], std::forward<Args>(args)...));
1748  }
1749  case op::Or:
1750  case op::OrRat:
1751  case op::And:
1752  case op::AndRat:
1753  case op::AndNLM:
1754  case op::Concat:
1755  case op::Fusion:
1756  {
1757  std::vector<formula> tmp;
1758  tmp.reserve(size());
1759  for (auto f: *this)
1760  tmp.emplace_back(trans(f, std::forward<Args>(args)...));
1761  return multop(o, std::move(tmp));
1762  }
1763  case op::Star:
1764  case op::FStar:
1765  return bunop(o, trans((*this)[0], std::forward<Args>(args)...),
1766  min(), max());
1767  }
1768  SPOT_UNREACHABLE();
1769  }
1770 
1779  template<typename Func, typename... Args>
1780  void traverse(Func func, Args&&... args)
1781  {
1782  if (func(*this, std::forward<Args>(args)...))
1783  return;
1784  for (auto f: *this)
1785  f.traverse(func, std::forward<Args>(args)...);
1786  }
1787 
1788  private:
1789 #ifndef SWIG
1790  [[noreturn]] static void report_ap_invalid_arg();
1791 #endif
1792  };
1793 
1795  SPOT_API
1796  std::ostream& print_formula_props(std::ostream& out, const formula& f,
1797  bool abbreviated = false);
1798 
1800  SPOT_API
1801  std::list<std::string> list_formula_props(const formula& f);
1802 
1804  SPOT_API
1805  std::ostream& operator<<(std::ostream& os, const formula& f);
1806 }
1807 
1808 #ifndef SWIG
1809 namespace std
1810 {
1811  template <>
1812  struct hash<spot::formula>
1813  {
1814  size_t operator()(const spot::formula& x) const noexcept
1815  {
1816  return x.id();
1817  }
1818  };
1819 }
1820 #endif
Actual storage for formula nodes.
Definition: formula.hh:128
const fnode *const * begin() const
Definition: formula.hh:281
const fnode *const * end() const
Definition: formula.hh:287
std::string kindstr() const
std::ostream & dump(std::ostream &os) const
bool is_boolean() const
Definition: formula.hh:399
size_t id() const
Definition: formula.hh:275
bool is_ff() const
Definition: formula.hh:309
bool is_sugar_free_boolean() const
Definition: formula.hh:405
bool is_Kleene_star() const
Definition: formula.hh:345
unsigned min() const
Definition: formula.hh:247
bool is_syntactic_safety() const
Definition: formula.hh:465
bool is_syntactic_stutter_invariant() const
Definition: formula.hh:417
unsigned size() const
Definition: formula.hh:263
static constexpr uint8_t unbounded()
Definition: formula.hh:158
static const fnode * eword()
Definition: formula.hh:327
const fnode * get_child_of(op o) const
Definition: formula.hh:224
unsigned max() const
Definition: formula.hh:255
static const fnode * ff()
Definition: formula.hh:303
const fnode * boolean_operands(unsigned *width=nullptr) const
bool accepts_eword() const
Definition: formula.hh:501
bool is_eventual() const
Definition: formula.hh:453
const std::string & ap_name() const
bool is(op o1, op o2, op o3, op o4) const
Definition: formula.hh:205
static bool instances_check()
safety check for the reference counters
bool is_leaf() const
Definition: formula.hh:269
bool has_spin_atomic_props() const
Definition: formula.hh:513
bool is_eword() const
Definition: formula.hh:333
static const fnode * tt()
Definition: formula.hh:315
bool is(op o1, op o2, op o3) const
Definition: formula.hh:200
op kind() const
Definition: formula.hh:180
bool has_lbt_atomic_props() const
Definition: formula.hh:507
bool is_sugar_free_ltl() const
Definition: formula.hh:423
bool is_syntactic_persistence() const
Definition: formula.hh:489
static const fnode * nested_unop_range(op uo, op bo, unsigned min, unsigned max, const fnode *f)
unsigned boolean_count() const
Definition: formula.hh:370
bool is_universal() const
Definition: formula.hh:459
bool is_tt() const
Definition: formula.hh:321
const fnode * get_child_of(std::initializer_list< op > l) const
Definition: formula.hh:234
const fnode * nth(unsigned i) const
Definition: formula.hh:293
bool is_constant() const
Definition: formula.hh:339
static const fnode * binop(op o, const fnode *f, const fnode *g)
static const fnode * one_star()
Definition: formula.hh:353
const fnode * all_but(unsigned i) const
bool is_syntactic_recurrence() const
Definition: formula.hh:483
bool is(std::initializer_list< op > l) const
Definition: formula.hh:210
bool is_syntactic_obligation() const
Definition: formula.hh:477
static const fnode * unop(op o, const fnode *f)
bool is_ltl_formula() const
Definition: formula.hh:429
bool is_finite() const
Definition: formula.hh:447
bool is_psl_formula() const
Definition: formula.hh:435
static const fnode * multop(op o, std::vector< const fnode * > l)
bool is_marked() const
Definition: formula.hh:495
void destroy() const
Dereference an fnode.
Definition: formula.hh:148
static const fnode * bunop(op o, const fnode *f, unsigned min, unsigned max=unbounded())
bool is(op o1, op o2) const
Definition: formula.hh:195
bool is_in_nenoform() const
Definition: formula.hh:411
static const fnode * ap(const std::string &name)
bool is_syntactic_guarantee() const
Definition: formula.hh:471
bool is_sere_formula() const
Definition: formula.hh:441
const fnode * clone() const
Clone an fnode.
Definition: formula.hh:134
bool is(op o) const
Definition: formula.hh:190
Allow iterating over children.
Definition: formula.hh:1442
Main class for temporal logic formula.
Definition: formula.hh:717
unsigned boolean_count() const
number of Boolean children
Definition: formula.hh:1607
bool is_leaf() const
Whether the formula is a leaf.
Definition: formula.hh:1421
size_t id() const
Return the id of a formula.
Definition: formula.hh:1434
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:1200
formula map(Trans trans, Args &&... args)
Clone this node after applying trans to its children.
Definition: formula.hh:1713
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:1192
static formula G(unsigned min_level, unsigned max_level, const formula &f)
Construct G[n:m].
Definition: formula.hh:970
static formula binop(op o, const formula &f, const formula &g)
Construct a binary operator.
Definition: formula.hh:1006
bool is(op o) const
Return true if the formula is of kind o.
Definition: formula.hh:1336
static formula multop(op o, std::vector< formula > &&l)
Construct an n-ary operator.
Definition: formula.hh:1122
formula(formula &&f) noexcept
Move-construct a formula.
Definition: formula.hh:754
formula(const fnode *f) noexcept
Create a formula from an fnode.
Definition: formula.hh:724
bool is(op o1, op o2) const
Return true if the formula is of kind o1 or o2.
Definition: formula.hh:1343
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:1555
unsigned min() const
Return start of the range for star-like operators.
Definition: formula.hh:1398
static constexpr uint8_t unbounded()
Unbounded constant to use as end of range for bounded operators.
Definition: formula.hh:857
static formula unop(op o, formula &&f)
Build a unary operator.
Definition: formula.hh:890
static formula eword()
Return the empty word constant.
Definition: formula.hh:1528
formula all_but(unsigned i) const
clone this formula, omitting child i
Definition: formula.hh:1593
static formula ff()
Return the false constant.
Definition: formula.hh:1504
static formula binop(op o, const formula &f, formula &&g)
Construct a binary operator.
Definition: formula.hh:1012
op kind() const
Return top-most operator.
Definition: formula.hh:1324
static formula multop(op o, const std::vector< formula > &l)
Construct an n-ary operator.
Definition: formula.hh:1111
unsigned size() const
Return the number of children.
Definition: formula.hh:1412
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:1522
bool is(op o1, op o2, op o3, op o4) const
Definition: formula.hh:1356
std::string kindstr() const
Return the name of the top-most operator.
Definition: formula.hh:1330
formula(const formula &f) noexcept
Clone a formula.
Definition: formula.hh:746
formula_child_iterator end() const
Allow iterating over children.
Definition: formula.hh:1491
static formula binop(op o, formula &&f, formula &&g)
Construct a binary operator.
Definition: formula.hh:1022
static formula ap(const formula &a)
Build an atomic proposition from... an atomic proposition.
Definition: formula.hh:873
formula get_child_of(std::initializer_list< op > l) const
Remove all operators in l and return the child.
Definition: formula.hh:1386
bool is_eword() const
Whether the formula is the empty word constant.
Definition: formula.hh:1534
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:1780
static formula F(unsigned min_level, unsigned max_level, const formula &f)
Construct F[n:m].
Definition: formula.hh:959
formula(std::nullptr_t) noexcept
Create a null formula.
Definition: formula.hh:734
static formula ap(const std::string &name)
Build an atomic proposition.
Definition: formula.hh:863
const std::string & ap_name() const
Print the name of an atomic proposition.
Definition: formula.hh:1574
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:1349
const formula & operator=(std::nullptr_t)
Reset a formula to null.
Definition: formula.hh:774
unsigned max() const
Return end of the range for star-like operators.
Definition: formula.hh:1406
static formula X(unsigned level, const formula &f)
Construct an X[n].
Definition: formula.hh:927
bool is_ff() const
Whether the formula is the false constant.
Definition: formula.hh:1510
formula_child_iterator begin() const
Allow iterating over children.
Definition: formula.hh:1485
bool is_constant() const
Whether the formula is op::ff, op::tt, or op::eword.
Definition: formula.hh:1540
~formula()
Destroy a formula.
Definition: formula.hh:761
std::ostream & dump(std::ostream &os) const
Print the formula for debugging.
Definition: formula.hh:1583
formula get_child_of(op o) const
Remove operator o and return the child.
Definition: formula.hh:1371
const fnode * to_node_()
Return the underlying pointer to the formula.
Definition: formula.hh:1315
bool is(std::initializer_list< op > l) const
Return true if the formulas nests all the operators in l.
Definition: formula.hh:1362
formula operator[](unsigned i) const
Return children number i.
Definition: formula.hh:1497
bool is_Kleene_star() const
Test whether the formula represent a Kleene star.
Definition: formula.hh:1549
static formula binop(op o, formula &&f, const formula &g)
Construct a binary operator.
Definition: formula.hh:1017
bool is_literal() const
Whether the formula is an atomic proposition or its negation.
Definition: formula.hh:1562
static formula tt()
Return the true constant.
Definition: formula.hh:1516
formula() noexcept
Default initialize a formula to nullptr.
Definition: formula.hh:740
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:884
formula boolean_operands(unsigned *width=nullptr) const
return a clone of the current node, restricted to its Boolean children
Definition: formula.hh:1625
static const formula nested_unop_range(op uo, op bo, unsigned min, unsigned max, formula f)
Nested operator construction (syntactic sugar).
Definition: formula.hh:1257
op
Operator types.
Definition: formula.hh:79
@ 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:27
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:645

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.1