Skip to content

Using struct instead of modules to describe problems? #20

@idabmat

Description

@idabmat

To use Genex today, a user builds a module and defines three functions. If the problem has parameters that impact how these functions should work, they can define functions to hold that data. That is the approach taken in the knapsack problem example.

But then what happens if the user wants to solve different versions of the same problem? Like solving the knapsack problem with other weights/profits/weight limits. Currently, they would have to either rewrite the module every time or duplicate it for each version. While working through Genetic Algorithms in Elixir, I opted for protocols when implementing the book's framework. I found the result easier to customise. Again, taking the knapsack problem as an example, the code would look something like this:

defmodule Knapsack do
  @enforce_keys [:profits, :weigths, :weight_limit]
  defstruct [:profits, :weights, :weight_limit, bound_breached: 0]

  defimpl Genex.Solvable do
    def genotype(knapsack), do: Genex.Tools.Genotype.binary(Enum.count(knapsack.weights))

    def fitness_function(knapsack, chromosome) do
      profit =
        chromosome.genes
        |> Enum.zip(knapsack.profits)
        |> Enum.reduce(0, fn {g, p}, acc -> acc + g * p end)

      weight_carried =
        chromosome.genes
        |> Enum.zip(knapsack.weights)
        |> Enum.reduce(0, fn {g, w}, acc -> acc + g * w end)

      weight_allowed? = weight_carried <= knapsack.weight_limit

      if weight_allowed? do
        profit
      else
        knapsack.bound_breached
      end
    end

    def terminate?(_knapsack, population), do: population.generation == 1000
  end
end

solution =
  %Knapsack{profits: [6, 5, 8, 9, 6, 7, 3], weights: [2, 3, 6, 7, 5, 9, 4], weight_limit: 12}
  |> Genex.run(
    title: "Knapsack",
    crossover_type: Genex.Tools.Crossover.two_point(),
    selection_type: Genex.Tools.Selection.roulette(),
    population_size: 50
  )

IO.inspect(solution.strongest.genes)

That would be a breaking change, but since 1.0 was not yet released, I thought this could be an appropriate time to suggest such a change.

Would a PR introducing this be welcome?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions