lib/utils/maximum_matching.ex

defmodule CPSolver.Utils.MaximumMatching do
  @moduledoc """
  Algorithms for finding maximum matching on graphs.
  """
  alias CPSolver.Common
  import CPSolver.Utils

  @spec build_flow_network([Common.variable_or_view()]) :: Graph.t()
  def build_flow_network(variables) do
    Enum.reduce(variables, {Graph.new(), 0}, fn var, {graph_acc, idx_acc} ->
      values = domain_values(var)

      {graph_acc
       |> Graph.add_edge(:s, variable_node(idx_acc), weight: 1)
       |> then(fn g ->
         Enum.reduce(values, g, fn val, g_acc ->
           g_acc
           |> Graph.add_edge(variable_node(idx_acc), value_node(idx_acc, val), weight: 1)
           |> Graph.add_edge(value_node(idx_acc, val), :t, weight: 1)
         end)
       end), idx_acc + 1}
    end)
    |> elem(0)
  end

  defp variable_node(idx) do
    {:variable, idx}
  end

  defp value_node(_var_idx, value) do
    {:value, value}
  end
end