Current section
Files
Jump to
Current section
Files
lib/vector_combination_solver.ex
require Dantzig.Problem, as: Problem
require Dantzig.Constraint, as: Constraint
require Dantzig.Polynomial, as: Polynomial
use Dantzig.Polynomial.Operators
defmodule VectorCombinationSolver do
@moduledoc """
Solves the minimal positive integer linear combination problem using Dantzig.
Find coefficients c1, c2, c3, c4, c5, c6 such that:
c1*[0,0,0,1] + c2*[0,1,0,1] + c3*[0,0,1,0] + c4*[0,0,1,1] + c5*[1,0,1,0] + c6*[1,1,0,0] = [3,5,4,7]
Minimizing: sum of all coefficients
"""
def solve(basis_vectors, target) do
# Create problem - minimize the sum
problem = Problem.new(direction: :minimize)
num_vectors = length(basis_vectors)
# Define variables - all non-negative integers
{coefficients, problem} = 1..num_vectors
|> Enum.map_reduce(problem, fn index, acc ->
{problem, coefficient} = Problem.new_variable(acc, "coefficient#{index}", min: 0.0, type: :integer)
{coefficient, problem}
end)
coefficients_by_index = coefficients
|> Enum.with_index()
|> Map.new(fn {value, index} -> {index, value} end)
#|> IO.inspect()
# Add constraints based on the vector equations
problem = target
|> Enum.with_index()
|> Enum.reduce(problem, fn {value, target_index}, acc ->
relevant_coefficients = basis_vectors
|> Enum.with_index()
|> Enum.map(fn {basis_vector, coefficient_index} ->
if Enum.at(basis_vector, target_index) == 1 do
coefficient_index
else
-1
end
end)
|> Enum.filter(fn (coefficient_index) ->
coefficient_index != -1
end)
lhs = relevant_coefficients
|> Enum.reduce(%Polynomial{}, fn coefficient_index, acc ->
acc + Map.fetch!(coefficients_by_index, coefficient_index)
end)
acc
|> Problem.add_constraint(
Constraint.new(lhs == value)
)
end)
objective = coefficients
|> Enum.reduce(%Polynomial{}, fn coefficient, acc ->
acc + coefficient
end)
problem = problem
|> Problem.increment_objective(objective)
# Solve the problem
{:ok, solution} = Dantzig.solve(problem)
# solution |> IO.inspect()
solution.objective
end
end