LCOV - code coverage report
Current view: top level - src/util - AdjacencyMatrix.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 79 79 100.0 %
Date: 2025-03-25 01:19:55 Functions: 7 7 100.0 %
Branches: 69 104 66.3 %

           Branch data     Line data    Source code
       1                 :            : #include <mutable/util/AdjacencyMatrix.hpp>
       2                 :            : 
       3                 :            : #include <queue>
       4                 :            : 
       5                 :            : 
       6                 :            : using namespace m;
       7                 :            : 
       8                 :            : 
       9                 :            : /*======================================================================================================================
      10                 :            :  * AdjacencyMatrix
      11                 :            :  *====================================================================================================================*/
      12                 :            : 
      13                 :          3 : AdjacencyMatrix AdjacencyMatrix::transitive_closure_directed() const
      14                 :            : {
      15                 :          3 :     AdjacencyMatrix closure(*this); // copy
      16                 :            : 
      17                 :            :     bool changed;
      18                 :          3 :     do {
      19                 :          4 :         changed = false;
      20         [ +  + ]:         22 :         for (std::size_t i = 0; i != num_vertices_; ++i) {
      21         [ +  + ]:        102 :             for (std::size_t j = 0; j != num_vertices_; ++j) {
      22         [ +  + ]:         84 :                 if (not closure(i, j)) {
      23                 :         67 :                     const SmallBitset row = closure.m_[i];
      24                 :         67 :                     const SmallBitset col_mask = SmallBitset::Singleton(j);
      25         [ +  + ]:        117 :                     for (std::size_t k : row) {
      26                 :         54 :                         M_insist(row[k]);
      27         [ +  + ]:         54 :                         if (closure.m_[k] & col_mask) {
      28                 :          4 :                             closure(i, j) = true;
      29                 :          4 :                             changed = true;
      30                 :          4 :                             break;
      31                 :            :                         }
      32                 :            :                     }
      33                 :         67 :                 }
      34                 :         84 :             }
      35                 :         18 :         }
      36         [ +  + ]:          4 :     } while (changed);
      37                 :            : 
      38                 :          3 :     return closure;
      39                 :            : }
      40                 :            : 
      41                 :          4 : AdjacencyMatrix AdjacencyMatrix::transitive_closure_undirected() const
      42                 :            : {
      43                 :          4 :     AdjacencyMatrix closure(*this); // copy
      44                 :            : 
      45                 :            :     bool changed;
      46                 :          4 :     do {
      47                 :          6 :         changed = false;
      48         [ +  + ]:         30 :         for (std::size_t i = 0; i != num_vertices_; ++i) {
      49         [ +  + ]:         87 :             for (std::size_t j = i; j != num_vertices_; ++j) { // exploit symmetry
      50                 :         63 :                 M_insist(closure(i, j) == closure(j, i), "not symmetric");
      51                 :         63 :                 const bool before = closure(i, j);
      52                 :         63 :                 const SmallBitset row = closure.m_[i];
      53                 :         63 :                 const SmallBitset col = closure.m_[j]; // exploit symmetry
      54                 :         63 :                 const bool dot = not (row & col).empty(); // compute connected-ness as "dot product"
      55                 :         63 :                 closure(i, j) = closure(j, i) = dot;
      56         [ +  + ]:         63 :                 changed = changed or before != dot;
      57                 :         63 :             }
      58                 :         24 :         }
      59         [ +  + ]:          6 :     } while (changed);
      60                 :            : 
      61                 :          4 :     return closure;
      62                 :            : }
      63                 :            : 
      64                 :          8 : AdjacencyMatrix AdjacencyMatrix::minimum_spanning_forest(std::function<double(std::size_t, std::size_t)> weight) const
      65                 :            : {
      66                 :          8 :     AdjacencyMatrix MSF(num_vertices_);
      67                 :            : 
      68         [ +  + ]:          8 :     if (num_vertices_ == 0)
      69                 :          1 :         return MSF;
      70                 :            : 
      71                 :            :     struct weighted_edge
      72                 :            :     {
      73                 :            :         std::size_t source, sink;
      74                 :          1 :         double weight;
      75                 :            : 
      76                 :            :         weighted_edge() = default;
      77                 :         22 :         weighted_edge(std::size_t source, std::size_t sink, double weight)
      78                 :         22 :             : source(source), sink(sink), weight(weight)
      79                 :         22 :         { }
      80                 :            : 
      81                 :            :         bool operator<(const weighted_edge &other) const { return this->weight < other.weight; }
      82                 :         23 :         bool operator>(const weighted_edge &other) const { return this->weight > other.weight; }
      83                 :            :     };
      84                 :          7 :     std::priority_queue<weighted_edge, std::vector<weighted_edge>, std::greater<weighted_edge>> Q;
      85                 :            : 
      86                 :            :     /* Run Prim's algorithm for each remaining vertex to compute a MSF. */
      87         [ +  - ]:          7 :     SmallBitset vertices_remaining = SmallBitset::All(num_vertices_);
      88                 :            : 
      89   [ +  -  +  + ]:         21 :     while (vertices_remaining) {
      90   [ +  -  +  - ]:         14 :         SmallBitset next_vertex = vertices_remaining.begin().as_set();
      91         [ +  - ]:         14 :         vertices_remaining = vertices_remaining - next_vertex;
      92                 :            : 
      93                 :            :         /* Prim's algorithm for finding a MST. */
      94   [ +  -  +  - ]:         29 :         while (next_vertex) {
      95                 :            :             /* Explore edges of `next_vertex`. */
      96   [ +  -  +  - ]:         29 :             M_insist(next_vertex.is_singleton());
      97   [ +  -  +  - ]:         29 :             const SmallBitset N = neighbors(next_vertex) & vertices_remaining;
      98   [ +  -  +  - ]:         29 :             const std::size_t u = *next_vertex.begin();
      99   [ +  -  +  -  :         51 :             for (std::size_t v : N)
          +  -  +  +  +  
                -  +  - ]
     100   [ +  -  +  - ]:         22 :                 Q.emplace(u, v, weight(u, v));
     101                 :            : 
     102                 :            :             /* Search for the cheapest edge not within the MSF. */
     103                 :            :             weighted_edge E;
     104                 :         29 :             do {
     105   [ +  -  +  + ]:         36 :                 if (Q.empty())
     106                 :         14 :                     goto MST_done;
     107         [ +  - ]:         22 :                 E = Q.top();
     108         [ +  - ]:         22 :                 Q.pop();
     109   [ +  -  +  -  :         22 :             } while (not vertices_remaining[E.sink]);
                   +  + ]
     110                 :            : 
     111                 :            :             /* Add edge to MSF. */
     112   [ +  -  +  -  :         15 :             M_insist(vertices_remaining[E.sink], "sink must not yet be in the MSF");
                   +  - ]
     113   [ +  -  +  - ]:         15 :             vertices_remaining[E.sink] = false;
     114   [ +  -  +  -  :         15 :             MSF(E.source, E.sink) = MSF(E.sink, E.source) = true; // add undirected edge to MSF
             +  -  +  - ]
     115         [ +  - ]:         15 :             next_vertex = SmallBitset::Singleton(E.sink);
     116                 :            :         }
     117                 :            : MST_done: /* MST is complete */;
     118                 :            :     }
     119                 :            :     return MSF;
     120                 :          8 : }
     121                 :            : 
     122                 :         11 : AdjacencyMatrix AdjacencyMatrix::tree_directed_away_from(SmallBitset root)
     123                 :            : {
     124                 :         11 :     M_insist(root.is_singleton());
     125                 :         11 :     AdjacencyMatrix directed_tree(num_vertices_);
     126                 :         11 :     SmallBitset V = root;
     127                 :         11 :     SmallBitset X;
     128         [ +  + ]:         41 :     while (not V.empty()) {
     129                 :         30 :         X |= V;
     130         [ +  + ]:         67 :         for (auto v : V)
     131                 :         37 :             directed_tree.m_[v] = this->m_[v] - X;
     132                 :         30 :         V = directed_tree.neighbors(V);
     133                 :            :     }
     134                 :            : 
     135                 :         11 :     return directed_tree;
     136                 :            : }
     137                 :            : 
     138                 :            : M_LCOV_EXCL_START
     139                 :            : void AdjacencyMatrix::dump(std::ostream &out) const { out << *this << std::endl; }
     140                 :            : void AdjacencyMatrix::dump() const { dump(std::cerr); }
     141                 :            : M_LCOV_EXCL_STOP

Generated by: LCOV version 1.16