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