[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/memgraph/mage/main/cpp/cycles_module/algorithm/cycles.cpp [Back]  [Original]

#include 

#include 
#include 

#include "cycles.hpp"

namespace cycles_util {

NodeState::NodeState(std::size_t number_of_nodes) {
  visited.resize(number_of_nodes, false);
  parent.resize(number_of_nodes, std::nullopt);
  depth.resize(number_of_nodes, 0);
}

void NodeState::SetVisited(std::uint64_t node_id) { visited[node_id] = true; }

bool NodeState::IsVisited(std::uint64_t node_id) const { return visited[node_id]; }

void NodeState::SetParent(std::uint64_t parent_id, std::uint64_t node_id) { parent[parent_id] = node_id; }

std::optional NodeState::GetParent(std::uint64_t node_id) const { return parent[node_id]; }

void NodeState::SetDepth(std::uint64_t node_id, std::uint64_t node_depth) { depth[node_id] = node_depth; }

std::uint64_t NodeState::GetDepth(std::uint64_t node_id) const { return depth[node_id]; }

void FindNonSpanningTreeEdges(std::uint64_t node_id, const mg_graph::GraphView &graph, NodeState *state,
                              std::set *non_st_edges) {
  std::unordered_set unique_neighbour;
  state->SetVisited(node_id);
  for (const auto &neigh : graph.Neighbours(node_id)) {
    auto next_id = neigh.node_id;

    // Check if is returning edge or already visited neighbour
    if (const auto parent = state->GetParent(node_id);
        parent && (next_id == *parent || unique_neighbour.find(next_id) != unique_neighbour.end())) {
      continue;
    }

    unique_neighbour.insert(next_id);

    if (state->IsVisited(next_id)) {
      auto sorted_edge = std::minmax(node_id, next_id);
      non_st_edges->insert(sorted_edge);
      continue;
    }

    // Set depth and parent for the next ST iteration
    state->SetParent(next_id, node_id);
    state->SetDepth(next_id, state->GetDepth(node_id) + 1);
    FindNonSpanningTreeEdges(next_id, graph, state, non_st_edges);
  }
}

void FindFundamentalCycles(const std::set &non_st_edges,
                           const NodeState &state, std::vector *fundamental_cycles) {
  for (const auto &[from, to] : non_st_edges) {
    fundamental_cycles->emplace_back(FindFundamentalCycle(from, to, state));
  }
}

std::vector FindFundamentalCycle(std::uint64_t node_a, std::uint64_t node_b, const NodeState &state) {
  std::vector cycle;
  if (state.depth[node_a] < state.depth[node_b]) {
    std::swap(node_a, node_b);
  }

  // climb until a and b reach the same depth:
  //
  //       ()               ()
  //      /  \             /  \.
  //    ()   (b)   -->   (a)  (b)
  //   /  \             /   \.
  // (a)  ()           ()   ()
  cycle.emplace_back(node_a);
  while (state.depth[node_a] > state.depth[node_b]) {
    const auto maybe_parent = state.GetParent(node_a);
    if (!maybe_parent) {
      throw mg_exception::InvalidIDException();
    }
    node_a = *maybe_parent;
    cycle.emplace_back(node_a);
  }

  if (node_a != node_b) {
    throw std::runtime_error("There should be no cross edges in DFS tree of an undirected graph.");
  }

  // Close the cycle
  cycle.emplace_back(cycle[0]);
  return cycle;
}

void CombineCycles(std::uint32_t mask, const std::vector &fundamental_cycles,
                   const mg_graph::GraphView &graph, std::vector *cycles) {
  std::map edge_cnt;
  for (std::size_t i = 0; i < fundamental_cycles.size(); ++i) {
    if ((mask & (1  2) {
    cycles->emplace_back(cycle);
  }
}

void GetCyclesFromFundamentals(const std::vector &fundamental_cycles,
                               const mg_graph::GraphView &graph, std::vector *cycles) {
  std::uint32_t size = 1  1 || from == to) {
      cycles.push_back({{from}, {to}});
    }
  }

  return cycles;
}

}  // namespace cycles_alg

Web Proxy Viewer  |  New URL  |  Original Page