LCOV - code coverage report
Current view: top level - lps/include/mcrl2/lps - find_representative.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 37 49 75.5 %
Date: 2024-04-26 03:18:02 Functions: 1 3 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Wieger Wesselink
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : /// \file mcrl2/lps/find_representative.h
      10             : /// \brief add your file description here.
      11             : 
      12             : #ifndef MCRL2_LPS_FIND_REPRESENTATIVE_H
      13             : #define MCRL2_LPS_FIND_REPRESENTATIVE_H
      14             : 
      15             : #include <cstddef>
      16             : #include <vector>
      17             : #include "mcrl2/utilities/detail/container_utility.h"
      18             : 
      19             : namespace mcrl2 {
      20             : 
      21             : namespace lps {
      22             : 
      23             : /// \brief Search for a unique representative in a graph.
      24             : /// \param u0 The root of the graph.
      25             : /// \param generate_successors A function that generates successors of a node.
      26             : /// \details This function is based on an iterative version of Tarjan's strongly connected components algorithm.
      27             : /// It returns the smallest node of the first SCC that is detected. The first SCC is a TSCC, meaning
      28             : /// that it has no outgoing edges. In a confluent tau graph there is only one TSCC, so this should
      29             : /// guarantee a unique representative.
      30             : /// N.B. The implementation is based on https://llbit.se/?p=3379
      31             : template <typename Node, typename GenerateSuccessors>
      32          18 : Node find_representative(Node& u0, GenerateSuccessors generate_successors)
      33             : {
      34             :   using utilities::detail::contains;
      35             : 
      36          18 :   std::vector<Node> stack;
      37          18 :   std::map<Node, std::size_t> low;
      38          18 :   std::map<Node, std::size_t> disc;
      39             : 
      40          18 :   std::map<Node, std::vector<Node>> successors;
      41          18 :   std::vector<std::pair<Node, std::size_t>> work;
      42             : 
      43          18 :   successors[u0] = generate_successors(u0);
      44          18 :   work.emplace_back(std::make_pair(u0, 0));
      45             : 
      46          48 :   while (!work.empty())
      47             :   {
      48          24 :     Node u = work.back().first;
      49          24 :     std::size_t i = work.back().second;
      50          24 :     work.pop_back();
      51             : 
      52          24 :     if (i == 0)
      53             :     {
      54          24 :       std::size_t k = disc.size();
      55          24 :       disc[u] = k;
      56          24 :       low[u] = k;
      57          24 :       stack.push_back(u);
      58             :     }
      59             : 
      60          24 :     bool recurse = false;
      61          24 :     const std::vector<Node>& succ = successors[u];
      62          24 :     for (std::size_t j = i; j < succ.size(); j++)
      63             :     {
      64           6 :       const Node& v = succ[j];
      65           6 :       if (disc.find(v) == disc.end())
      66             :       {
      67           6 :         successors[v] = generate_successors(v);
      68           6 :         work.emplace_back(std::make_pair(u, j + 1));
      69           6 :         work.emplace_back(std::make_pair(v, 0));
      70           6 :         recurse = true;
      71           6 :         break;
      72             :       }
      73           0 :       else if (contains(stack, v))
      74             :       {
      75           0 :         low[u] = std::min(low[u], disc[v]);
      76             :       }
      77             :     }
      78          24 :     if (recurse)
      79             :     {
      80           6 :       continue;
      81             :     }
      82          18 :     if (disc[u] == low[u])
      83             :     {
      84             :       // an SCC has been found; return the node with the minimum value in this SCC
      85          18 :       Node result = u;
      86           0 :       while (true)
      87             :       {
      88          18 :         const auto& v = stack.back();
      89          18 :         if (v == u)
      90             :         {
      91          18 :           break;
      92             :         }
      93           0 :         if (v < result)
      94             :         {
      95           0 :           result = v;
      96             :         }
      97           0 :         stack.pop_back();
      98             :       }
      99          36 :       return result;
     100          18 :     }
     101           0 :     if (!work.empty())
     102             :     {
     103           0 :       Node v = u;
     104           0 :       u = work.back().first;
     105           0 :       low[u] = std::min(low[u], low[v]);
     106           0 :     }
     107             :   }
     108           0 :   throw mcrl2::runtime_error("find_representative did not find a solution");
     109          18 : }
     110             : 
     111             : } // namespace lps
     112             : 
     113             : } // namespace mcrl2
     114             : 
     115             : #endif // MCRL2_LPS_FIND_REPRESENTATIVE_H

Generated by: LCOV version 1.14