defmodule CPSolver.Variable.UnfixedTracker do alias InPlace.SparseSet alias CPSolver.Utils.Vector alias CPSolver.Variable.Interface def new(variables) when is_list(variables) do new(Vector.new(variables)) end def new(variables) do variables |> Vector.size() |> SparseSet.new() |> update(variables) end def update(tracker, variables) do each(tracker, fn var_idx -> Interface.fixed?(variables[var_idx - 1]) && delete(tracker, var_idx) end) tracker end def copy(tracker) do SparseSet.copy(tracker) end def delete(tracker, idx) do SparseSet.delete(tracker, idx) end def serialize(tracker) do SparseSet.serialize(tracker) end def deserialize(tracker) do SparseSet.deserialize(tracker) end def each(tracker, action) do SparseSet.each(tracker, action) end def iterate(%{unfixed_variables_tracker: tracker, variables: variables} = _data, ordered? \\ true) do iterate(tracker, variables, ordered?) end def iterate(tracker, variables, ordered?) do iterate(tracker, variables, [], fn var, acc -> [var | acc] end, ordered?) |> Enum.reverse() end def iterate(%{unfixed_variables_tracker: tracker, variables: variables} = _data, initial, reducer, ordered?) do iterate(tracker, variables, initial, reducer, ordered?) end def iterate(variables, initial, reducer, ordered?) when is_list(variables) do Enum.reduce(variables, initial, fn var, acc -> reducer.(var, acc) end) |> then(fn vars -> ordered? && Enum.sort_by(vars, fn var -> var.index end) || vars end) end def iterate(tracker, variables, initial, reducer, ordered?) when is_function(reducer, 2) do if ordered? do SparseSet.iterate_ordered(tracker, initial, variable_iterator(tracker, variables, reducer)) else SparseSet.iterate(tracker, initial, variable_iterator(tracker, variables, reducer)) end end defp variable_iterator(tracker, variables, reducer) do fn idx, acc -> var = variables[idx - 1] if Interface.fixed?(var) do delete(tracker, idx) acc else reducer.(var, acc) end end end def empty?(tracker) do SparseSet.empty?(tracker) end end