lib/utils/digraph.ex

defmodule CPSolver.Utils.Digraph do
    def new(opts \\ []) do
      :digraph.new(opts)
    end


    def add_edge(dg, v1, v2) do
      :digraph.add_edge(dg, v1, v2)
      dg
    end

    def add_edge(dg, v1, v2, label) do
      :digraph.add_edge(dg, v1, v2, label)
      dg
    end

    def add_edge(dg, e, v1, v2, label) do
      :digraph.add_edge(dg, e, v1, v2, label)
      dg
    end

    def add_vertex(dg, v) do
      :digraph.add_vertex(dg, v)
      dg
    end

    def add_vertex(dg, v, label) do
      :digraph.add_vertex(dg, v, label)
      dg
    end

    def delete_edge(dg, e) do
      :digraph.del_edge(dg, e)
      dg
    end

    def delete_edges(dg, edges) do
      :digraph.del_edges(dg, edges)
      dg
    end

    def delete_path(dg, v1, v2) do
      :digraph.del_path(dg, v1, v2)
      dg
    end

    def delete_vertex(dg, v) do
      :digraph.del_vertex(dg, v)
      dg
    end

    def delete_vertices(dg, vertices) do
      :digraph.del_vertices(dg, vertices)
      dg
    end

    def delete(dg) do
      :digraph.delete(dg)
    end

    def edge(dg, e) do
      :digraph.edge(dg, e)
    end

    def edges(dg) do
      :digraph.edges(dg)
      |> expand_edges(dg)
    end

    def edges(dg, v) do
      :digraph.edges(dg, v)
      |> expand_edges(dg)
    end

    def get_cycle(dg, v) do
      :digraph.get_cycle(dg, v)
    end

    def get_path(dg, v1, v2) do
      :digraph.get_path(dg, v1, v2)
    end

    def get_short_cycle(dg, v) do
      :digraph.get_short_cycle(dg, v)
    end

    def get_short_path(dg, v1, v2) do
      :digraph.get_short_path(dg, v1, v2)
    end

    def in_degree(dg, v) do
      :digraph.in_degree(dg, v)
    end

    def in_edges(dg, v) do
      :digraph.in_edges(dg, v)
      |> expand_edges(dg)
    end

    def in_neighbours(dg, v) do
      :digraph.in_neighbours(dg, v)
    end

    def no_edges(dg) do
      :digraph.no_edges(dg)
    end

    def no_vertices(dg) do
      :digraph.no_vertices(dg)
    end

    def out_degree(dg, v) do
      :digraph.out_degree(dg, v)
    end

    def out_edges(dg, v) do
      :digraph.out_edges(dg, v)
      |> expand_edges(dg)
    end

    def out_neighbours(dg, v) do
      :digraph.out_neighbours(dg, v)
    end

    def vertex(dg, v) do
      :digraph.vertex(dg, v)
    end

    def vertices(dg) do
      :digraph.vertices(dg)
    end

    def copy(graph) do
      dg = :digraph.new()
      Enum.each(:digraph.vertices(graph), fn vertex_id ->
        {_vertex_id, label} = vertex(graph, vertex_id)
        :digraph.add_vertex(dg, vertex_id, label)
      end)

      Enum.each(:digraph.edges(graph), fn edge ->
        {_e, v1, v2, label} = :digraph.edge(graph, edge)
        :digraph.add_edge(dg, v1, v2, label)
        end)
      dg
    end

    def from_libgraph(%Graph{} = graph) do
      dg = new()
      Enum.each(Graph.vertices(graph), fn vertex ->
        add_vertex(dg, vertex, Graph.vertex_labels(graph, vertex))
      end)

      edges = Graph.edges(graph)
      Enum.each(edges, fn %Graph.Edge{v1: v1, v2: v2, label: label} ->
          add_edge(dg, v1, v2, label)
        end)
      dg
    end

    def to_libgraph(digraph) do
      g_vertices = Enum.reduce(vertices(digraph), Graph.new(),
        fn vertex, graph_acc ->
          {vertex_id, label} = vertex(digraph, vertex)
          Graph.add_vertex(graph_acc, vertex_id, label)
        end)

        Enum.reduce(edges(digraph), g_vertices, fn digraph_edge, graph_acc ->
            %Graph.Edge{v1: v1, v2: v2, label: label} = digraph_edge
            Graph.add_edge(graph_acc, v1, v2, label: label)
          end)
    end

    defp expand_edges(edges, digraph) do
      Enum.map(edges, fn e ->
        {_edge_id, v1, v2, labels} = edge(digraph, e)
        %Graph.Edge{v1: v1, v2: v2, label: labels, weight: 1}
      end)
    end

end