1 // -*- coding: utf-8 -*-
2 // Copyright (C) 2018-2020 Laboratoire de Recherche et Développement
3 // 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 #include "config.h"
21 #include <spot/twaalgos/toparity.hh>
22 #include <spot/twaalgos/sccinfo.hh>
23 
24 #include <deque>
25 #include <utility>
26 #include <spot/twa/twa.hh>
27 #include <spot/twaalgos/cleanacc.hh>
28 #include <spot/twaalgos/degen.hh>
29 #include <spot/twaalgos/toparity.hh>
30 #include <spot/twaalgos/dualize.hh>
31 #include <spot/twaalgos/isdet.hh>
32 #include <spot/twaalgos/parity.hh>
33 #include <spot/twaalgos/remfin.hh>
34 #include <spot/twaalgos/sccinfo.hh>
35 #include <spot/twaalgos/totgba.hh>
36 #include <unordered_map>
37 
38 #include <unistd.h>
39 namespace spot
40 {
41 
42   // Old version of IAR.
43   namespace
44   {
45 
46     using perm_t = std::vector<unsigned>;
47     struct iar_state
48     {
49       unsigned state;
50       perm_t perm;
51 
52       bool
operator <spot::__anonca2c3ba70111::iar_state53       operator<(const iar_state& other) const
54       {
55         return state == other.state ? perm < other.perm : state < other.state;
56       }
57     };
58 
59     template<bool is_rabin>
60     class iar_generator
61     {
62       // helper functions: access fin and inf parts of the pairs
63       // these functions negate the Streett condition to see it as a Rabin one
64       const acc_cond::mark_t&
fin(unsigned k) const65       fin(unsigned k) const
66       {
67         if (is_rabin)
68           return pairs_[k].fin;
69         else
70           return pairs_[k].inf;
71       }
72       acc_cond::mark_t
inf(unsigned k) const73       inf(unsigned k) const
74       {
75         if (is_rabin)
76           return pairs_[k].inf;
77         else
78           return pairs_[k].fin;
79       }
80     public:
iar_generator(const const_twa_graph_ptr & a,const std::vector<acc_cond::rs_pair> & p,const bool pretty_print)81       explicit iar_generator(const const_twa_graph_ptr& a,
82                              const std::vector<acc_cond::rs_pair>& p,
83                              const bool pretty_print)
84       : aut_(a)
85       , pairs_(p)
86       , scc_(scc_info(a))
87       , pretty_print_(pretty_print)
88       , state2pos_iar_states(aut_->num_states(), -1U)
89       {}
90 
91       twa_graph_ptr
run()92       run()
93       {
94         res_ = make_twa_graph(aut_->get_dict());
95         res_->copy_ap_of(aut_);
96 
97         build_iar_scc(scc_.initial());
98 
99         {
100           // resulting automaton has acceptance condition: parity max odd
101           // for Rabin-like input and parity max even for Streett-like input.
102           // with priorities ranging from 0 to 2*(nb pairs)
103           // /!\ priorities are shifted by -1 compared to the original paper
104           unsigned sets = 2 * pairs_.size() + 1;
105           res_->set_acceptance(sets, acc_cond::acc_code::parity_max(is_rabin,
106                                                                     sets));
107         }
108         {
109           unsigned s = iar2num.at(state2iar.at(aut_->get_init_state_number()));
110           res_->set_init_state(s);
111         }
112 
113         // there could be quite a number of unreachable states, prune them
114         res_->purge_unreachable_states();
115 
116         if (pretty_print_)
117         {
118           unsigned nstates = res_->num_states();
119           auto names = new std::vector<std::string>(nstates);
120           for (auto e : res_->edges())
121           {
122             unsigned s = e.src;
123             iar_state iar = num2iar.at(s);
124             std::ostringstream st;
125             st << iar.state << ' ';
126             if (iar.perm.empty())
127               st << '[';
128             char sep = '[';
129             for (unsigned h: iar.perm)
130             {
131               st << sep << h;
132               sep = ',';
133             }
134             st << ']';
135             (*names)[s] = st.str();
136           }
137           res_->set_named_prop("state-names", names);
138         }
139 
140         return res_;
141       }
142 
143       void
build_iar_scc(unsigned scc_num)144       build_iar_scc(unsigned scc_num)
145       {
146         // we are working on an SCC: the state we start from does not matter
147         unsigned init = scc_.one_state_of(scc_num);
148 
149         std::deque<iar_state> todo;
150         auto get_state = [&](const iar_state& s)
151           {
152             auto it = iar2num.find(s);
153             if (it == iar2num.end())
154               {
155                 unsigned nb = res_->new_state();
156                 iar2num[s] = nb;
157                 num2iar[nb] = s;
158                 unsigned iar_pos = iar_states.size();
159                 unsigned old_newest_pos = state2pos_iar_states[s.state];
160                 state2pos_iar_states[s.state] = iar_pos;
161                 iar_states.push_back({s, old_newest_pos});
162                 todo.push_back(s);
163                 return nb;
164               }
165             return it->second;
166           };
167 
168         auto get_other_scc = [this](unsigned state)
169           {
170             auto it = state2iar.find(state);
171             // recursively build the destination SCC if we detect that it has
172             // not been already built.
173             if (it == state2iar.end())
174               build_iar_scc(scc_.scc_of(state));
175             return iar2num.at(state2iar.at(state));
176           };
177 
178         if (scc_.is_trivial(scc_num))
179           {
180             iar_state iar_s{init, perm_t()};
181             state2iar[init] = iar_s;
182             unsigned src_num = get_state(iar_s);
183             // Do not forget to connect to subsequent SCCs
184             for (const auto& e : aut_->out(init))
185               res_->new_edge(src_num, get_other_scc(e.dst), e.cond);
186             return;
187           }
188 
189         // determine the pairs that appear in the SCC
190         auto colors = scc_.acc_sets_of(scc_num);
191         std::set<unsigned> scc_pairs;
192         for (unsigned k = 0; k != pairs_.size(); ++k)
193           if (!inf(k) || (colors & (pairs_[k].fin | pairs_[k].inf)))
194             scc_pairs.insert(k);
195 
196         perm_t p0;
197         for (unsigned k : scc_pairs)
198           p0.push_back(k);
199 
200         iar_state s0{init, p0};
201         get_state(s0); // put s0 in todo
202 
203         // the main loop
204         while (!todo.empty())
205           {
206             iar_state current = todo.front();
207             todo.pop_front();
208 
209             unsigned src_num = get_state(current);
210 
211             for (const auto& e : aut_->out(current.state))
212               {
213                 // connect to the appropriate state
214                 if (scc_.scc_of(e.dst) != scc_num)
215                   res_->new_edge(src_num, get_other_scc(e.dst), e.cond);
216                 else
217                   {
218                     // find the new permutation
219                     perm_t new_perm = current.perm;
220                     // Count pairs whose fin-part is seen on this transition
221                     unsigned seen_nb = 0;
222                     // consider the pairs for this SCC only
223                     for (unsigned k : scc_pairs)
224                       if (e.acc & fin(k))
225                         {
226                           ++seen_nb;
227                           auto it = std::find(new_perm.begin(),
228                                               new_perm.end(),
229                                               k);
230                           // move the pair in front of the permutation
231                           std::rotate(new_perm.begin(), it, it+1);
232                         }
233 
234                     iar_state dst;
235                     unsigned dst_num = -1U;
236 
237                     // Optimization: when several indices are seen in the
238                     // transition, they move at the front of new_perm in any
239                     // order. Check whether there already exists an iar_state
240                     // that matches this condition.
241 
242                     auto iar_pos = state2pos_iar_states[e.dst];
243                     while (iar_pos != -1U)
244                     {
245                       iar_state& tmp = iar_states[iar_pos].first;
246                       iar_pos = iar_states[iar_pos].second;
247                       if (std::equal(new_perm.begin() + seen_nb,
248                         new_perm.end(),
249                         tmp.perm.begin() + seen_nb))
250                       {
251                         dst = tmp;
252                         dst_num = iar2num[dst];
253                         break;
254                       }
255                     }
256                     // if such a state was not found, build it
257                     if (dst_num == -1U)
258                       {
259                         dst = iar_state{e.dst, new_perm};
260                         dst_num = get_state(dst);
261                       }
262 
263                     // find the maximal index encountered by this transition
264                     unsigned maxint = -1U;
265                     for (int k = current.perm.size() - 1; k >= 0; --k)
266                       {
267                         unsigned pk = current.perm[k];
268                         if (!inf(pk) ||
269                             (e.acc & (pairs_[pk].fin | pairs_[pk].inf))) {
270                               maxint = k;
271                               break;
272                             }
273                       }
274 
275                     acc_cond::mark_t acc = {};
276                     if (maxint == -1U)
277                       acc = {0};
278                     else if (e.acc & fin(current.perm[maxint]))
279                       acc = {2*maxint+2};
280                     else
281                       acc = {2*maxint+1};
282 
283                     res_->new_edge(src_num, dst_num, e.cond, acc);
284                   }
285               }
286           }
287 
288         // Optimization: find the bottom SCC of the sub-automaton we have just
289         // built. To that end, we have to ignore edges going out of scc_num.
290         auto leaving_edge = [&](unsigned d)
291           {
292             return scc_.scc_of(num2iar.at(d).state) != scc_num;
293           };
294         auto filter_edge = [](const twa_graph::edge_storage_t&,
295                               unsigned dst,
296                               void* filter_data)
297           {
298             decltype(leaving_edge)* data =
299               static_cast<decltype(leaving_edge)*>(filter_data);
300 
301             if ((*data)(dst))
302               return scc_info::edge_filter_choice::ignore;
303             return scc_info::edge_filter_choice::keep;
304           };
305         scc_info sub_scc(res_, get_state(s0), filter_edge, &leaving_edge);
306         // SCCs are numbered in reverse topological order, so the bottom SCC has
307         // index 0.
308         const unsigned bscc = 0;
309         assert(sub_scc.succ(0).empty());
310         assert(
311             [&]()
312             {
313               for (unsigned s = 1; s != sub_scc.scc_count(); ++s)
314                 if (sub_scc.succ(s).empty())
315                   return false;
316               return true;
317             } ());
318 
319         assert(sub_scc.states_of(bscc).size()
320             >= scc_.states_of(scc_num).size());
321 
322         // update state2iar
323         for (unsigned scc_state : sub_scc.states_of(bscc))
324           {
325             iar_state& iar = num2iar.at(scc_state);
326             if (state2iar.find(iar.state) == state2iar.end())
327               state2iar[iar.state] = iar;
328           }
329       }
330 
331     private:
332       const const_twa_graph_ptr& aut_;
333       const std::vector<acc_cond::rs_pair>& pairs_;
334       const scc_info scc_;
335       twa_graph_ptr res_;
336       bool pretty_print_;
337 
338       // to be used when entering a new SCC
339       // maps a state of aut_ onto an iar_state with the appropriate perm
340       std::map<unsigned, iar_state> state2iar;
341 
342       std::map<iar_state, unsigned> iar2num;
343       std::map<unsigned, iar_state> num2iar;
344 
345       std::vector<unsigned> state2pos_iar_states;
346       std::vector<std::pair<iar_state, unsigned>> iar_states;
347     };
348 
349     // Make this a function different from iar_maybe(), so that
350     // iar() does not have to call a deprecated function.
351     static twa_graph_ptr
iar_maybe_(const const_twa_graph_ptr & aut,bool pretty_print)352     iar_maybe_(const const_twa_graph_ptr& aut, bool pretty_print)
353     {
354       std::vector<acc_cond::rs_pair> pairs;
355       if (!aut->acc().is_rabin_like(pairs))
356         if (!aut->acc().is_streett_like(pairs))
357           return nullptr;
358         else
359           {
360             iar_generator<false> gen(aut, pairs, pretty_print);
361             return gen.run();
362           }
363       else
364         {
365           iar_generator<true> gen(aut, pairs, pretty_print);
366           return gen.run();
367         }
368     }
369   }
370 
371   twa_graph_ptr
iar_maybe(const const_twa_graph_ptr & aut,bool pretty_print)372   iar_maybe(const const_twa_graph_ptr& aut, bool pretty_print)
373   {
374     return iar_maybe_(aut, pretty_print);
375   }
376 
377   twa_graph_ptr
iar(const const_twa_graph_ptr & aut,bool pretty_print)378   iar(const const_twa_graph_ptr& aut, bool pretty_print)
379   {
380     if (auto res = iar_maybe_(aut, pretty_print))
381       return res;
382     throw std::runtime_error("iar() expects Rabin-like or Streett-like input");
383   }
384 
385 // New version for paritizing
386 namespace
387 {
388 struct node
389 {
390     // A color of the permutation or a state.
391     unsigned label;
392     std::vector<node*> children;
393     // is_leaf is true if the label is a state of res_.
394     bool is_leaf;
395 
nodespot::__anonca2c3ba70711::node396     node()
397         : node(0, 0){
398     }
399 
nodespot::__anonca2c3ba70711::node400     node(int label_, bool is_leaf_)
401         : label(label_)
402         , children(0)
403         , is_leaf(is_leaf_){
404     }
405 
~nodespot::__anonca2c3ba70711::node406     ~node()
407     {
408         for (auto c : children)
409             delete c;
410     }
411 
412     // Add a permutation to the tree.
413     void
add_new_permspot::__anonca2c3ba70711::node414     add_new_perm(const std::vector<unsigned>& permu, int pos, unsigned state)
415     {
416         if (pos == -1)
417             children.push_back(new node(state, true));
418         else
419         {
420             auto lab = permu[pos];
421             auto child = std::find_if(children.begin(), children.end(),
422                 [lab](node* n){
423                     return n->label == lab;
424                 });
425             if (child == children.end())
426             {
427                 node* new_child = new node(lab, false);
428                 children.push_back(new_child);
429                 new_child->add_new_perm(permu, pos - 1, state);
430             }
431             else
432                 (*child)->add_new_perm(permu, pos - 1, state);
433         }
434     }
435 
436     node*
get_sub_treespot::__anonca2c3ba70711::node437     get_sub_tree(const std::vector<unsigned>& elements, int pos)
438     {
439         if (pos < 0)
440             return this;
441         unsigned lab = elements[pos];
442         auto child = std::find_if(children.begin(), children.end(),
443                 [lab](node* n){
444                     return n->label == lab;
445                 });
446         assert(child != children.end());
447         return (*child)->get_sub_tree(elements, pos - 1);
448     }
449 
450     // Gives a state of res_ (if it exists) reachable from this node.
451     // If use_last is true, we take the most recent, otherwise we take
452     // the oldest.
453     unsigned
get_endspot::__anonca2c3ba70711::node454     get_end(bool use_last)
455     {
456         if (children.empty())
457         {
458             if (!is_leaf)
459                 return -1U;
460             return label;
461         }
462         if (use_last)
463             return children[children.size() - 1]->get_end(use_last);
464         return children[0]->get_end(use_last);
465     }
466 
467     // Try to find a state compatible with the permu when seen_nb colors are
468     // moved.
469     unsigned
get_existingspot::__anonca2c3ba70711::node470     get_existing(const std::vector<unsigned>& permu, unsigned seen_nb, int pos,
471                  bool use_last)
472     {
473         if (pos < (int) seen_nb)
474             return get_end(use_last);
475         else
476         {
477             auto lab = permu[pos];
478             auto child = std::find_if(children.begin(), children.end(),
479                 [lab](node* n){
480                     return n->label == lab;
481                 });
482             if (child == children.end())
483                 return -1U;
484             return (*child)->get_existing(permu, seen_nb, pos - 1, use_last);
485         }
486     }
487 };
488 
489 class state_2_car_scc
490 {
491 std::vector<node> nodes;
492 
493 public:
state_2_car_scc(unsigned nb_states)494 state_2_car_scc(unsigned nb_states)
495     : nodes(nb_states, node()){
496 }
497 
498 // Try to find a state compatible with the permu when seen_nb colors are
499 // moved. If use_last is true, it return the last created compatible state.
500 // If it is false, it returns the oldest.
501 unsigned
get_res_state(unsigned state,const std::vector<unsigned> & permu,unsigned seen_nb,bool use_last)502 get_res_state(unsigned state, const std::vector<unsigned>& permu,
503               unsigned seen_nb, bool use_last)
504 {
505     return nodes[state].get_existing(permu, seen_nb,
506                                      permu.size() - 1, use_last);
507 }
508 
509 void
add_res_state(unsigned initial,unsigned state,const std::vector<unsigned> & permu)510 add_res_state(unsigned initial, unsigned state,
511               const std::vector<unsigned>& permu)
512 {
513     nodes[initial].add_new_perm(permu, ((int) permu.size()) - 1, state);
514 }
515 
516 node*
get_sub_tree(const std::vector<unsigned> & elements,unsigned state)517 get_sub_tree(const std::vector<unsigned>& elements, unsigned state)
518 {
519     return nodes[state].get_sub_tree(elements, elements.size() - 1);
520 }
521 };
522 
523 class car_generator
524 {
525 enum algorithm {
526     // Try to have a Büchi condition if we have Rabin.
527     Rabin_to_Buchi,
528     Streett_to_Buchi,
529     // IAR
530     IAR_Streett,
531     IAR_Rabin,
532     // CAR
533     CAR,
534     // Changing colors transforms acceptance to max even/odd copy.
535     Copy_even,
536     Copy_odd,
537     // If a condition is "t" or "f", we just have to copy the automaton.
538     False_clean,
539     True_clean,
540     None
541 };
542 
543 
544 static std::string
algorithm_to_str(algorithm algo)545 algorithm_to_str(algorithm algo)
546 {
547     std::string algo_str;
548     switch (algo)
549     {
550     case IAR_Streett:
551         algo_str = "IAR (Streett)";
552         break;
553     case IAR_Rabin:
554         algo_str = "IAR (Rabin)";
555         break;
556     case CAR:
557         algo_str = "CAR";
558         break;
559     case Copy_even:
560         algo_str = "Copy even";
561         break;
562     case Copy_odd:
563         algo_str = "Copy odd";
564         break;
565     case False_clean:
566         algo_str = "False clean";
567         break;
568     case True_clean:
569         algo_str = "True clean";
570         break;
571     case Streett_to_Buchi:
572         algo_str = "Streett to Büchi";
573         break;
574     case Rabin_to_Buchi:
575         algo_str = "Rabin to Büchi";
576         break;
577     default:
578         algo_str = "None";
579         break;
580     }
581     return algo_str;
582 }
583 
584 using perm_t = std::vector<unsigned>;
585 
586 struct car_state
587 {
588     // State of the original automaton
589     unsigned state;
590     // We create a new automaton for each SCC of the original automaton
591     // so we keep a link between a car_state and the state of the
592     // subautomaton.
593     unsigned state_scc;
594     // Permutation used by IAR and CAR.
595     perm_t perm;
596 
597     bool
operator <spot::__anonca2c3ba70711::car_generator::car_state598     operator<(const car_state &other) const
599     {
600         if (state < other.state)
601             return true;
602         if (state > other.state)
603             return false;
604         if (perm < other.perm)
605             return true;
606         if (perm > other.perm)
607             return false;
608         return state_scc < other.state_scc;
609     }
610 
611     std::string
to_stringspot::__anonca2c3ba70711::car_generator::car_state612     to_string(algorithm algo) const
613     {
614         std::stringstream s;
615         s << state;
616         unsigned ps = perm.size();
617         if (ps > 0)
618         {
619             s << " [";
620             for (unsigned i = 0; i != ps; ++i)
621             {
622                 if (i > 0)
623                     s << ',';
624                 s << perm[i];
625             }
626             s << ']';
627         }
628         s << ", ";
629         s << algorithm_to_str(algo);
630         return s.str();
631     }
632 };
633 
634 const acc_cond::mark_t &
fin(const std::vector<acc_cond::rs_pair> & pairs,unsigned k,algorithm algo) const635 fin(const std::vector<acc_cond::rs_pair>& pairs, unsigned k, algorithm algo)
636 const
637 {
638     if (algo == IAR_Rabin)
639         return pairs[k].fin;
640     else
641         return pairs[k].inf;
642 }
643 
644 acc_cond::mark_t
inf(const std::vector<acc_cond::rs_pair> & pairs,unsigned k,algorithm algo) const645 inf(const std::vector<acc_cond::rs_pair>& pairs, unsigned k, algorithm algo)
646 const
647 {
648     if (algo == IAR_Rabin)
649         return pairs[k].inf;
650     else
651         return pairs[k].fin;
652 }
653 
654 // Gives for each state a set of marks incoming to this state.
655 std::vector<std::set<acc_cond::mark_t>>
get_inputs_states(const twa_graph_ptr & aut)656 get_inputs_states(const twa_graph_ptr& aut)
657 {
658     auto used = aut->acc().get_acceptance().used_sets();
659     std::vector<std::set<acc_cond::mark_t>> inputs(aut->num_states());
660     for (auto e : aut->edges())
661     {
662         auto elements = e.acc & used;
663         if (elements.has_many())
664             inputs[e.dst].insert(elements);
665     }
666     return inputs;
667 }
668 
669 // Gives for each state a set of pairs incoming to this state.
670 std::vector<std::set<std::vector<unsigned>>>
get_inputs_iar(const twa_graph_ptr & aut,algorithm algo,const std::set<unsigned> & perm_elem,const std::vector<acc_cond::rs_pair> & pairs)671 get_inputs_iar(const twa_graph_ptr& aut, algorithm algo,
672                const std::set<unsigned>& perm_elem,
673                const std::vector<acc_cond::rs_pair>& pairs)
674 {
675     std::vector<std::set<std::vector<unsigned>>> inputs(aut->num_states());
676     for (auto e : aut->edges())
677     {
678         auto acc = e.acc;
679         std::vector<unsigned> new_vect;
680         for (unsigned k : perm_elem)
681             if (acc & fin(pairs, k, algo))
682                 new_vect.push_back(k);
683         std::sort(std::begin(new_vect), std::end(new_vect));
684         inputs[e.dst].insert(new_vect);
685     }
686     return inputs;
687 }
688 // Give an order from the set of marks
689 std::vector<unsigned>
group_to_vector(const std::set<acc_cond::mark_t> & group)690 group_to_vector(const std::set<acc_cond::mark_t>& group)
691 {
692     // In this function, we have for example the marks {1, 2}, {1, 2, 3}, {2}
693     // A compatible order is [2, 1, 3]
694     std::vector<acc_cond::mark_t> group_vect(group.begin(), group.end());
695 
696     // We sort the elements by inclusion. This function is called on a
697     // set of marks such that each mark is included or includes the others.
698     std::sort(group_vect.begin(), group_vect.end(),
699               [](const acc_cond::mark_t left, const acc_cond::mark_t right)
700                 {
701                     return (left != right) && ((left & right) == left);
702                 });
703     // At this moment, we have the vector [{2}, {1, 2}, {1, 2, 3}].
704     // In order to create the order, we add the elements of the first element.
705     // Then we add the elements of the second mark (without duplication), etc.
706     std::vector<unsigned> result;
707     for (auto mark : group_vect)
708     {
709         for (unsigned col : mark.sets())
710             if (std::find(result.begin(), result.end(), col) == result.end())
711                 result.push_back(col);
712     }
713     return result;
714 }
715 
716 // Give an order from the set of indices of pairs
717 std::vector<unsigned>
group_to_vector_iar(const std::set<std::vector<unsigned>> & group)718 group_to_vector_iar(const std::set<std::vector<unsigned>>& group)
719 {
720     std::vector<std::vector<unsigned>> group_vect(group.begin(), group.end());
721     for (auto& vec : group_vect)
722         std::sort(std::begin(vec), std::end(vec));
723     std::sort(group_vect.begin(), group_vect.end(),
724               [](const std::vector<unsigned> left,
725                  const std::vector<unsigned> right)
726                 {
727                     return (right != left)
728                         && std::includes(right.begin(), right.end(),
729                                          left.begin(), left.end());
730                 });
731     std::vector<unsigned> result;
732     for (auto vec : group_vect)
733         for (unsigned col : vec)
734             if (std::find(result.begin(), result.end(), col) == result.end())
735                 result.push_back(col);
736     return result;
737 }
738 
739 // Give a correspondance between a mark and an order for CAR
740 std::map<acc_cond::mark_t, std::vector<unsigned>>
get_groups(const std::set<acc_cond::mark_t> & marks_input)741 get_groups(const std::set<acc_cond::mark_t>& marks_input)
742 {
743     std::map<acc_cond::mark_t, std::vector<unsigned>> result;
744 
745     std::vector<std::set<acc_cond::mark_t>> groups;
746     for (acc_cond::mark_t mark : marks_input)
747     {
748         bool added = false;
749         for (unsigned group = 0; group < groups.size(); ++group)
750         {
751             if (std::all_of(groups[group].begin(), groups[group].end(),
752                             [mark](acc_cond::mark_t element)
753                             {
754                                 return ((element | mark) == mark)
755                                 || ((element | mark) == element);
756                             }))
757             {
758                 groups[group].insert(mark);
759                 added = true;
760                 break;
761             }
762         }
763         if (!added)
764             groups.push_back({mark});
765     }
766     for (auto& group : groups)
767     {
768         auto new_vector = group_to_vector(group);
769         for (auto mark : group)
770             result.insert({mark, new_vector});
771     }
772     return result;
773 }
774 
775 // Give a correspondance between a mark and an order for IAR
776 std::map<std::vector<unsigned>, std::vector<unsigned>>
get_groups_iar(const std::set<std::vector<unsigned>> & marks_input)777 get_groups_iar(const std::set<std::vector<unsigned>>& marks_input)
778 {
779     std::map<std::vector<unsigned>, std::vector<unsigned>> result;
780 
781     std::vector<std::set<std::vector<unsigned>>> groups;
782     for (auto vect : marks_input)
783     {
784         bool added = false;
785         for (unsigned group = 0; group < groups.size(); ++group)
786             if (std::all_of(groups[group].begin(), groups[group].end(),
787                             [vect](std::vector<unsigned> element)
788                             {
789                                 return std::includes(vect.begin(), vect.end(),
790                                                element.begin(), element.end())
791                               || std::includes(element.begin(), element.end(),
792                                                      vect.begin(), vect.end());
793                             }))
794             {
795                 groups[group].insert(vect);
796                 added = true;
797                 break;
798             }
799         if (!added)
800             groups.push_back({vect});
801     }
802     for (auto& group : groups)
803     {
804         auto new_vector = group_to_vector_iar(group);
805         for (auto vect : group)
806             result.insert({vect, new_vector});
807     }
808     return result;
809 }
810 
811 // Give for each state the correspondance between a mark and an order (CAR)
812 std::vector<std::map<acc_cond::mark_t, std::vector<unsigned>>>
get_mark_to_vector(const twa_graph_ptr & aut)813 get_mark_to_vector(const twa_graph_ptr& aut)
814 {
815     std::vector<std::map<acc_cond::mark_t, std::vector<unsigned>>> result;
816     auto inputs = get_inputs_states(aut);
817     for (unsigned state = 0; state < inputs.size(); ++state)
818         result.push_back(get_groups(inputs[state]));
819     return result;
820 }
821 
822 // Give for each state the correspondance between a mark and an order (IAR)
823 std::vector<std::map<std::vector<unsigned>, std::vector<unsigned>>>
get_iar_to_vector(const twa_graph_ptr & aut,algorithm algo,const std::set<unsigned> & perm_elem,const std::vector<acc_cond::rs_pair> & pairs)824 get_iar_to_vector(const twa_graph_ptr& aut, algorithm algo,
825                   const std::set<unsigned>& perm_elem,
826                   const std::vector<acc_cond::rs_pair>& pairs)
827 {
828     std::vector<std::map<std::vector<unsigned>, std::vector<unsigned>>> result;
829     auto inputs = get_inputs_iar(aut, algo, perm_elem, pairs);
830     for (unsigned state = 0; state < inputs.size(); ++state)
831         result.push_back(get_groups_iar(inputs[state]));
832     return result;
833 }
834 
835 public:
car_generator(const const_twa_graph_ptr & a,to_parity_options options)836 explicit car_generator(const const_twa_graph_ptr &a, to_parity_options options)
837     : aut_(a)
838     , scc_(scc_info(a))
839     , is_odd(false)
840     , options(options)
841 {
842     if (options.pretty_print)
843         names = new std::vector<std::string>();
844     else
845         names = nullptr;
846 }
847 
848 // During the creation of the states, we had to choose between a set of
849 // compatible states. But it is possible to create another compatible state
850 // after. This function checks if a compatible state was created after and
851 // use it.
852 void
change_transitions_destination(twa_graph_ptr & aut,const std::vector<unsigned> & states,std::map<unsigned,std::vector<unsigned>> & partial_history,state_2_car_scc & state_2_car)853 change_transitions_destination(twa_graph_ptr& aut,
854 const std::vector<unsigned>& states,
855 std::map<unsigned, std::vector<unsigned>>& partial_history,
856 state_2_car_scc& state_2_car)
857 {
858     for (auto s : states)
859         for (auto& edge : aut->out(s))
860         {
861             unsigned
862                 src = edge.src,
863                 dst = edge.dst;
864             // We don't change loops
865             if (src == dst)
866                 continue;
867             unsigned dst_scc = num2car[dst].state_scc;
868             auto cant_change = partial_history[aut->edge_number(edge)];
869             edge.dst = state_2_car.get_sub_tree(cant_change, dst_scc)
870                                     ->get_end(true);
871         }
872 }
873 
874 unsigned
apply_false_true_clean(const twa_graph_ptr & sub_automaton,bool is_true,const std::vector<int> & inf_fin_prefix,unsigned max_free_color,std::map<unsigned,car_state> & state2car_local,std::map<car_state,unsigned> & car2num_local)875 apply_false_true_clean(const twa_graph_ptr &sub_automaton, bool is_true,
876                        const std::vector<int>& inf_fin_prefix,
877                        unsigned max_free_color,
878                        std::map<unsigned, car_state>& state2car_local,
879                        std::map<car_state, unsigned>& car2num_local)
880 {
881     std::vector<unsigned>* init_states = sub_automaton->
882         get_named_prop<std::vector<unsigned>>("original-states");
883 
884     for (unsigned state = 0; state < sub_automaton->num_states(); ++state)
885     {
886         unsigned s_aut = (*init_states)[state];
887 
888         car_state new_car = { s_aut, state, perm_t() };
889         auto new_state = res_->new_state();
890         car2num_local[new_car] = new_state;
891         num2car.insert(num2car.begin() + new_state, new_car);
892         if (options.pretty_print)
893             names->push_back(
894                 new_car.to_string(is_true ? True_clean : False_clean));
895         state2car_local[s_aut] = new_car;
896     }
897     for (unsigned state = 0; state < sub_automaton->num_states(); ++state)
898     {
899         unsigned s_aut = (*init_states)[state];
900         car_state src = { s_aut, state, perm_t() };
901         unsigned src_state = car2num_local[src];
902         for (auto e : aut_->out(s_aut))
903         {
904             auto col = is_true ^ !is_odd;
905             if (((unsigned)col) > max_free_color)
906                 throw std::runtime_error("CAR needs more sets");
907             if (scc_.scc_of(s_aut) == scc_.scc_of(e.dst))
908             {
909                 for (auto c : e.acc.sets())
910                     if (inf_fin_prefix[c] + is_odd > col)
911                         col = inf_fin_prefix[c] + is_odd;
912                 acc_cond::mark_t cond = { (unsigned) col };
913                 res_->new_edge(
914                     src_state, car2num_local[state2car_local[e.dst]],
915                     e.cond, cond);
916             }
917         }
918     }
919     return sub_automaton->num_states();
920 }
921 
922 unsigned
apply_copy(const twa_graph_ptr & sub_automaton,const std::vector<unsigned> & permut,bool copy_odd,const std::vector<int> & inf_fin_prefix,std::map<unsigned,car_state> & state2car_local,std::map<car_state,unsigned> & car2num_local)923 apply_copy(const twa_graph_ptr &sub_automaton,
924            const std::vector<unsigned> &permut,
925            bool copy_odd,
926            const std::vector<int>& inf_fin_prefix,
927            std::map<unsigned, car_state>& state2car_local,
928            std::map<car_state, unsigned>& car2num_local)
929 {
930     std::vector<unsigned>* init_states = sub_automaton
931         ->get_named_prop<std::vector<unsigned>>("original-states");
932     for (unsigned state = 0; state < sub_automaton->num_states(); ++state)
933     {
934         car_state new_car = { (*init_states)[state], state, perm_t() };
935         auto new_state = res_->new_state();
936         car2num_local[new_car] = new_state;
937         num2car.insert(num2car.begin() + new_state, new_car);
938         state2car_local[(*init_states)[state]] = new_car;
939         if (options.pretty_print)
940             names->push_back(
941                 new_car.to_string(copy_odd ? Copy_odd : Copy_even));
942     }
943     auto cond_col = sub_automaton->acc().get_acceptance().used_sets();
944     for (unsigned s = 0; s < sub_automaton->num_states(); ++s)
945     {
946         for (auto e : sub_automaton->out(s))
947         {
948             acc_cond::mark_t mark = { };
949             int max_edge = -1;
950             for (auto col : e.acc.sets())
951             {
952                 if (cond_col.has(col))
953                     max_edge = std::max(max_edge, (int) permut[col]);
954                 if (inf_fin_prefix[col] + (is_odd || copy_odd) > max_edge)
955                     max_edge = inf_fin_prefix[col] + (is_odd || copy_odd);
956             }
957             if (max_edge != -1)
958                 mark.set((unsigned) max_edge);
959             car_state src = { (*init_states)[s], s, perm_t() },
960                       dst = { (*init_states)[e.dst], e.dst, perm_t() };
961             unsigned src_state = car2num_local[src],
962                      dst_state = car2num_local[dst];
963             res_->new_edge(src_state, dst_state, e.cond, mark);
964         }
965     }
966     return sub_automaton->num_states();
967 }
968 
969 unsigned
apply_to_Buchi(const twa_graph_ptr & sub_automaton,const twa_graph_ptr & buchi,bool is_streett_to_buchi,const std::vector<int> & inf_fin_prefix,unsigned max_free_color,std::map<unsigned,car_state> & state2car_local,std::map<car_state,unsigned> & car2num_local)970 apply_to_Buchi(const twa_graph_ptr& sub_automaton,
971                const twa_graph_ptr& buchi,
972                bool is_streett_to_buchi,
973                const std::vector<int>& inf_fin_prefix,
974                unsigned max_free_color,
975                std::map<unsigned, car_state>& state2car_local,
976                std::map<car_state, unsigned>& car2num_local)
977 {
978     std::vector<unsigned>* init_states = sub_automaton
979         ->get_named_prop<std::vector<unsigned>>("original-states");
980 
981     for (unsigned state = 0; state < buchi->num_states(); ++state)
982     {
983         car_state new_car = { (*init_states)[state], state, perm_t() };
984         auto new_state = res_->new_state();
985         car2num_local[new_car] = new_state;
986         num2car.insert(num2car.begin() + new_state, new_car);
987         state2car_local[(*init_states)[state]] = new_car;
988         if (options.pretty_print)
989             names->push_back(new_car.to_string(
990                 is_streett_to_buchi ? Streett_to_Buchi : Rabin_to_Buchi));
991     }
992     auto g = buchi->get_graph();
993     for (unsigned s = 0; s < buchi->num_states(); ++s)
994     {
995         unsigned b = g.state_storage(s).succ;
996         while (b)
997         {
998             auto& e = g.edge_storage(b);
999             auto acc = e.acc;
1000             acc <<= (is_odd + is_streett_to_buchi);
1001             if ((is_odd || is_streett_to_buchi) && acc == acc_cond::mark_t{ })
1002                 acc = { (unsigned) (is_streett_to_buchi && is_odd) };
1003             car_state src = { (*init_states)[s], s, perm_t() },
1004                       dst = { (*init_states)[e.dst], e.dst, perm_t() };
1005             unsigned src_state = car2num_local[src],
1006                      dst_state = car2num_local[dst];
1007             int col = ((int) acc.max_set()) - 1;
1008             if (col > (int) max_free_color)
1009                 throw std::runtime_error("CAR needs more sets");
1010             auto& e2 = sub_automaton->get_graph().edge_storage(b);
1011             for (auto c : e2.acc.sets())
1012             {
1013                 if (inf_fin_prefix[c] + is_odd > col)
1014                     col = inf_fin_prefix[c] + is_odd;
1015             }
1016             if (col != -1)
1017                 acc = { (unsigned) col };
1018             else
1019                 acc = {};
1020             res_->new_edge(src_state, dst_state, e.cond, acc);
1021             b = e.next_succ;
1022         }
1023     }
1024     return buchi->num_states();
1025 }
1026 
1027 // Create a permutation for the first state of a SCC (IAR)
1028 void
initial_perm_iar(std::set<unsigned> & perm_elem,perm_t & p0,algorithm algo,const acc_cond::mark_t & colors,const std::vector<acc_cond::rs_pair> & pairs)1029 initial_perm_iar(std::set<unsigned> &perm_elem, perm_t &p0,
1030                  algorithm algo, const acc_cond::mark_t &colors,
1031                  const std::vector<acc_cond::rs_pair> &pairs)
1032 {
1033     for (unsigned k = 0; k != pairs.size(); ++k)
1034         if (!inf(pairs, k, algo) || (colors & (pairs[k].fin | pairs[k].inf)))
1035         {
1036             perm_elem.insert(k);
1037             p0.push_back(k);
1038         }
1039 }
1040 
1041 // Create a permutation for the first state of a SCC (CAR)
1042 void
initial_perm_car(perm_t & p0,const acc_cond::mark_t & colors)1043 initial_perm_car(perm_t &p0, const acc_cond::mark_t &colors)
1044 {
1045     auto cont = colors.sets();
1046     p0.assign(cont.begin(), cont.end());
1047 }
1048 
1049 void
find_new_perm_iar(perm_t & new_perm,const std::vector<acc_cond::rs_pair> & pairs,const acc_cond::mark_t & acc,algorithm algo,const std::set<unsigned> & perm_elem,unsigned & seen_nb)1050 find_new_perm_iar(perm_t &new_perm,
1051                   const std::vector<acc_cond::rs_pair> &pairs,
1052                   const acc_cond::mark_t &acc,
1053                   algorithm algo, const std::set<unsigned> &perm_elem,
1054                   unsigned &seen_nb)
1055 {
1056     for (unsigned k : perm_elem)
1057         if (acc & fin(pairs, k, algo))
1058         {
1059             ++seen_nb;
1060             auto it = std::find(new_perm.begin(), new_perm.end(), k);
1061 
1062             // move the pair in front of the permutation
1063             std::rotate(new_perm.begin(), it, it + 1);
1064         }
1065 }
1066 
1067 // Given the set acc of colors appearing on an edge, create a new
1068 // permutation new_perm, and give the number seen_nb of colors moved to
1069 // the head of the permutation.
1070 void
find_new_perm_car(perm_t & new_perm,const acc_cond::mark_t & acc,unsigned & seen_nb,unsigned & h)1071 find_new_perm_car(perm_t &new_perm, const acc_cond::mark_t &acc,
1072                   unsigned &seen_nb, unsigned &h)
1073 {
1074     for (unsigned k : acc.sets())
1075     {
1076         auto it = std::find(new_perm.begin(), new_perm.end(), k);
1077         if (it != new_perm.end())
1078         {
1079             h = std::max(h, unsigned(it - new_perm.begin()) + 1);
1080             std::rotate(new_perm.begin(), it, it + 1);
1081             ++seen_nb;
1082         }
1083     }
1084 }
1085 
1086 void
get_acceptance_iar(algorithm algo,const perm_t & current_perm,const std::vector<acc_cond::rs_pair> & pairs,const acc_cond::mark_t & e_acc,acc_cond::mark_t & acc)1087 get_acceptance_iar(algorithm algo, const perm_t &current_perm,
1088                    const std::vector<acc_cond::rs_pair> &pairs,
1089                    const acc_cond::mark_t &e_acc, acc_cond::mark_t &acc)
1090 {
1091     unsigned delta_acc = (algo == IAR_Streett) && is_odd;
1092 
1093     // find the maximal index encountered by this transition
1094     unsigned maxint = -1U;
1095 
1096     for (int k = current_perm.size() - 1; k >= 0; --k)
1097     {
1098         unsigned pk = current_perm[k];
1099 
1100         if (!inf(pairs, pk,
1101                  algo)
1102             || (e_acc & (pairs[pk].fin | pairs[pk].inf)))
1103         {
1104             maxint = k;
1105             break;
1106         }
1107     }
1108     unsigned value;
1109 
1110     if (maxint == -1U)
1111         value = delta_acc;
1112     else if (e_acc & fin(pairs, current_perm[maxint], algo))
1113         value = 2 * maxint + 2 + delta_acc;
1114     else
1115         value = 2 * maxint + 1 + delta_acc;
1116     acc = { value };
1117 }
1118 
1119 void
get_acceptance_car(const acc_cond & sub_aut_cond,const perm_t & new_perm,unsigned h,acc_cond::mark_t & acc)1120 get_acceptance_car(const acc_cond &sub_aut_cond, const perm_t &new_perm,
1121                    unsigned h, acc_cond::mark_t &acc)
1122 {
1123     acc_cond::mark_t m(new_perm.begin(), new_perm.begin() + h);
1124     bool rej = !sub_aut_cond.accepting(m);
1125     unsigned value = 2 * h + rej + is_odd;
1126     acc = { value };
1127 }
1128 
1129 unsigned
apply_lar(const twa_graph_ptr & sub_automaton,unsigned init,std::vector<acc_cond::rs_pair> & pairs,algorithm algo,unsigned scc_num,const std::vector<int> & inf_fin_prefix,unsigned max_free_color,std::map<unsigned,car_state> & state2car_local,std::map<car_state,unsigned> & car2num_local,unsigned max_states)1130 apply_lar(const twa_graph_ptr &sub_automaton,
1131           unsigned init, std::vector<acc_cond::rs_pair> &pairs,
1132           algorithm algo, unsigned scc_num,
1133           const std::vector<int>& inf_fin_prefix,
1134           unsigned max_free_color,
1135           std::map<unsigned, car_state>& state2car_local,
1136           std::map<car_state, unsigned>& car2num_local,
1137           unsigned max_states)
1138 {
1139     auto maps = get_mark_to_vector(sub_automaton);
1140     // For each edge e of res_, we store the elements of the permutation
1141     // that are not moved, and we respect the order.
1142     std::map<unsigned, std::vector<unsigned>> edge_to_colors;
1143     unsigned nb_created_states = 0;
1144     auto state_2_car = state_2_car_scc(sub_automaton->num_states());
1145     std::vector<unsigned>* init_states = sub_automaton->
1146         get_named_prop<std::vector<unsigned>>("original-states");
1147     std::deque<car_state> todo;
1148     auto get_state =
1149         [&](const car_state &s){
1150             auto it = car2num_local.find(s);
1151 
1152             if (it == car2num_local.end())
1153             {
1154                 ++nb_created_states;
1155                 unsigned nb = res_->new_state();
1156                 if (options.search_ex)
1157                     state_2_car.add_res_state(s.state_scc, nb, s.perm);
1158                 car2num_local[s] = nb;
1159                 num2car.insert(num2car.begin() + nb, s);
1160 
1161                 todo.push_back(s);
1162                 if (options.pretty_print)
1163                     names->push_back(s.to_string(algo));
1164                 return nb;
1165             }
1166             return it->second;
1167         };
1168 
1169     auto colors = sub_automaton->acc().get_acceptance().used_sets();
1170     std::set<unsigned> perm_elem;
1171 
1172     perm_t p0 = { };
1173     switch (algo)
1174     {
1175     case IAR_Streett:
1176     case IAR_Rabin:
1177         initial_perm_iar(perm_elem, p0, algo, colors, pairs);
1178         break;
1179     case CAR:
1180         initial_perm_car(p0, colors);
1181         break;
1182     default:
1183         assert(false);
1184         break;
1185     }
1186 
1187     std::vector<std::map<std::vector<unsigned>, std::vector<unsigned>>>
1188     iar_maps;
1189     if (algo == IAR_Streett || algo == IAR_Rabin)
1190         iar_maps = get_iar_to_vector(sub_automaton, algo, perm_elem, pairs);
1191 
1192     car_state s0{ (*init_states)[init], init, p0 };
1193     get_state(s0);         // put s0 in todo
1194 
1195     // the main loop
1196     while (!todo.empty())
1197     {
1198         car_state current = todo.front();
1199         todo.pop_front();
1200 
1201         unsigned src_num = get_state(current);
1202         for (const auto &e : sub_automaton->out(current.state_scc))
1203         {
1204             perm_t new_perm = current.perm;
1205 
1206             // Count pairs whose fin-part is seen on this transition
1207             unsigned seen_nb = 0;
1208 
1209             // consider the pairs for this SCC only
1210             unsigned h = 0;
1211 
1212             switch (algo)
1213             {
1214             case IAR_Rabin:
1215             case IAR_Streett:
1216                 find_new_perm_iar(new_perm, pairs, e.acc, algo,
1217                                   perm_elem, seen_nb);
1218                 break;
1219             case CAR:
1220                 find_new_perm_car(new_perm, e.acc, seen_nb, h);
1221                 break;
1222             default:
1223                 assert(false);
1224             }
1225 
1226             std::vector<unsigned> not_moved(new_perm.begin() + seen_nb,
1227                                             new_perm.end());
1228 
1229             if (options.force_order)
1230             {
1231                 if (algo == CAR && seen_nb > 1)
1232                 {
1233                     auto map = maps[e.dst];
1234                     acc_cond::mark_t first_vals(
1235                         new_perm.begin(), new_perm.begin() + seen_nb);
1236                     auto new_start = map.find(first_vals);
1237                     assert(new_start->second.size() >= seen_nb);
1238                     assert(new_start != map.end());
1239                     for (unsigned i = 0; i < seen_nb; ++i)
1240                         new_perm[i] = new_start->second[i];
1241                 }
1242                 else if ((algo == IAR_Streett || algo == IAR_Rabin)
1243                         && seen_nb > 1)
1244                 {
1245                     auto map = iar_maps[e.dst];
1246                     std::vector<unsigned> first_vals(
1247                             new_perm.begin(), new_perm.begin() + seen_nb);
1248                     std::sort(std::begin(first_vals), std::end(first_vals));
1249                     auto new_start = map.find(first_vals);
1250                     assert(new_start->second.size() >= seen_nb);
1251                     assert(new_start != map.end());
1252                     for (unsigned i = 0; i < seen_nb; ++i)
1253                         new_perm[i] = new_start->second[i];
1254                 }
1255             }
1256 
1257             // Optimization: when several indices are seen in the
1258             // transition, they move at the front of new_perm in any
1259             // order. Check whether there already exists an car_state
1260             // that matches this condition.
1261             car_state dst;
1262             unsigned dst_num = -1U;
1263 
1264             if (options.search_ex)
1265                 dst_num = state_2_car.get_res_state(e.dst, new_perm, seen_nb,
1266                             options.use_last);
1267 
1268             if (dst_num == -1U)
1269             {
1270                 auto dst = car_state{ (*init_states)[e.dst], e.dst, new_perm };
1271                 dst_num = get_state(dst);
1272                 if (nb_created_states > max_states)
1273                     return -1U;
1274             }
1275 
1276             acc_cond::mark_t acc = { };
1277 
1278             switch (algo)
1279             {
1280             case IAR_Rabin:
1281             case IAR_Streett:
1282                 get_acceptance_iar(algo, current.perm, pairs, e.acc, acc);
1283                 break;
1284             case CAR:
1285                 get_acceptance_car(sub_automaton->acc(), new_perm, h, acc);
1286                 break;
1287             default:
1288                 assert(false);
1289             }
1290 
1291             unsigned acc_col = acc.min_set() - 1;
1292             if (options.parity_prefix)
1293             {
1294                 if (acc_col > max_free_color)
1295                     throw std::runtime_error("CAR needs more sets");
1296                 // parity prefix
1297                 for (auto col : e.acc.sets())
1298                 {
1299                     if (inf_fin_prefix[col] + is_odd > (int) acc_col)
1300                         acc_col = (unsigned) inf_fin_prefix[col] + is_odd;
1301                 }
1302             }
1303             auto new_e = res_->new_edge(src_num, dst_num, e.cond, { acc_col });
1304             edge_to_colors.insert({new_e, not_moved});
1305         }
1306     }
1307     if (options.search_ex && options.use_last)
1308     {
1309         std::vector<unsigned> added_states;
1310         std::transform(car2num_local.begin(), car2num_local.end(),
1311                        std::back_inserter(added_states),
1312                        [](std::pair<const car_state, unsigned> pair) {
1313                            return pair.second;
1314                        });
1315         change_transitions_destination(
1316             res_, added_states, edge_to_colors, state_2_car);
1317     }
1318     auto leaving_edge =
1319         [&](unsigned d){
1320             return scc_.scc_of(num2car.at(d).state) != scc_num;
1321         };
1322     auto filter_edge =
1323         [](const twa_graph::edge_storage_t &,
1324            unsigned dst,
1325            void* filter_data){
1326             decltype(leaving_edge) *data =
1327                 static_cast<decltype(leaving_edge)*>(filter_data);
1328 
1329             if ((*data)(dst))
1330                 return scc_info::edge_filter_choice::ignore;
1331 
1332             return scc_info::edge_filter_choice::keep;
1333         };
1334     scc_info sub_scc(res_, get_state(s0), filter_edge, &leaving_edge);
1335 
1336     // SCCs are numbered in reverse topological order, so the bottom SCC has
1337     // index 0.
1338     const unsigned bscc = 0;
1339     assert(sub_scc.scc_count() != 0);
1340     assert(sub_scc.succ(0).empty());
1341     assert(
1342         [&](){
1343                     for (unsigned s = 1; s != sub_scc.scc_count(); ++s)
1344                         if (sub_scc.succ(s).empty())
1345                             return false;
1346 
1347                     return true;
1348                 } ());
1349 
1350     assert(sub_scc.states_of(bscc).size() >= sub_automaton->num_states());
1351 
1352     // update state2car
1353     for (unsigned scc_state : sub_scc.states_of(bscc))
1354     {
1355         car_state &car = num2car.at(scc_state);
1356 
1357         if (state2car_local.find(car.state) == state2car_local.end())
1358             state2car_local[car.state] = car;
1359     }
1360     return sub_scc.states_of(bscc).size();
1361 }
1362 
1363 algorithm
chooseAlgo(twa_graph_ptr & sub_automaton,twa_graph_ptr & rabin_aut,std::vector<acc_cond::rs_pair> & pairs,std::vector<unsigned> & permut)1364 chooseAlgo(twa_graph_ptr &sub_automaton,
1365            twa_graph_ptr &rabin_aut,
1366            std::vector<acc_cond::rs_pair> &pairs,
1367            std::vector<unsigned> &permut)
1368 {
1369     auto scc_condition = sub_automaton->acc();
1370     if (options.parity_equiv)
1371     {
1372         if (scc_condition.is_f())
1373             return False_clean;
1374         if (scc_condition.is_t())
1375             return True_clean;
1376         std::vector<int> permut_tmp(scc_condition.all_sets().max_set(), -1);
1377 
1378         if (!is_odd && scc_condition.is_parity_max_equiv(permut_tmp, true))
1379         {
1380             for (auto c : permut_tmp)
1381                 permut.push_back((unsigned) c);
1382 
1383             scc_condition.apply_permutation(permut);
1384             sub_automaton->apply_permutation(permut);
1385             return Copy_even;
1386         }
1387         std::fill(permut_tmp.begin(), permut_tmp.end(), -1);
1388         if (scc_condition.is_parity_max_equiv(permut_tmp, false))
1389         {
1390             for (auto c : permut_tmp)
1391                 permut.push_back((unsigned) c);
1392             scc_condition.apply_permutation(permut);
1393             sub_automaton->apply_permutation(permut);
1394             return Copy_odd;
1395         }
1396     }
1397 
1398     if (options.rabin_to_buchi)
1399     {
1400         auto ra = rabin_to_buchi_if_realizable(sub_automaton);
1401         if (ra != nullptr)
1402         {
1403             rabin_aut = ra;
1404             return Rabin_to_Buchi;
1405         }
1406         else
1407         {
1408             bool streett_buchi = false;
1409             auto sub_cond = sub_automaton->get_acceptance();
1410             sub_automaton->set_acceptance(sub_cond.complement());
1411             auto ra = rabin_to_buchi_if_realizable(sub_automaton);
1412             streett_buchi = (ra != nullptr);
1413             sub_automaton->set_acceptance(sub_cond);
1414             if (streett_buchi)
1415             {
1416                 rabin_aut = ra;
1417                 return Streett_to_Buchi;
1418             }
1419         }
1420     }
1421 
1422     auto pairs1 = std::vector<acc_cond::rs_pair>();
1423     auto pairs2 = std::vector<acc_cond::rs_pair>();
1424     std::sort(pairs1.begin(), pairs1.end());
1425     pairs1.erase(std::unique(pairs1.begin(), pairs1.end()), pairs1.end());
1426     std::sort(pairs2.begin(), pairs2.end());
1427     pairs2.erase(std::unique(pairs2.begin(), pairs2.end()), pairs2.end());
1428     bool is_r_like = scc_condition.is_rabin_like(pairs1);
1429     bool is_s_like = scc_condition.is_streett_like(pairs2);
1430     unsigned num_cols = scc_condition.get_acceptance().used_sets().count();
1431     if (is_r_like)
1432     {
1433         if ((is_s_like && pairs1.size() < pairs2.size()) || !is_s_like)
1434         {
1435             if (pairs1.size() > num_cols)
1436                 return CAR;
1437             pairs = pairs1;
1438             return IAR_Rabin;
1439         }
1440         else if (is_s_like)
1441         {
1442             if (pairs2.size() > num_cols)
1443                 return CAR;
1444             pairs = pairs2;
1445             return IAR_Streett;
1446         }
1447     }
1448     else
1449     {
1450         if (is_s_like)
1451         {
1452             if (pairs2.size() > num_cols)
1453                 return CAR;
1454             pairs = pairs2;
1455             return IAR_Streett;
1456         }
1457     }
1458     return CAR;
1459 }
1460 
1461 unsigned
build_scc(twa_graph_ptr & sub_automaton,unsigned scc_num,std::map<unsigned,car_state> & state2car_local,std::map<car_state,unsigned> & car2num_local,algorithm & algo,unsigned max_states=-1U)1462 build_scc(twa_graph_ptr &sub_automaton,
1463           unsigned scc_num,
1464           std::map<unsigned, car_state>& state2car_local,
1465           std::map<car_state, unsigned>&car2num_local,
1466           algorithm& algo,
1467           unsigned max_states = -1U)
1468 {
1469 
1470     std::vector<int> parity_prefix_colors (SPOT_MAX_ACCSETS,
1471                                             - SPOT_MAX_ACCSETS - 2);
1472     unsigned min_prefix_color = SPOT_MAX_ACCSETS + 1;
1473     if (options.parity_prefix)
1474     {
1475         auto new_acc = sub_automaton->acc();
1476         auto colors = std::vector<unsigned>();
1477         bool inf_start =
1478             sub_automaton->acc().has_parity_prefix(new_acc, colors);
1479         sub_automaton->set_acceptance(new_acc);
1480         for (unsigned i = 0; i < colors.size(); ++i)
1481             parity_prefix_colors[colors[i]] =
1482                 SPOT_MAX_ACCSETS - 4 - i - !inf_start;
1483         if (colors.size() > 0)
1484             min_prefix_color =
1485                 SPOT_MAX_ACCSETS - 4 - colors.size() - 1 - !inf_start;
1486     }
1487     --min_prefix_color;
1488 
1489     unsigned init = 0;
1490 
1491     std::vector<acc_cond::rs_pair> pairs = { };
1492     auto permut = std::vector<unsigned>();
1493     twa_graph_ptr rabin_aut = nullptr;
1494     algo = chooseAlgo(sub_automaton, rabin_aut, pairs, permut);
1495     switch (algo)
1496     {
1497     case False_clean:
1498     case True_clean:
1499         return apply_false_true_clean(sub_automaton, (algo == True_clean),
1500                                       parity_prefix_colors, min_prefix_color,
1501                                       state2car_local, car2num_local);
1502         break;
1503     case IAR_Streett:
1504     case IAR_Rabin:
1505     case CAR:
1506         return apply_lar(sub_automaton, init, pairs, algo, scc_num,
1507                          parity_prefix_colors, min_prefix_color,
1508                          state2car_local, car2num_local, max_states);
1509         break;
1510     case Copy_odd:
1511     case Copy_even:
1512         return apply_copy(sub_automaton, permut, algo == Copy_odd,
1513                           parity_prefix_colors, state2car_local,
1514                           car2num_local);
1515         break;
1516     case Rabin_to_Buchi:
1517     case Streett_to_Buchi:
1518         return apply_to_Buchi(sub_automaton, rabin_aut,
1519                               (algo == Streett_to_Buchi),
1520                               parity_prefix_colors, min_prefix_color,
1521                               state2car_local, car2num_local);
1522         break;
1523     default:
1524         break;
1525     }
1526     return -1U;
1527 }
1528 
1529 public:
1530 twa_graph_ptr
run()1531 run()
1532 {
1533     res_ = make_twa_graph(aut_->get_dict());
1534     res_->copy_ap_of(aut_);
1535     for (unsigned scc = 0; scc < scc_.scc_count(); ++scc)
1536     {
1537         if (!scc_.is_useful_scc(scc))
1538             continue;
1539         auto sub_automata = scc_.split_on_sets(scc, { }, true);
1540         if (sub_automata.empty())
1541         {
1542             for (auto state : scc_.states_of(scc))
1543             {
1544                 auto new_state = res_->new_state();
1545                 car_state new_car = { state, state, perm_t() };
1546                 car2num[new_car] = new_state;
1547                 num2car.insert(num2car.begin() + new_state, new_car);
1548                 if (options.pretty_print)
1549                     names->push_back(new_car.to_string(None));
1550                 state2car[state] = new_car;
1551             }
1552             continue;
1553         }
1554 
1555         auto sub_automaton = sub_automata[0];
1556         auto deg = sub_automaton;
1557         if (options.acc_clean)
1558             simplify_acceptance_here(sub_automaton);
1559         bool has_degeneralized = false;
1560         if (options.partial_degen)
1561         {
1562             std::vector<acc_cond::mark_t> forbid;
1563             auto m =
1564                 is_partially_degeneralizable(sub_automaton, true,
1565                                              true, forbid);
1566             while (m != acc_cond::mark_t {})
1567             {
1568                 auto tmp = partial_degeneralize(deg, m);
1569                 simplify_acceptance_here(tmp);
1570                 if (tmp->get_acceptance().used_sets().count()
1571                     < deg->get_acceptance().used_sets().count() ||
1572                     !(options.reduce_col_deg))
1573                 {
1574                     deg = tmp;
1575                     has_degeneralized = true;
1576                 }
1577                 else
1578                     forbid.push_back(m);
1579                 m = is_partially_degeneralizable(deg, true, true, forbid);
1580             }
1581         }
1582 
1583         if (options.propagate_col)
1584         {
1585             propagate_marks_here(sub_automaton);
1586             if (deg != sub_automaton)
1587               propagate_marks_here(deg);
1588         }
1589 
1590         std::map<unsigned, car_state> state2car_sub, state2car_deg;
1591         std::map<car_state, unsigned> car2num_sub, car2num_deg;
1592 
1593         unsigned nb_states_deg = -1U,
1594                  nb_states_sub = -1U;
1595 
1596         algorithm algo_sub, algo_deg;
1597         unsigned max_states_sub_car = -1U;
1598         // We try with and without degeneralization and we keep the best.
1599         if (has_degeneralized)
1600         {
1601             nb_states_deg =
1602                 build_scc(deg, scc, state2car_deg, car2num_deg, algo_deg);
1603             // We suppose that if we see nb_states_deg + 1000 states when
1604             // when construct the version without degeneralization during the
1605             // construction, we will not be able to have nb_states_deg after
1606             // removing useless states. So we will stop the execution.
1607             max_states_sub_car =
1608                 10000 + nb_states_deg - 1;
1609         }
1610         if (!options.force_degen || !has_degeneralized)
1611             nb_states_sub =
1612                 build_scc(sub_automaton, scc, state2car_sub, car2num_sub,
1613                           algo_sub, max_states_sub_car);
1614         if (nb_states_deg < nb_states_sub)
1615         {
1616             state2car.insert(state2car_deg.begin(), state2car_deg.end());
1617             car2num.insert(car2num_deg.begin(), car2num_deg.end());
1618             algo_sub = algo_deg;
1619         }
1620         else
1621         {
1622             state2car.insert(state2car_sub.begin(), state2car_sub.end());
1623             car2num.insert(car2num_sub.begin(), car2num_sub.end());
1624         }
1625         if ((algo_sub == IAR_Rabin || algo_sub == Copy_odd) && !is_odd)
1626         {
1627             is_odd = true;
1628             for (auto &edge : res_->edges())
1629             {
1630                 if (scc_.scc_of(num2car[edge.src].state) != scc
1631                    && scc_.scc_of(num2car[edge.dst].state) != scc)
1632                 {
1633                     if (edge.acc == acc_cond::mark_t{})
1634                         edge.acc = { 0 };
1635                     else
1636                         edge.acc <<= 1;
1637                 }
1638             }
1639         }
1640     }
1641 
1642     for (unsigned state = 0; state < res_->num_states(); ++state)
1643     {
1644         unsigned original_state = num2car.at(state).state;
1645         auto state_scc = scc_.scc_of(original_state);
1646         for (auto edge : aut_->out(original_state))
1647         {
1648             if (scc_.scc_of(edge.dst) != state_scc)
1649             {
1650                 auto car = state2car.find(edge.dst);
1651                 if (car != state2car.end())
1652                 {
1653                     unsigned res_dst = car2num.at(car->second);
1654                     res_->new_edge(state, res_dst, edge.cond, { });
1655                 }
1656             }
1657         }
1658     }
1659     unsigned initial_state = aut_->get_init_state_number();
1660     auto initial_car_ptr = state2car.find(initial_state);
1661     car_state initial_car;
1662     // If we take an automaton with one state and without transition,
1663     // the SCC was useless so state2car doesn't have initial_state
1664     if (initial_car_ptr == state2car.end())
1665     {
1666         assert(res_->num_states() == 0);
1667         auto new_state = res_->new_state();
1668         car_state new_car = {initial_state, 0, perm_t()};
1669         state2car[initial_state] = new_car;
1670         if (options.pretty_print)
1671             names->push_back(new_car.to_string(None));
1672         num2car.insert(num2car.begin() + new_state, new_car);
1673         car2num[new_car] = new_state;
1674         initial_car = new_car;
1675     }
1676     else
1677         initial_car = initial_car_ptr->second;
1678     auto initial_state_res = car2num.find(initial_car);
1679     if (initial_state_res != car2num.end())
1680         res_->set_init_state(initial_state_res->second);
1681     else
1682         res_->new_state();
1683     if (options.pretty_print)
1684         res_->set_named_prop("state-names", names);
1685 
1686     res_->purge_unreachable_states();
1687     // If parity_prefix is used, we use all available colors by
1688     // default: The IAR/CAR are using lower indices, and the prefix is
1689     // using the upper indices.  So we use reduce_parity() to clear
1690     // the mess.   If parity_prefix is not used,
1691     unsigned max_color = SPOT_MAX_ACCSETS;
1692     if (!options.parity_prefix)
1693       {
1694         acc_cond::mark_t all = {};
1695         for (auto& e: res_->edges())
1696           all |= e.acc;
1697         max_color = all.max_set();
1698       }
1699     res_->set_acceptance(acc_cond::acc_code::parity_max(is_odd, max_color));
1700     if (options.parity_prefix)
1701       reduce_parity_here(res_);
1702     return res_;
1703 }
1704 
1705 private:
1706 const const_twa_graph_ptr &aut_;
1707 const scc_info scc_;
1708 twa_graph_ptr res_;
1709 // Says if we constructing an odd or even max
1710 bool is_odd;
1711 
1712 std::vector<car_state> num2car;
1713 std::map<unsigned, car_state> state2car;
1714 std::map<car_state, unsigned> car2num;
1715 
1716 to_parity_options options;
1717 
1718 std::vector<std::string>* names;
1719 }; // car_generator
1720 
1721 }// namespace
1722 
1723 
1724 twa_graph_ptr
to_parity(const const_twa_graph_ptr & aut,const to_parity_options options)1725 to_parity(const const_twa_graph_ptr &aut, const to_parity_options options)
1726 {
1727     return car_generator(aut, options).run();
1728 }
1729 
1730   // Old version of CAR.
1731   namespace
1732   {
1733     struct lar_state
1734     {
1735       unsigned state;
1736       std::vector<unsigned> perm;
1737 
operator <spot::__anonca2c3ba71411::lar_state1738       bool operator<(const lar_state& s) const
1739       {
1740         return state == s.state ? perm < s.perm : state < s.state;
1741       }
1742 
to_stringspot::__anonca2c3ba71411::lar_state1743       std::string to_string() const
1744       {
1745         std::stringstream s;
1746         s << state << " [";
1747         unsigned ps = perm.size();
1748         for (unsigned i = 0; i != ps; ++i)
1749           {
1750             if (i > 0)
1751               s << ',';
1752             s << perm[i];
1753           }
1754         s << ']';
1755         return s.str();
1756       }
1757     };
1758 
1759     class lar_generator
1760     {
1761       const const_twa_graph_ptr& aut_;
1762       twa_graph_ptr res_;
1763       const bool pretty_print;
1764 
1765       std::map<lar_state, unsigned> lar2num;
1766     public:
lar_generator(const const_twa_graph_ptr & a,bool pretty_print)1767       explicit lar_generator(const const_twa_graph_ptr& a, bool pretty_print)
1768       : aut_(a)
1769       , res_(nullptr)
1770       , pretty_print(pretty_print)
1771       {}
1772 
run()1773       twa_graph_ptr run()
1774       {
1775         res_ = make_twa_graph(aut_->get_dict());
1776         res_->copy_ap_of(aut_);
1777 
1778         std::deque<lar_state> todo;
1779         auto get_state = [this, &todo](const lar_state& s)
1780           {
1781             auto it = lar2num.emplace(s, -1U);
1782             if (it.second) // insertion took place
1783               {
1784                 unsigned nb = res_->new_state();
1785                 it.first->second = nb;
1786                 todo.push_back(s);
1787               }
1788             return it.first->second;
1789           };
1790 
1791         std::vector<unsigned> initial_perm(aut_->num_sets());
1792         std::iota(initial_perm.begin(), initial_perm.end(), 0);
1793         {
1794           lar_state s0{aut_->get_init_state_number(), initial_perm};
1795           res_->set_init_state(get_state(s0));
1796         }
1797 
1798         scc_info si(aut_, scc_info_options::NONE);
1799         // main loop
1800         while (!todo.empty())
1801           {
1802             lar_state current = todo.front();
1803             todo.pop_front();
1804 
1805             // TODO: todo could store this number to avoid one lookup
1806             unsigned src_num = get_state(current);
1807 
1808             unsigned source_scc = si.scc_of(current.state);
1809             for (const auto& e : aut_->out(current.state))
1810               {
1811                 // find the new permutation
1812                 std::vector<unsigned> new_perm = current.perm;
1813                 unsigned h = 0;
1814                 for (unsigned k : e.acc.sets())
1815                   {
1816                     auto it = std::find(new_perm.begin(), new_perm.end(), k);
1817                     h = std::max(h, unsigned(new_perm.end() - it));
1818                     std::rotate(it, it+1, new_perm.end());
1819                   }
1820 
1821                 if (source_scc != si.scc_of(e.dst))
1822                   {
1823                     new_perm = initial_perm;
1824                     h = 0;
1825                   }
1826 
1827                 lar_state dst{e.dst, new_perm};
1828                 unsigned dst_num = get_state(dst);
1829 
1830                 // Do the h last elements satisfy the acceptance condition?
1831                 // If they do, emit 2h, if they don't emit 2h+1.
1832                 acc_cond::mark_t m(new_perm.end() - h, new_perm.end());
1833                 bool rej = !aut_->acc().accepting(m);
1834                 res_->new_edge(src_num, dst_num, e.cond, {2*h + rej});
1835               }
1836           }
1837 
1838         // parity max even
1839         unsigned sets = 2*aut_->num_sets() + 2;
1840         res_->set_acceptance(sets, acc_cond::acc_code::parity_max_even(sets));
1841 
1842         if (pretty_print)
1843           {
1844             auto names = new std::vector<std::string>(res_->num_states());
1845             for (const auto& p : lar2num)
1846               (*names)[p.second] = p.first.to_string();
1847             res_->set_named_prop("state-names", names);
1848           }
1849 
1850         return res_;
1851       }
1852     };
1853   }
1854 
1855   twa_graph_ptr
to_parity_old(const const_twa_graph_ptr & aut,bool pretty_print)1856   to_parity_old(const const_twa_graph_ptr& aut, bool pretty_print)
1857   {
1858     if (!aut->is_existential())
1859       throw std::runtime_error("LAR does not handle alternation");
1860     // if aut is already parity return it as is
1861     if (aut->acc().is_parity())
1862       return std::const_pointer_cast<twa_graph>(aut);
1863 
1864     lar_generator gen(aut, pretty_print);
1865     return gen.run();
1866   }
1867 
1868 }
1869