Initial commit
This commit is contained in:
		
							
								
								
									
										4
									
								
								.formatter.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.formatter.exs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| # Used by "mix format" | ||||
| [ | ||||
|   inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] | ||||
| ] | ||||
							
								
								
									
										26
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| # The directory Mix will write compiled artifacts to. | ||||
| /_build/ | ||||
|  | ||||
| # If you run "mix test --cover", coverage assets end up here. | ||||
| /cover/ | ||||
|  | ||||
| # The directory Mix downloads your dependencies sources to. | ||||
| /deps/ | ||||
|  | ||||
| # Where third-party dependencies like ExDoc output generated docs. | ||||
| /doc/ | ||||
|  | ||||
| # Ignore .fetch files in case you like to edit your project deps locally. | ||||
| /.fetch | ||||
|  | ||||
| # If the VM crashes, it generates a dump, let's ignore it too. | ||||
| erl_crash.dump | ||||
|  | ||||
| # Also ignore archive artifacts (built via "mix archive.build"). | ||||
| *.ez | ||||
|  | ||||
| # Ignore package tarball (built via "mix hex.build"). | ||||
| genetic-*.tar | ||||
|  | ||||
| # Temporary files, for example, from tests. | ||||
| /tmp/ | ||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| # Genetic | ||||
|  | ||||
| **TODO: Add description** | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
| If [available in Hex](https://hex.pm/docs/publish), the package can be installed | ||||
| by adding `genetic` to your list of dependencies in `mix.exs`: | ||||
|  | ||||
| ```elixir | ||||
| def deps do | ||||
|   [ | ||||
|     {:genetic, "~> 0.1.0"} | ||||
|   ] | ||||
| end | ||||
| ``` | ||||
|  | ||||
| Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) | ||||
| and published on [HexDocs](https://hexdocs.pm). Once published, the docs can | ||||
| be found at <https://hexdocs.pm/genetic>. | ||||
|  | ||||
							
								
								
									
										77
									
								
								lib/genetic.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								lib/genetic.ex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| defmodule Genetic do | ||||
|     alias Types.Chromosome | ||||
|  | ||||
|     def initialize(genotype, opts \\ []) do | ||||
|         population_size = Keyword.get(opts, :population_size, 100) | ||||
|         for _ <- 1..population_size, do: genotype.() | ||||
|     end | ||||
|  | ||||
|     def evaluate(population, fitness_function, opts \\ []) do | ||||
|         population | ||||
|         |> Enum.map( | ||||
|             fn chromosome -> | ||||
|                 fitness = fitness_function.(chromosome) | ||||
|                 age = chromosome.age + 1 | ||||
|                 %Chromosome{chromosome | fitness: fitness, age: age} | ||||
|             end | ||||
|         ) | ||||
|         |> Enum.sort_by(& &1.fitness, &>=/2) | ||||
|     end | ||||
|  | ||||
|     def select(population, opts \\ []) do | ||||
|         population | ||||
|         |> Enum.chunk_every(2) | ||||
|         |> Enum.map(&List.to_tuple(&1)) | ||||
|     end | ||||
|  | ||||
|     def crossover(population, opts \\ []) do | ||||
|         population | ||||
|         |> Enum.reduce([], | ||||
|             fn {p1, p2}, acc -> | ||||
|                 cx_point = :rand.uniform(length(p1.genes)) | ||||
|                 {{h1,t1},{h2,t2}} = | ||||
|                     {Enum.split(p1.genes, cx_point), | ||||
|                     Enum.split(p2.genes, cx_point)} | ||||
|                 {c1,c2} = {%Chromosome{p1 | genes: h1 ++ t2}, %Chromosome{p2 | genes: h2 ++ t1} } | ||||
|                 [c1,c2 | acc] | ||||
|             end | ||||
|         ) | ||||
|     end | ||||
|  | ||||
|     def mutation(population, opts \\ []) do  | ||||
|         population | ||||
|         |> Enum.map( | ||||
|             fn chromosome -> | ||||
|                 if :rand.uniform() < 0.05 do | ||||
|                     %Chromosome{chromosome | genes: Enum.shuffle(chromosome)} | ||||
|                 else | ||||
|                     chromosome | ||||
|                 end | ||||
|             end | ||||
|         ) | ||||
|     end | ||||
|  | ||||
|     def run(problem, opts \\ []) do | ||||
|         population = initialize(&problem.genotype/0) | ||||
|         population  | ||||
|         |> evolve(problem, opts) | ||||
|     end | ||||
|  | ||||
|     def evolve(population, problem, opts \\ []) do | ||||
|         population = evaluate(population, &problem.fitness_function/1, opts) | ||||
|         best = hd(population) | ||||
|         IO.write("\rCurrent Best: #{best.fitness}") | ||||
|         if problem.terminate?(population) do | ||||
|             best | ||||
|         else | ||||
|             population | ||||
|             |> select(opts) | ||||
|             |> crossover(opts) | ||||
|             |> mutation(opts) | ||||
|             |> evolve(problem, opts) | ||||
|         end | ||||
|  | ||||
|  | ||||
|     end | ||||
|  | ||||
| end | ||||
							
								
								
									
										12
									
								
								lib/types/chromosome.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/types/chromosome.ex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| defmodule Types.Chromosome do | ||||
|     @type t :: %__MODULE__ { | ||||
|         genes: Enum.t, | ||||
|         size: integer(), | ||||
|         fitness: number(), | ||||
|         age: integer() | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @enforce_keys :genes | ||||
|     defstruct [:genes, size: 0, fitness: 0, age: 0] | ||||
| end | ||||
							
								
								
									
										28
									
								
								mix.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								mix.exs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| defmodule Genetic.MixProject do | ||||
|   use Mix.Project | ||||
|  | ||||
|   def project do | ||||
|     [ | ||||
|       app: :genetic, | ||||
|       version: "0.1.0", | ||||
|       elixir: "~> 1.13", | ||||
|       start_permanent: Mix.env() == :prod, | ||||
|       deps: deps() | ||||
|     ] | ||||
|   end | ||||
|  | ||||
|   # Run "mix help compile.app" to learn about applications. | ||||
|   def application do | ||||
|     [ | ||||
|       extra_applications: [:logger] | ||||
|     ] | ||||
|   end | ||||
|  | ||||
|   # Run "mix help deps" to learn about dependencies. | ||||
|   defp deps do | ||||
|     [ | ||||
|       # {:dep_from_hexpm, "~> 0.3.0"}, | ||||
|       # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} | ||||
|     ] | ||||
|   end | ||||
| end | ||||
							
								
								
									
										9
									
								
								problem.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								problem.ex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| defmodule Problem do | ||||
|     alias Types.Chromosome | ||||
|  | ||||
|     @callback genotype :: Chromosome.t | ||||
|  | ||||
|     @callback fitness_function(Chromosome.t) :: number() | ||||
|  | ||||
|     @callback terminate?(Enum.t) :: boolean() | ||||
| end | ||||
							
								
								
									
										23
									
								
								scripts/one_max.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								scripts/one_max.exs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| genotype = fn -> for _ <- 1..1000, do: Enum.random(0..1) end | ||||
|  | ||||
| fitness_function = fn chromosome -> Enum.sum(chromosome) end | ||||
| max_fitness = 1000 | ||||
|  | ||||
| defmodule OneMax do | ||||
|     @behaviour Problem | ||||
|  | ||||
|     @impl Problem | ||||
|     def genotype() do | ||||
|         for _ <- 1..1000, do: Enum.random(0.. | ||||
|     end | ||||
|      | ||||
|     @impl Problem | ||||
|     def fitness_function(chromosome) do | ||||
|         Enum.sum(chromosome.genes) | ||||
|     end | ||||
| end | ||||
|   | ||||
| soln = Genetic.run(fitness_function, genotype, max_fitness) | ||||
|  | ||||
| IO.write("\n") | ||||
| IO.inspect(soln) | ||||
							
								
								
									
										8
									
								
								test/genetic_test.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								test/genetic_test.exs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| defmodule GeneticTest do | ||||
|   use ExUnit.Case | ||||
|   doctest Genetic | ||||
|  | ||||
|   test "greets the world" do | ||||
|     assert Genetic.hello() == :world | ||||
|   end | ||||
| end | ||||
							
								
								
									
										1
									
								
								test/test_helper.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/test_helper.exs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| ExUnit.start() | ||||
		Reference in New Issue
	
	Block a user