LCOV - code coverage report
Current view: top level - pg/source - RecursiveSolver.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 0 95 0.0 %
Date: 2024-04-26 03:18:02 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2009-2013 University of Twente
       2             : // Copyright (c) 2009-2013 Michael Weber <michaelw@cs.utwente.nl>
       3             : // Copyright (c) 2009-2013 Maks Verver <maksverver@geocities.com>
       4             : // Copyright (c) 2009-2013 Eindhoven University of Technology
       5             : //
       6             : // Distributed under the Boost Software License, Version 1.0.
       7             : // (See accompanying file LICENSE_1_0.txt or copy at
       8             : // http://www.boost.org/LICENSE_1_0.txt)
       9             : 
      10             : #include "mcrl2/pg/attractor_impl.h"
      11             : #include "mcrl2/pg/DenseSet.h"
      12             : #include "mcrl2/pg/RecursiveSolver.h"
      13             : 
      14             : /*! Returns the complement of a vertex set.
      15             : 
      16             :     This function returns a vector of increasing vertex indices between 0 and
      17             :     V (exclusive) where 0 <= v < V is in the result iff. it is not included in
      18             :     the set s.
      19             : */
      20           0 : static std::vector<verti> get_complement(verti V, const DenseSet<verti> &s)
      21             : {
      22           0 :     std::vector<verti> res;
      23           0 :     verti n = V - s.size();
      24           0 :     res.reserve(n);
      25           0 :     DenseSet<verti>::const_iterator it = s.begin(), end = s.end();
      26           0 :     verti v = 0;
      27           0 :     while (it != end)
      28             :     {
      29           0 :         verti w = *it;
      30           0 :         while (v < w) res.push_back(v++);
      31           0 :         ++v;
      32           0 :         ++it;
      33             :     }
      34           0 :     while (v < V) res.push_back(v++);
      35           0 :     assert(n == (verti)res.size());
      36           0 :     return res;
      37           0 : }
      38             : 
      39             : /*! Returns the first inversion in parity for priorities occurring in the given
      40             :     game; i.e. the least value 'p` such that there is a priority `q` such that
      41             :     cardinality(q) > 0 && cardinality(p) > 0 && q < p && q%2 != p%2.
      42             : 
      43             :     If there are no inversions, the priority limit, d, is returned instead. */
      44           0 : int first_inversion(const ParityGame &game)
      45             : {
      46           0 :     int d = game.d();
      47           0 :     int q = 0;
      48           0 :     while (q < d && game.cardinality(q) == 0) ++q;
      49           0 :     int p = q + 1;
      50           0 :     while (p < d && game.cardinality(p) == 0) p += 2;
      51           0 :     return p < d ? p : d;
      52             : }
      53             : 
      54           0 : RecursiveSolver::RecursiveSolver(const ParityGame &game)
      55           0 :     : ParityGameSolver(game)
      56             : {
      57           0 : }
      58             : 
      59           0 : RecursiveSolver::~RecursiveSolver()
      60             : {
      61           0 : }
      62             : 
      63           0 : ParityGame::Strategy RecursiveSolver::solve()
      64             : {
      65           0 :     ParityGame game;
      66           0 :     game.assign(game_);
      67           0 :     ParityGame::Strategy strategy(game.graph().V(), NO_VERTEX);
      68           0 :     Substrategy substrat(strategy);
      69           0 :     if (!solve(game, substrat)) strategy.clear();
      70           0 :     return strategy;
      71           0 : }
      72             : 
      73             : /* Implementation note: the recursive solver might use either a DenseSet or
      74             :    a std::set to store vertex sets (which are passed to make_attractor_set).
      75             :    The former is faster when the size of these sets is large, but requires O(V)
      76             :    time and memory to initialize, which is costly when these sets are small.
      77             : 
      78             :    It seems that the benefit of faster lookups during attractor set computation
      79             :    usually tips the balance in favor of the DenseSet.
      80             : 
      81             :    Note that hash sets cannot readily be used because get_complement() expects
      82             :    iterators to produce the set contents in-order.
      83             : */
      84             : 
      85           0 : bool RecursiveSolver::solve(ParityGame &game, Substrategy &strat)
      86             : {
      87           0 :     if (aborted()) return false;
      88             : 
      89             :     std::size_t prio;
      90           0 :     while ((prio = first_inversion(game)) < game.d())
      91             :     {
      92           0 :         mCRL2log(mcrl2::log::debug) <<"prio=" << prio << std::endl;
      93             : 
      94           0 :         const StaticGraph &graph = game.graph();
      95           0 :         const verti V = graph.V();
      96           0 :         std::vector<verti> unsolved;
      97             : 
      98             :         // Compute attractor set of minimum priority vertices:
      99             :         {
     100           0 :             ParityGame::Player player = (ParityGame::Player)((prio - 1)%2);
     101             :             //std::set<verti> min_prio_attr;
     102           0 :             DenseSet<verti> min_prio_attr(0, V);
     103           0 :             for (verti v = 0; v < V; ++v)
     104             :             {
     105           0 :                 if (game.priority(v) < prio) min_prio_attr.insert(v);
     106             :             }
     107           0 :             mCRL2log(mcrl2::log::debug) <<"|min_prio|=" << min_prio_attr.size() << std::endl;
     108           0 :             assert(!min_prio_attr.empty());
     109           0 :             make_attractor_set_2(game, player, min_prio_attr, strat);
     110           0 :             mCRL2log(mcrl2::log::debug) << "|min_prio_attr|=" << min_prio_attr.size() << std::endl;
     111           0 :             if (min_prio_attr.size() == V) break;
     112           0 :             get_complement(V, min_prio_attr).swap(unsolved);
     113           0 :         }
     114             : 
     115             :         // Solve vertices not in the minimum priority attractor set:
     116             :         {
     117           0 :             ParityGame subgame;
     118           0 :             subgame.make_subgame(game, unsolved.begin(), unsolved.end(),
     119             :                                  true, StaticGraph::EDGE_PREDECESSOR);
     120           0 :             Substrategy substrat(strat, unsolved);
     121           0 :             if (!solve(subgame, substrat)) return false;
     122             : 
     123             :             // Compute attractor set of all vertices won by the opponent:
     124           0 :             ParityGame::Player opponent = (ParityGame::Player)(prio%2);
     125             :             //std::set<verti> lost_attr;
     126           0 :             DenseSet<verti> lost_attr(0, V);
     127           0 :             for ( std::vector<verti>::const_iterator it = unsolved.begin();
     128           0 :                   it != unsolved.end(); ++it )
     129             :             {
     130           0 :                 if (strat.winner(*it, game.player(*it)) == opponent)
     131             :                 {
     132           0 :                     lost_attr.insert(*it);
     133             :                 }
     134             :             }
     135           0 :             mCRL2log(mcrl2::log::debug) << "|lost|=" << lost_attr.size() << std::endl;
     136           0 :             if (lost_attr.empty()) break;
     137           0 :             make_attractor_set_2(game, opponent, lost_attr, strat);
     138           0 :             mCRL2log(mcrl2::log::debug) << "|lost_attr|=" << lost_attr.size() << std::endl;
     139           0 :             get_complement(V, lost_attr).swap(unsolved);
     140           0 :         }
     141             : 
     142             :         // Repeat with subgame of which vertices won by odd have been removed:
     143             :         {
     144           0 :             ParityGame subgame;
     145           0 :             subgame.make_subgame(game, unsolved.begin(), unsolved.end(),
     146             :                                  true, StaticGraph::EDGE_PREDECESSOR);
     147           0 :             Substrategy substrat(strat, unsolved);
     148           0 :             strat.swap(substrat);
     149           0 :             game.swap(subgame);
     150           0 :         }
     151           0 :     }
     152             : 
     153             :     // If we get here, then the opponent's winning set was empty; the strategy
     154             :     // for most vertices has already been initialized, except for those with
     155             :     // minimum priority. Since the whole game is won by the current player, it
     156             :     // suffices to pick an arbitrary successor for these vertices:
     157           0 :     const StaticGraph &graph = game.graph();
     158           0 :     const verti V = graph.V();
     159           0 :     if (graph.edge_dir() & StaticGraph::EDGE_SUCCESSOR)
     160             :     {
     161           0 :         for (verti v = 0; v < V; ++v)
     162             :         {
     163           0 :             if (game.priority(v) < prio)
     164             :             {
     165           0 :                 if (game.player(v) == game.priority(v)%2)
     166             :                 {
     167           0 :                     strat[v] = *graph.succ_begin(v);
     168             :                 }
     169             :                 else
     170             :                 {
     171           0 :                     strat[v] = NO_VERTEX;
     172             :                 }
     173             :             }
     174             :         }
     175             :     }
     176             :     else
     177             :     {
     178             :         // NOTE: this assumes the graph is a proper game graph!
     179             :         // If there are min. priority vertices without any successors, we won't
     180             :         // be able to find them this way!
     181           0 :         for (verti w = 0; w < V; ++w)
     182             :         {
     183           0 :             for (StaticGraph::const_iterator it = graph.pred_begin(w);
     184           0 :                 it != graph.pred_end(w); ++it)
     185             :             {
     186           0 :                 const verti v = *it;
     187             : 
     188           0 :                 if (game.priority(v) < prio)
     189             :                 {
     190           0 :                     if (game.player(v) == game.priority(v)%2)
     191             :                     {
     192           0 :                         strat[v] = w;
     193             :                     }
     194             :                     else
     195             :                     {
     196           0 :                         strat[v] = NO_VERTEX;
     197             :                     }
     198             :                 }
     199             :             }
     200             :         }
     201             :     }
     202           0 :     return true;
     203             : }
     204             : 
     205           0 : ParityGameSolver *RecursiveSolverFactory::create( const ParityGame &game,
     206             :         const verti *vertex_map, verti vertex_map_size )
     207             : {
     208             :     (void)vertex_map;       // unused
     209             :     (void)vertex_map_size;  // unused
     210             : 
     211           0 :     return new RecursiveSolver(game);
     212             : }

Generated by: LCOV version 1.14