-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Eric Matte
committed
Nov 17, 2019
1 parent
512d521
commit 5a6271f
Showing
10 changed files
with
132 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
module Genetic | ||
module Algorithm | ||
VERSION = "0.1.0".freeze | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# A member of a given population | ||
class Genetic::Algorithm::Chromosome | ||
attr_accessor :genes | ||
attr_accessor :fitness | ||
|
||
def initialize(genes:, fitness:) | ||
@genes = genes | ||
@fitness = fitness | ||
end | ||
|
||
# Randomly change one of its gene. | ||
# Help maintain diversity within the population and prevent premature convergence. | ||
# @param [(Object | Float)[][]] ranges - The available ranges to mutate from for all genes. ranges.lenght must equals genes.length | ||
# @param [Boolean] sampleFromRanges | ||
# If true: take one of the available values for a given range | ||
# if false: take a random floating value between ranges[i][0] and ranges[i][1] | ||
def mutate(ranges, sample_from_ranges = false) | ||
i = rand(0..(genes.length - 1)) | ||
@genes[i] = sample_from_ranges ? ranges[i].sample : rand(ranges[i][0]..ranges[i][1]) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Record and display best individuals accross generations | ||
class Genetic::Algorithm::FitnessRecorder | ||
attr_accessor :best_individual | ||
|
||
def initialize | ||
@best_individual = nil | ||
@max_fitness = [] | ||
@max_overall_finess = [] | ||
@average_fitness = [] | ||
end | ||
|
||
def record_generation(generation, population) | ||
best_generation_individual = population.max_by(&:fitness) | ||
|
||
# Save best individual across all generations | ||
if best_generation_individual.fitness > (@best_individual&.fitness || -1e10) | ||
@best_individual = best_generation_individual | ||
end | ||
|
||
# Record progress information | ||
@max_fitness << best_generation_individual.fitness | ||
@max_overall_finess << @best_individual.fitness | ||
average = population.map(&:fitness).inject(:+) / population.length | ||
@average_fitness << average | ||
|
||
puts "Generation #{generation} completed." | ||
puts " Best overall fitness: #{@best_individual.fitness}" | ||
puts " Best population fitness: #{best_generation_individual.fitness}" | ||
puts " Average population fitness: #{average}" | ||
end | ||
|
||
def display_best_individual(shifts) | ||
puts "\n" | ||
puts "Result: Best overall individual fitness: #{@best_individual.fitness}" | ||
puts " Shift\t->\tSelected employee:" | ||
print_shift = ->(shift) { "[#{shift.start_at.localtime} - #{shift.end_at.localtime}]: #{shift.position.name}" } | ||
print_employee = ->(employee) { "#{employee.profile.full_name} (#{employee.email})" } | ||
puts shifts.each_with_index.map { |s, i| "#{print_shift[s[:shift]]}\t->\t#{print_employee[@best_individual.genes[i].user]}" } | ||
|
||
# puts "#{@max_fitness.each_with_index.map { |_, i| i }}," | ||
# puts "#{@max_fitness}," | ||
# puts "#{@max_overall_finess}," | ||
# puts "#{@average_fitness}," | ||
end | ||
|
||
def save_best_individual_genes | ||
raise "not implemented".freeze | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
require "test_helper" | ||
require "genetic/algorithm/chromosome" | ||
|
||
class Genetic::Algorithm::ChromosomeTest < Minitest::Test | ||
def test_it_can_mutate_floats | ||
20.times do | ||
test_genes = Array.new(rand(1..20)) { rand(0..100) } | ||
test_ranges = Array.new(test_genes.length) do |i| | ||
el = test_genes[i].to_f | ||
[rand(el - 50.0..el), rand(el..el + 50.0)] | ||
end | ||
|
||
chromosome = Genetic::Algorithm::Chromosome.new(fitness: nil, genes: test_genes.dup) | ||
chromosome.mutate(test_ranges) | ||
|
||
number_of_mutated_genes = 0 | ||
chromosome.genes.each_with_index do |el, i| | ||
if el != test_genes[i] | ||
number_of_mutated_genes += 1 | ||
end | ||
|
||
assert(test_ranges[i][0] < el && el < test_ranges[i][1]) | ||
end | ||
assert_equal(1, number_of_mutated_genes) | ||
end | ||
end | ||
|
||
def test_it_can_mutate_with_data_range | ||
test_ranges = [%w[male female], [18, 19, 20, 21, 22], ["🔥", "❄️", "🌎", "💨"]] | ||
test_genes = Array.new(test_ranges.length) { |i| test_ranges[i][0] } | ||
|
||
chromosome = Genetic::Algorithm::Chromosome.new(fitness: nil, genes: test_genes.dup) | ||
20.times do |i| # Discrete mutations can sometimes return the same value | ||
assert(false, "Unable to mutate") if i == 20 | ||
chromosome.mutate(test_ranges, true) | ||
break if chromosome.genes != test_genes | ||
end | ||
|
||
number_of_mutated_genes = 0 | ||
chromosome.genes.each_with_index do |el, i| | ||
if el != test_genes[i] | ||
number_of_mutated_genes += 1 | ||
end | ||
|
||
assert((test_ranges[i].include? el)) | ||
end | ||
assert_equal(1, number_of_mutated_genes) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) | ||
require "genetic/algorithm/resolver" | ||
require "genetic/algorithm" | ||
|
||
require "minitest/autorun" |