spot  2.3.3.dev
acc.hh
1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2014, 2015, 2016, 2017 Laboratoire de Recherche et
3 // Développement de l'Epita.
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 
20 #pragma once
21 
22 #include <functional>
23 #include <unordered_map>
24 #include <sstream>
25 #include <vector>
26 #include <spot/tl/defaultenv.hh>
27 #include <iostream>
28 
29 namespace spot
30 {
31  class SPOT_API acc_cond
32  {
33  public:
34  struct mark_t
35  {
36  typedef unsigned value_t;
37  value_t id;
38 
39  mark_t() = default;
40 
41  mark_t(value_t id) noexcept
42  : id(id)
43  {
44  }
45 
46  template<class iterator>
47  mark_t(const iterator& begin, const iterator& end) noexcept
48  {
49  id = 0U;
50  for (iterator i = begin; i != end; ++i)
51  set(*i);
52  }
53 
54  mark_t(std::initializer_list<unsigned> vals) noexcept
55  : mark_t(vals.begin(), vals.end())
56  {
57  }
58 
59  bool operator==(unsigned o) const
60  {
61  SPOT_ASSERT(o == 0U);
62  return id == o;
63  }
64 
65  bool operator!=(unsigned o) const
66  {
67  SPOT_ASSERT(o == 0U);
68  return id != o;
69  }
70 
71  bool operator==(mark_t o) const
72  {
73  return id == o.id;
74  }
75 
76  bool operator!=(mark_t o) const
77  {
78  return id != o.id;
79  }
80 
81  bool operator<(mark_t o) const
82  {
83  return id < o.id;
84  }
85 
86  bool operator<=(mark_t o) const
87  {
88  return id <= o.id;
89  }
90 
91  bool operator>(mark_t o) const
92  {
93  return id > o.id;
94  }
95 
96  bool operator>=(mark_t o) const
97  {
98  return id >= o.id;
99  }
100 
101  explicit operator bool() const
102  {
103  return id != 0;
104  }
105 
106  bool has(unsigned u) const
107  {
108  return id & (1U << u);
109  }
110 
111  void set(unsigned u)
112  {
113  id |= (1U << u);
114  }
115 
116  void clear(unsigned u)
117  {
118  id &= ~(1U << u);
119  }
120 
121  mark_t& operator&=(mark_t r)
122  {
123  id &= r.id;
124  return *this;
125  }
126 
127  mark_t& operator|=(mark_t r)
128  {
129  id |= r.id;
130  return *this;
131  }
132 
133  mark_t& operator-=(mark_t r)
134  {
135  id &= ~r.id;
136  return *this;
137  }
138 
139  mark_t& operator^=(mark_t r)
140  {
141  id ^= r.id;
142  return *this;
143  }
144 
145  mark_t operator&(mark_t r) const
146  {
147  return id & r.id;
148  }
149 
150  mark_t operator|(mark_t r) const
151  {
152  return id | r.id;
153  }
154 
155  mark_t operator-(mark_t r) const
156  {
157  return id & ~r.id;
158  }
159 
160  mark_t operator~() const
161  {
162  return ~id;
163  }
164 
165  mark_t operator^(mark_t r) const
166  {
167  return id ^ r.id;
168  }
169 
170  mark_t operator<<(unsigned i) const
171  {
172  return id << i;
173  }
174 
175  mark_t& operator<<=(unsigned i)
176  {
177  id <<= i;
178  return *this;
179  }
180 
181  mark_t operator>>(unsigned i) const
182  {
183  return id >> i;
184  }
185 
186  mark_t& operator>>=(unsigned i)
187  {
188  id >>= i;
189  return *this;
190  }
191 
192  mark_t strip(mark_t y) const
193  {
194  // strip every bit of id that is marked in y
195  // 100101110100.strip(
196  // 001011001000)
197  // == 10 1 11 100
198  // == 10111100
199 
200  auto xv = id; // 100101110100
201  auto yv = y.id; // 001011001000
202 
203  while (yv && xv)
204  {
205  // Mask for everything after the last 1 in y
206  auto rm = (~yv) & (yv - 1); // 000000000111
207  // Mask for everything before the last 1 in y
208  auto lm = ~(yv ^ (yv - 1)); // 111111110000
209  xv = ((xv & lm) >> 1) | (xv & rm);
210  yv = (yv & lm) >> 1;
211  }
212  return xv;
213  }
214 
215  // Number of bits sets.
216  unsigned count() const
217  {
218 #ifdef __GNUC__
219  return __builtin_popcount(id);
220 #else
221  unsigned c = 0U;
222  auto v = id;
223  while (v)
224  {
225  ++c;
226  v &= v - 1;
227  }
228  return c;
229 #endif
230  }
231 
232  // Return the number of the highest set used plus one.
233  // If no set is used, this returns 0,
234  // If the sets {1,3,8} are used, this returns 9.
235  unsigned max_set() const
236  {
237 #ifdef __GNUC__
238  return (id == 0) ? 0 : (sizeof(unsigned) * 8 - __builtin_clz(id));
239 #else
240  auto i = id;
241  int res = 0;
242  while (i)
243  {
244  ++res;
245  i >>= 1;
246  }
247  return res;
248 #endif
249  }
250 
251  // Return the number of the lowest set used plus one.
252  // If no set is used, this returns 0.
253  // If the sets {1,3,8} are used, this returns 2.
254  unsigned min_set() const
255  {
256  if (id == 0)
257  return 0;
258 #ifdef __GNUC__
259  return __builtin_ctz(id) + 1;
260 #else
261  auto i = id;
262  int res = 1;
263  while ((i & 1) == 0)
264  {
265  ++res;
266  i >>= 1;
267  }
268  return res;
269 #endif
270  }
271 
272  // Return the lowest acceptance mark
273  mark_t lowest() const
274  {
275  return id & -id;
276  }
277 
278  // Remove n bits that where set
279  mark_t& remove_some(unsigned n)
280  {
281  while (n--)
282  id &= id - 1;
283  return *this;
284  }
285 
286  template<class iterator>
287  void fill(iterator here) const
288  {
289  auto a = id;
290  unsigned level = 0;
291  while (a)
292  {
293  if (a & 1)
294  *here++ = level;
295  ++level;
296  a >>= 1;
297  }
298  }
299 
300  // FIXME: Return some iterable object without building a vector.
301  std::vector<unsigned> sets() const
302  {
303  std::vector<unsigned> res;
304  fill(std::back_inserter(res));
305  return res;
306  }
307 
308  SPOT_API
309  friend std::ostream& operator<<(std::ostream& os, mark_t m);
310  };
311 
312  // This encodes either an operator or set of acceptance sets.
313  enum class acc_op : unsigned short
314  { Inf, Fin, InfNeg, FinNeg, And, Or };
315  union acc_word
316  {
317  mark_t mark;
318  struct {
319  acc_op op; // Operator
320  unsigned short size; // Size of the subtree (number of acc_word),
321  // not counting this node.
322  } sub;
323  };
324 
325  struct SPOT_API acc_code: public std::vector<acc_word>
326  {
327  bool operator==(const acc_code& other) const
328  {
329  unsigned pos = size();
330  if (other.size() != pos)
331  return false;
332  while (pos > 0)
333  {
334  auto op = (*this)[pos - 1].sub.op;
335  auto sz = (*this)[pos - 1].sub.size;
336  if (other[pos - 1].sub.op != op ||
337  other[pos - 1].sub.size != sz)
338  return false;
339  switch (op)
340  {
341  case acc_cond::acc_op::And:
342  case acc_cond::acc_op::Or:
343  --pos;
344  break;
345  case acc_cond::acc_op::Inf:
346  case acc_cond::acc_op::InfNeg:
347  case acc_cond::acc_op::Fin:
348  case acc_cond::acc_op::FinNeg:
349  pos -= 2;
350  if (other[pos].mark != (*this)[pos].mark)
351  return false;
352  break;
353  }
354  }
355  return true;
356  };
357 
358  bool operator<(const acc_code& other) const
359  {
360  unsigned pos = size();
361  auto osize = other.size();
362  if (pos < osize)
363  return true;
364  if (pos > osize)
365  return false;
366  while (pos > 0)
367  {
368  auto op = (*this)[pos - 1].sub.op;
369  auto oop = other[pos - 1].sub.op;
370  if (op < oop)
371  return true;
372  if (op > oop)
373  return false;
374  auto sz = (*this)[pos - 1].sub.size;
375  auto osz = other[pos - 1].sub.size;
376  if (sz < osz)
377  return true;
378  if (sz > osz)
379  return false;
380  switch (op)
381  {
382  case acc_cond::acc_op::And:
383  case acc_cond::acc_op::Or:
384  --pos;
385  break;
386  case acc_cond::acc_op::Inf:
387  case acc_cond::acc_op::InfNeg:
388  case acc_cond::acc_op::Fin:
389  case acc_cond::acc_op::FinNeg:
390  pos -= 2;
391  auto m = (*this)[pos].mark;
392  auto om = other[pos].mark;
393  if (m < om)
394  return true;
395  if (m > om)
396  return false;
397  break;
398  }
399  }
400  return false;
401  }
402 
403  bool operator>(const acc_code& other) const
404  {
405  return other < *this;
406  }
407 
408  bool operator<=(const acc_code& other) const
409  {
410  return !(other < *this);
411  }
412 
413  bool operator>=(const acc_code& other) const
414  {
415  return !(*this < other);
416  }
417 
418  bool operator!=(const acc_code& other) const
419  {
420  return !(*this == other);
421  }
422 
423  bool is_t() const
424  {
425  unsigned s = size();
426  return s == 0 || ((*this)[s - 1].sub.op == acc_op::Inf
427  && (*this)[s - 2].mark == 0U);
428  }
429 
430  bool is_f() const
431  {
432  unsigned s = size();
433  return s > 1
434  && (*this)[s - 1].sub.op == acc_op::Fin && (*this)[s - 2].mark == 0U;
435  }
436 
437  static acc_code f()
438  {
439  acc_code res;
440  res.resize(2);
441  res[0].mark = 0U;
442  res[1].sub.op = acc_op::Fin;
443  res[1].sub.size = 1;
444  return res;
445  }
446 
447  static acc_code t()
448  {
449  return {};
450  }
451 
452  static acc_code fin(mark_t m)
453  {
454  acc_code res;
455  res.resize(2);
456  res[0].mark = m;
457  res[1].sub.op = acc_op::Fin;
458  res[1].sub.size = 1;
459  return res;
460  }
461 
462  static acc_code fin(std::initializer_list<unsigned> vals)
463  {
464  return fin(mark_t(vals));
465  }
466 
467  static acc_code fin_neg(mark_t m)
468  {
469  acc_code res;
470  res.resize(2);
471  res[0].mark = m;
472  res[1].sub.op = acc_op::FinNeg;
473  res[1].sub.size = 1;
474  return res;
475  }
476 
477  static acc_code fin_neg(std::initializer_list<unsigned> vals)
478  {
479  return fin_neg(mark_t(vals));
480  }
481 
482  static acc_code inf(mark_t m)
483  {
484  acc_code res;
485  res.resize(2);
486  res[0].mark = m;
487  res[1].sub.op = acc_op::Inf;
488  res[1].sub.size = 1;
489  return res;
490  }
491 
492  static acc_code inf(std::initializer_list<unsigned> vals)
493  {
494  return inf(mark_t(vals));
495  }
496 
497  static acc_code inf_neg(mark_t m)
498  {
499  acc_code res;
500  res.resize(2);
501  res[0].mark = m;
502  res[1].sub.op = acc_op::InfNeg;
503  res[1].sub.size = 1;
504  return res;
505  }
506 
507  static acc_code inf_neg(std::initializer_list<unsigned> vals)
508  {
509  return inf_neg(mark_t(vals));
510  }
511 
512  static acc_code buchi()
513  {
514  return inf({0});
515  }
516 
517  static acc_code cobuchi()
518  {
519  return fin({0});
520  }
521 
522  static acc_code generalized_buchi(unsigned n)
523  {
524  acc_cond::mark_t m = (1U << n) - 1;
525  if (n == 8 * sizeof(mark_t::value_t))
526  m = mark_t(-1U);
527  return inf(m);
528  }
529 
530  static acc_code generalized_co_buchi(unsigned n)
531  {
532  acc_cond::mark_t m = (1U << n) - 1;
533  if (n == 8 * sizeof(mark_t::value_t))
534  m = mark_t(-1U);
535  return fin(m);
536  }
537 
538  // n is a number of pairs.
539  static acc_code rabin(unsigned n)
540  {
541  acc_cond::acc_code res = f();
542  while (n > 0)
543  {
544  res |= inf({2*n - 1}) & fin({2*n - 2});
545  --n;
546  }
547  return res;
548  }
549 
550  // n is a number of pairs.
551  static acc_code streett(unsigned n)
552  {
553  acc_cond::acc_code res = t();
554  while (n > 0)
555  {
556  res &= inf({2*n - 1}) | fin({2*n - 2});
557  --n;
558  }
559  return res;
560  }
561 
562  template<class Iterator>
563  static acc_code generalized_rabin(Iterator begin, Iterator end)
564  {
565  acc_cond::acc_code res = f();
566  unsigned n = 0;
567  for (Iterator i = begin; i != end; ++i)
568  {
569  acc_cond::acc_code pair = fin({n++});
570  acc_cond::mark_t m = 0U;
571  for (unsigned ni = *i; ni > 0; --ni)
572  m.set(n++);
573  pair &= inf(m);
574  std::swap(pair, res);
575  res |= std::move(pair);
576  }
577  return res;
578  }
579 
580  static acc_code parity(bool max, bool odd, unsigned sets);
581 
582  // Number of acceptance sets to use, and probability to reuse
583  // each set another time after it has been used in the
584  // acceptance formula.
585  static acc_code random(unsigned n, double reuse = 0.0);
586 
587  acc_code& operator&=(acc_code&& r)
588  {
589  if (is_t() || r.is_f())
590  {
591  *this = std::move(r);
592  return *this;
593  }
594  if (is_f() || r.is_t())
595  return *this;
596  unsigned s = size() - 1;
597  unsigned rs = r.size() - 1;
598  // We want to group all Inf(x) operators:
599  // Inf(a) & Inf(b) = Inf(a & b)
600  if (((*this)[s].sub.op == acc_op::Inf
601  && r[rs].sub.op == acc_op::Inf)
602  || ((*this)[s].sub.op == acc_op::InfNeg
603  && r[rs].sub.op == acc_op::InfNeg))
604  {
605  (*this)[s - 1].mark |= r[rs - 1].mark;
606  return *this;
607  }
608 
609  // In the more complex scenarios, left and right may both
610  // be conjunctions, and Inf(x) might be a member of each
611  // side. Find it if it exists.
612  // left_inf points to the left Inf mark if any.
613  // right_inf points to the right Inf mark if any.
614  acc_word* left_inf = nullptr;
615  if ((*this)[s].sub.op == acc_op::And)
616  {
617  auto start = &(*this)[s] - (*this)[s].sub.size;
618  auto pos = &(*this)[s] - 1;
619  pop_back();
620  while (pos > start)
621  {
622  if (pos->sub.op == acc_op::Inf)
623  {
624  left_inf = pos - 1;
625  break;
626  }
627  pos -= pos->sub.size + 1;
628  }
629  }
630  else if ((*this)[s].sub.op == acc_op::Inf)
631  {
632  left_inf = &(*this)[s - 1];
633  }
634 
635  acc_word* right_inf = nullptr;
636  auto right_end = &r.back();
637  if (right_end->sub.op == acc_op::And)
638  {
639  auto start = &r[0];
640  auto pos = --right_end;
641  while (pos > start)
642  {
643  if (pos->sub.op == acc_op::Inf)
644  {
645  right_inf = pos - 1;
646  break;
647  }
648  pos -= pos->sub.size + 1;
649  }
650  }
651  else if (right_end->sub.op == acc_op::Inf)
652  {
653  right_inf = right_end - 1;
654  }
655 
656  if (left_inf && right_inf)
657  {
658  left_inf->mark |= right_inf->mark;
659  insert(this->end(), &r[0], right_inf);
660  insert(this->end(), right_inf + 2, right_end + 1);
661  }
662  else if (right_inf)
663  {
664  // Always insert Inf() at the very first entry.
665  insert(this->begin(), right_inf, right_inf + 2);
666  insert(this->end(), &r[0], right_inf);
667  insert(this->end(), right_inf + 2, right_end + 1);
668  }
669  else
670  {
671  insert(this->end(), &r[0], right_end + 1);
672  }
673 
674  acc_word w;
675  w.sub.op = acc_op::And;
676  w.sub.size = size();
677  emplace_back(w);
678  return *this;
679  }
680 
681  acc_code& operator&=(const acc_code& r)
682  {
683  if (is_t() || r.is_f())
684  {
685  *this = r;
686  return *this;
687  }
688  if (is_f() || r.is_t())
689  return *this;
690  unsigned s = size() - 1;
691  unsigned rs = r.size() - 1;
692  // Inf(a) & Inf(b) = Inf(a & b)
693  if (((*this)[s].sub.op == acc_op::Inf
694  && r[rs].sub.op == acc_op::Inf)
695  || ((*this)[s].sub.op == acc_op::InfNeg
696  && r[rs].sub.op == acc_op::InfNeg))
697  {
698  (*this)[s - 1].mark |= r[rs - 1].mark;
699  return *this;
700  }
701 
702  // In the more complex scenarios, left and right may both
703  // be conjunctions, and Inf(x) might be a member of each
704  // side. Find it if it exists.
705  // left_inf points to the left Inf mark if any.
706  // right_inf points to the right Inf mark if any.
707  acc_word* left_inf = nullptr;
708  if ((*this)[s].sub.op == acc_op::And)
709  {
710  auto start = &(*this)[s] - (*this)[s].sub.size;
711  auto pos = &(*this)[s] - 1;
712  pop_back();
713  while (pos > start)
714  {
715  if (pos->sub.op == acc_op::Inf)
716  {
717  left_inf = pos - 1;
718  break;
719  }
720  pos -= pos->sub.size + 1;
721  }
722  }
723  else if ((*this)[s].sub.op == acc_op::Inf)
724  {
725  left_inf = &(*this)[s - 1];
726  }
727 
728  const acc_word* right_inf = nullptr;
729  auto right_end = &r.back();
730  if (right_end->sub.op == acc_op::And)
731  {
732  auto start = &r[0];
733  auto pos = --right_end;
734  while (pos > start)
735  {
736  if (pos->sub.op == acc_op::Inf)
737  {
738  right_inf = pos - 1;
739  break;
740  }
741  pos -= pos->sub.size + 1;
742  }
743  }
744  else if (right_end->sub.op == acc_op::Inf)
745  {
746  right_inf = right_end - 1;
747  }
748 
749  if (left_inf && right_inf)
750  {
751  left_inf->mark |= right_inf->mark;
752  insert(this->end(), &r[0], right_inf);
753  insert(this->end(), right_inf + 2, right_end + 1);
754  }
755  else if (right_inf)
756  {
757  // Always insert Inf() at the very first entry.
758  insert(this->begin(), right_inf, right_inf + 2);
759  insert(this->end(), &r[0], right_inf);
760  insert(this->end(), right_inf + 2, right_end + 1);
761  }
762  else
763  {
764  insert(this->end(), &r[0], right_end + 1);
765  }
766 
767  acc_word w;
768  w.sub.op = acc_op::And;
769  w.sub.size = size();
770  emplace_back(w);
771  return *this;
772  }
773 
774  acc_code operator&(acc_code&& r)
775  {
776  acc_code res = *this;
777  res &= r;
778  return res;
779  }
780 
781  acc_code operator&(const acc_code& r)
782  {
783  acc_code res = *this;
784  res &= r;
785  return res;
786  }
787 
788  acc_code& operator|=(acc_code&& r)
789  {
790  if (is_t() || r.is_f())
791  return *this;
792  if (is_f() || r.is_t())
793  {
794  *this = std::move(r);
795  return *this;
796  }
797  unsigned s = size() - 1;
798  unsigned rs = r.size() - 1;
799  // Fin(a) | Fin(b) = Fin(a | b)
800  if (((*this)[s].sub.op == acc_op::Fin
801  && r[rs].sub.op == acc_op::Fin)
802  || ((*this)[s].sub.op == acc_op::FinNeg
803  && r[rs].sub.op == acc_op::FinNeg))
804  {
805  (*this)[s - 1].mark |= r[rs - 1].mark;
806  return *this;
807  }
808  if ((*this)[s].sub.op == acc_op::Or)
809  pop_back();
810  if (r.back().sub.op == acc_op::Or)
811  r.pop_back();
812  insert(this->end(), r.begin(), r.end());
813  acc_word w;
814  w.sub.op = acc_op::Or;
815  w.sub.size = size();
816  emplace_back(w);
817  return *this;
818  }
819 
820  acc_code& operator|=(const acc_code& r)
821  {
822  return *this |= acc_code(r);
823  }
824 
825  acc_code operator|(acc_code&& r)
826  {
827  acc_code res = *this;
828  res |= r;
829  return res;
830  }
831 
832  acc_code operator|(const acc_code& r)
833  {
834  acc_code res = *this;
835  res |= r;
836  return res;
837  }
838 
839  acc_code& operator<<=(unsigned sets)
840  {
841  if (empty())
842  return *this;
843  unsigned pos = size();
844  do
845  {
846  switch ((*this)[pos - 1].sub.op)
847  {
848  case acc_cond::acc_op::And:
849  case acc_cond::acc_op::Or:
850  --pos;
851  break;
852  case acc_cond::acc_op::Inf:
853  case acc_cond::acc_op::InfNeg:
854  case acc_cond::acc_op::Fin:
855  case acc_cond::acc_op::FinNeg:
856  pos -= 2;
857  (*this)[pos].mark.id <<= sets;
858  break;
859  }
860  }
861  while (pos > 0);
862  return *this;
863  }
864 
865  acc_code operator<<(unsigned sets) const
866  {
867  acc_code res = *this;
868  res <<= sets;
869  return res;
870  }
871 
872  bool is_dnf() const;
873  bool is_cnf() const;
874 
875  acc_code to_dnf() const;
876  acc_code to_cnf() const;
877 
878  acc_code complement() const;
879 
880  // Return a list of acceptance marks needed to close a cycle
881  // that already visit INF infinitely often, so that the cycle is
882  // accepting (ACCEPTING=true) or rejecting (ACCEPTING=false).
883  // Positive values describe positive set.
884  // A negative value x means the set -x-1 must be absent.
885  std::vector<std::vector<int>>
886  missing(mark_t inf, bool accepting) const;
887 
888  bool accepting(mark_t inf) const;
889 
890  bool inf_satisfiable(mark_t inf) const;
891 
892  // Remove all the acceptance sets in rem.
893  //
894  // If MISSING is set, the acceptance sets are assumed to be
895  // missing from the automaton, and the acceptance is updated to
896  // reflect this. For instance (Inf(1)&Inf(2))|Fin(3) will
897  // become Fin(3) if we remove 2 because it is missing from this
898  // automaton, because there is no way to fulfill Inf(1)&Inf(2)
899  // in this case. So essentially MISSING causes Inf(rem) to
900  // become f, and Fin(rem) to become t.
901  //
902  // If MISSING is unset, Inf(rem) become t while Fin(rem) become
903  // f. Removing 2 from (Inf(1)&Inf(2))|Fin(3) would then give
904  // Inf(1)|Fin(3).
905  acc_code strip(acc_cond::mark_t rem, bool missing) const;
906 
907  // Return the set of sets appearing in the condition.
908  acc_cond::mark_t used_sets() const;
909 
910  // Return the sets used as Inf or Fin in the acceptance condition
911  std::pair<acc_cond::mark_t, acc_cond::mark_t> used_inf_fin_sets() const;
912 
913  // Print the acceptance as HTML. The set_printer function can
914  // be used to implement customized output for set numbers.
915  std::ostream&
916  to_html(std::ostream& os,
917  std::function<void(std::ostream&, int)>
918  set_printer = nullptr) const;
919 
920  // Print the acceptance as text. The set_printer function can
921  // be used to implement customized output for set numbers.
922  std::ostream&
923  to_text(std::ostream& os,
924  std::function<void(std::ostream&, int)>
925  set_printer = nullptr) const;
926 
927 
950  acc_code(const char* input);
951 
956  {
957  }
958 
959  // Calls to_text
960  SPOT_API
961  friend std::ostream& operator<<(std::ostream& os, const acc_code& code);
962  };
963 
964  acc_cond(unsigned n_sets = 0, const acc_code& code = {})
965  : num_(0U), all_(0U), code_(code)
966  {
967  add_sets(n_sets);
968  uses_fin_acceptance_ = check_fin_acceptance();
969  }
970 
971  acc_cond(const acc_code& code)
972  : num_(0U), all_(0U), code_(code)
973  {
974  add_sets(code.used_sets().max_set());
975  uses_fin_acceptance_ = check_fin_acceptance();
976  }
977 
978  acc_cond(const acc_cond& o)
979  : num_(o.num_), all_(o.all_), code_(o.code_),
980  uses_fin_acceptance_(o.uses_fin_acceptance_)
981  {
982  }
983 
984  acc_cond& operator=(const acc_cond& o)
985  {
986  num_ = o.num_;
987  all_ = o.all_;
988  code_ = o.code_;
989  uses_fin_acceptance_ = o.uses_fin_acceptance_;
990  return *this;
991  }
992 
993  ~acc_cond()
994  {
995  }
996 
997  void set_acceptance(const acc_code& code)
998  {
999  code_ = code;
1000  uses_fin_acceptance_ = check_fin_acceptance();
1001  }
1002 
1003  const acc_code& get_acceptance() const
1004  {
1005  return code_;
1006  }
1007 
1008  acc_code& get_acceptance()
1009  {
1010  return code_;
1011  }
1012 
1013  bool uses_fin_acceptance() const
1014  {
1015  return uses_fin_acceptance_;
1016  }
1017 
1018  bool is_t() const
1019  {
1020  return code_.is_t();
1021  }
1022 
1023  bool is_all() const
1024  {
1025  return num_ == 0 && is_t();
1026  }
1027 
1028  bool is_f() const
1029  {
1030  return code_.is_f();
1031  }
1032 
1033  bool is_none() const
1034  {
1035  return num_ == 0 && is_f();
1036  }
1037 
1038  bool is_buchi() const
1039  {
1040  unsigned s = code_.size();
1041  return num_ == 1 &&
1042  s == 2 && code_[1].sub.op == acc_op::Inf && code_[0].mark == all_sets();
1043  }
1044 
1045  bool is_co_buchi() const
1046  {
1047  return num_ == 1 && is_generalized_co_buchi();
1048  }
1049 
1050  void set_generalized_buchi()
1051  {
1052  set_acceptance(inf(all_sets()));
1053  }
1054 
1055  bool is_generalized_buchi() const
1056  {
1057  unsigned s = code_.size();
1058  return (s == 0 && num_ == 0) || (s == 2 && code_[1].sub.op == acc_op::Inf
1059  && code_[0].mark == all_sets());
1060  }
1061 
1062  bool is_generalized_co_buchi() const
1063  {
1064  unsigned s = code_.size();
1065  return (s == 2 &&
1066  code_[1].sub.op == acc_op::Fin && code_[0].mark == all_sets());
1067  }
1068 
1069  // Returns a number of pairs (>=0) if Rabin, or -1 else.
1070  int is_rabin() const;
1071  // Returns a number of pairs (>=0) if Streett, or -1 else.
1072  int is_streett() const;
1073 
1074  // Return the number of Inf in each pair.
1075  bool is_generalized_rabin(std::vector<unsigned>& pairs) const;
1076 
1077  // If EQUIV is false, this return true iff the acceptance
1078  // condition is a parity condition written in the canonical way
1079  // given in the HOA specifications. If EQUIV is true, then we
1080  // check whether the condition is logically equivalent to some
1081  // parity acceptance condition.
1082  bool is_parity(bool& max, bool& odd, bool equiv = false) const;
1083  bool is_parity() const
1084  {
1085  bool max;
1086  bool min;
1087  return is_parity(max, min);
1088  }
1089 
1090  // Return (true, m) if there exist some acceptance mark m that
1091  // does not satisfy the acceptance condition. Return (false, 0U)
1092  // otherwise.
1093  std::pair<bool, acc_cond::mark_t> unsat_mark() const;
1094 
1095  protected:
1096  bool check_fin_acceptance() const;
1097 
1098  public:
1099  static acc_code inf(mark_t mark)
1100  {
1101  return acc_code::inf(mark);
1102  }
1103 
1104  static acc_code inf(std::initializer_list<unsigned> vals)
1105  {
1106  return inf(mark_t(vals.begin(), vals.end()));
1107  }
1108 
1109  static acc_code inf_neg(mark_t mark)
1110  {
1111  return acc_code::inf_neg(mark);
1112  }
1113 
1114  static acc_code inf_neg(std::initializer_list<unsigned> vals)
1115  {
1116  return inf_neg(mark_t(vals.begin(), vals.end()));
1117  }
1118 
1119  static acc_code fin(mark_t mark)
1120  {
1121  return acc_code::fin(mark);
1122  }
1123 
1124  static acc_code fin(std::initializer_list<unsigned> vals)
1125  {
1126  return fin(mark_t(vals.begin(), vals.end()));
1127  }
1128 
1129  static acc_code fin_neg(mark_t mark)
1130  {
1131  return acc_code::fin_neg(mark);
1132  }
1133 
1134  static acc_code fin_neg(std::initializer_list<unsigned> vals)
1135  {
1136  return fin_neg(mark_t(vals.begin(), vals.end()));
1137  }
1138 
1139  unsigned add_sets(unsigned num)
1140  {
1141  if (num == 0)
1142  return -1U;
1143  unsigned j = num_;
1144  num_ += num;
1145  if (num_ > 8 * sizeof(mark_t::id))
1146  throw std::runtime_error("Too many acceptance sets used.");
1147  all_ = all_sets_();
1148  return j;
1149  }
1150 
1151  unsigned add_set()
1152  {
1153  return add_sets(1);
1154  }
1155 
1156  mark_t mark(unsigned u) const
1157  {
1158  SPOT_ASSERT(u < num_sets());
1159  return 1U << u;
1160  }
1161 
1162  mark_t comp(mark_t l) const
1163  {
1164  return all_ ^ l.id;
1165  }
1166 
1167  mark_t all_sets() const
1168  {
1169  return all_;
1170  }
1171 
1172  bool accepting(mark_t inf) const
1173  {
1174  return code_.accepting(inf);
1175  }
1176 
1177  bool inf_satisfiable(mark_t inf) const
1178  {
1179  return code_.inf_satisfiable(inf);
1180  }
1181 
1182  mark_t accepting_sets(mark_t inf) const;
1183 
1184  std::ostream& format(std::ostream& os, mark_t m) const
1185  {
1186  auto a = m;
1187  if (a == 0U)
1188  return os;
1189  return os << m;
1190  }
1191 
1192  std::string format(mark_t m) const
1193  {
1194  std::ostringstream os;
1195  format(os, m);
1196  return os.str();
1197  }
1198 
1199  unsigned num_sets() const
1200  {
1201  return num_;
1202  }
1203 
1204  template<class iterator>
1205  mark_t useless(iterator begin, iterator end) const
1206  {
1207  mark_t::value_t u = 0U; // The set of useless marks.
1208  for (unsigned x = 0; x < num_; ++x)
1209  {
1210  // Skip marks that are already known to be useless.
1211  if (u & (1 << x))
1212  continue;
1213  unsigned all = all_ ^ (u | (1 << x));
1214  for (iterator y = begin; y != end; ++y)
1215  {
1216  auto v = y->id;
1217  if (v & (1 << x))
1218  {
1219  all &= v;
1220  if (!all)
1221  break;
1222  }
1223  }
1224  u |= all;
1225  }
1226  return u;
1227  }
1228 
1229  protected:
1230  mark_t::value_t all_sets_() const
1231  {
1232  if (num_ == 0)
1233  return 0;
1234  return -1U >> (8 * sizeof(mark_t::value_t) - num_);
1235  }
1236 
1237  unsigned num_;
1238  mark_t::value_t all_;
1239  acc_code code_;
1240  bool uses_fin_acceptance_ = false;
1241 
1242  };
1243 
1244  SPOT_API
1245  std::ostream& operator<<(std::ostream& os, const acc_cond& acc);
1246 }
1247 
1248 namespace std
1249 {
1250  template<>
1251  struct hash<spot::acc_cond::mark_t>
1252  {
1253  size_t operator()(spot::acc_cond::mark_t m) const
1254  {
1255  std::hash<decltype(m.id)> h;
1256  return h(m.id);
1257  }
1258  };
1259 }
Definition: graph.hh:33
Definition: formula.hh:1671
Definition: acc.hh:31
Definition: acc.hh:315
(omega-Rational) Or
acc_code()
Build an empty acceptance condition.
Definition: acc.hh:955
op
Operator types.
Definition: formula.hh:62
Definition: acc.hh:325
(omega-Rational) And
Definition: acc.hh:34

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Tue Apr 18 2017 14:42:56 for spot by doxygen 1.8.13