evopop 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -9
- data/lib/evopop.rb +2 -1
- data/lib/evopop/crossover.rb +10 -29
- data/lib/evopop/crossover_array.rb +65 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7807b58e3f22619a088086082e9e487bfcaa367c
|
|
4
|
+
data.tar.gz: e8b1fe7390fe1bd84a2df0991c3b2106bb1e36b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35f737e742c07176c1527929096b2fd78ae5d4007b486cd3a9775e234efe19b2d933d7e488f7819b99dbabd4334fd2ac3096860cd26093b6d2ae63b8e102d5d4
|
|
7
|
+
data.tar.gz: 406bd5fce6c6a5b98a8c8621f3f1d5a7fc1944ade0f7ddb4e4356b2a5da87801fe059b625602395dde9cc62756c39eaf5ca41b88ac968858f532671405c23151
|
data/README.md
CHANGED
|
@@ -13,18 +13,18 @@ over a fitness function.
|
|
|
13
13
|
require 'evopop'
|
|
14
14
|
|
|
15
15
|
# Initialize the population to be trained with good defaults.
|
|
16
|
-
population
|
|
17
|
-
population.population_size
|
|
18
|
-
population.dna_len
|
|
19
|
-
population.max_generations
|
|
20
|
-
population.initial_range_min
|
|
21
|
-
population.initial_range_max
|
|
16
|
+
population = Evopop::Population.new
|
|
17
|
+
population.population_size = 1000
|
|
18
|
+
population.dna_len = 2
|
|
19
|
+
population.max_generations = 1000
|
|
20
|
+
population.initial_range_min = -10_000.0
|
|
21
|
+
population.initial_range_max = 10_000.0
|
|
22
22
|
population.mutation_range_min = -10.0
|
|
23
23
|
population.mutation_range_max = 10.0
|
|
24
|
-
population.mutation_num
|
|
25
|
-
population.crossover_params
|
|
24
|
+
population.mutation_num = 10
|
|
25
|
+
population.crossover_params = { ordinal: (DNA_LEN / 2) }.freeze
|
|
26
26
|
population.crossover_function = Evopop::Crossover.method(:one_point)
|
|
27
|
-
population.fitness_function
|
|
27
|
+
population.fitness_function = proc do |dna|
|
|
28
28
|
Math.sin(dna[0]) + Math.cos(dna[1])
|
|
29
29
|
end
|
|
30
30
|
|
data/lib/evopop.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'evopop/population'
|
|
4
4
|
require 'evopop/candidate'
|
|
5
5
|
require 'evopop/crossover'
|
|
6
|
+
require 'evopop/crossover_array'
|
|
6
7
|
require 'evopop/dna'
|
|
7
8
|
|
|
8
9
|
# Toplevel class for evopop project
|
|
@@ -25,7 +26,7 @@ module Evopop
|
|
|
25
26
|
|
|
26
27
|
def initialize
|
|
27
28
|
@average_fitness = []
|
|
28
|
-
@population_size =
|
|
29
|
+
@population_size = 500
|
|
29
30
|
@max_generations = 100
|
|
30
31
|
@initial_range_min = -100
|
|
31
32
|
@initial_range_max = 100
|
data/lib/evopop/crossover.rb
CHANGED
|
@@ -8,25 +8,18 @@ module Evopop
|
|
|
8
8
|
# http://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)#One-point_crossover
|
|
9
9
|
def self.one_point(candidates, params)
|
|
10
10
|
ordinal = params[:ordinal]
|
|
11
|
+
arr_a, arr_b = CrossoverArray.one_point_crossover(candidates[0].dna, candidates[1].dna, ordinal)
|
|
11
12
|
|
|
12
|
-
#
|
|
13
|
-
# first candidate and the second chunk of the second candidate
|
|
14
|
-
dna_a_left = candidates[0].dna.take(ordinal)
|
|
15
|
-
dna_b_right = candidates[1].dna.drop(ordinal)
|
|
16
|
-
|
|
17
|
-
# Compose the dna of the second child from the first chunk of the
|
|
18
|
-
# first candidate and the second chunk of the second candidate
|
|
19
|
-
dna_b_left = candidates[1].dna.take(ordinal)
|
|
20
|
-
dna_a_right = candidates[0].dna.drop(ordinal)
|
|
21
|
-
|
|
13
|
+
# TODO: Move this to its own class, DnaRange
|
|
22
14
|
min_range = candidates[0].dna.min_range
|
|
23
15
|
max_range = candidates[1].dna.max_range
|
|
24
16
|
|
|
17
|
+
# TODO: Move this to its own class, DnaMutationRange
|
|
25
18
|
min_mutation = candidates[1].dna.min_mutation
|
|
26
19
|
max_mutation = candidates[1].dna.max_mutation
|
|
27
20
|
|
|
28
|
-
dna_a = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation,
|
|
29
|
-
dna_b = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation,
|
|
21
|
+
dna_a = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation, arr_a)
|
|
22
|
+
dna_b = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation, arr_b)
|
|
30
23
|
|
|
31
24
|
# Initialize and assign DNA to children.
|
|
32
25
|
[
|
|
@@ -43,18 +36,15 @@ module Evopop
|
|
|
43
36
|
# Make sure to sort.
|
|
44
37
|
ordinals = params[:ordinals].split(',').sort.collect(&:to_i)
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
cdna_a = candidates[0].dna
|
|
48
|
-
cdna_b = candidates[1].dna
|
|
39
|
+
cdna_a, cdna_b = CrossoverArray.two_point_crossover(candidates[0].dna, candidates[1].dna, ordinals)
|
|
49
40
|
|
|
50
41
|
[
|
|
51
|
-
Evopop::Candidate.new(
|
|
52
|
-
Evopop::Candidate.new(
|
|
42
|
+
Evopop::Candidate.new(cdna_a),
|
|
43
|
+
Evopop::Candidate.new(cdna_b)
|
|
53
44
|
]
|
|
54
45
|
end
|
|
55
46
|
|
|
56
47
|
def self.combine_on_ordinal(dna_a, dna_b, ordinals)
|
|
57
|
-
# TODO: Would this be better in dna.rb?
|
|
58
48
|
dna_a[0..ordinals[0]] + dna_b[(ordinals[0] + 1)..ordinals[1]] + dna_a[(ordinals[1] + 1)..dna_a.length - 1]
|
|
59
49
|
end
|
|
60
50
|
|
|
@@ -79,7 +69,7 @@ module Evopop
|
|
|
79
69
|
ordinals.each do |i|
|
|
80
70
|
n_ordinal = old_ordinal..i
|
|
81
71
|
|
|
82
|
-
cdna_a, cdna_b = build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, n_ordinal, synchronous)
|
|
72
|
+
cdna_a, cdna_b = CrossoverArray.build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, n_ordinal, synchronous)
|
|
83
73
|
|
|
84
74
|
synchronous = !synchronous
|
|
85
75
|
next_ordinal = i + 1
|
|
@@ -87,7 +77,7 @@ module Evopop
|
|
|
87
77
|
next if ordinals.last != next_ordinal - 1
|
|
88
78
|
|
|
89
79
|
ordinal_range = next_ordinal..(dna_length - 1)
|
|
90
|
-
cdna_a, cdna_b = build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, ordinal_range, synchronous)
|
|
80
|
+
cdna_a, cdna_b = CrossoverArray.build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, ordinal_range, synchronous)
|
|
91
81
|
end
|
|
92
82
|
|
|
93
83
|
[
|
|
@@ -96,15 +86,6 @@ module Evopop
|
|
|
96
86
|
]
|
|
97
87
|
end
|
|
98
88
|
|
|
99
|
-
def self.build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, ordinal_range, synchronous)
|
|
100
|
-
pdnas = [pdna_a, pdna_b]
|
|
101
|
-
pdnas.reverse! unless synchronous
|
|
102
|
-
cdna_a += pdnas[0][ordinal_range]
|
|
103
|
-
cdna_b += pdnas[1][ordinal_range]
|
|
104
|
-
|
|
105
|
-
[cdna_a, cdna_b]
|
|
106
|
-
end
|
|
107
|
-
|
|
108
89
|
def self.average(candidates, _params)
|
|
109
90
|
new_dna = Evopop::Dna.new(
|
|
110
91
|
candidates[0].dna.min_range,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Class for handling crossover against arrays.
|
|
4
|
+
# Supports
|
|
5
|
+
# * Single point crossover
|
|
6
|
+
# * n-point corssover
|
|
7
|
+
class CrossoverArray
|
|
8
|
+
def self.one_point_crossover(a, b, ordinal)
|
|
9
|
+
# Compose the dna of the first child from the first chunk of the
|
|
10
|
+
# first candidate and the second chunk of the second candidate
|
|
11
|
+
dna_a_left = a[0..ordinal]
|
|
12
|
+
dna_b_right = b[(ordinal + 1)..-1]
|
|
13
|
+
|
|
14
|
+
# Compose the dna of the second child from the first chunk of the
|
|
15
|
+
# first candidate and the second chunk of the second candidate
|
|
16
|
+
dna_b_left = b[0..ordinal]
|
|
17
|
+
dna_a_right = a[(ordinal + 1)..-1]
|
|
18
|
+
|
|
19
|
+
[dna_a_left + dna_b_right, dna_b_left + dna_a_right]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.two_point_crossover(cdna_a, cdna_b, ordinals)
|
|
23
|
+
dna_a = combine_on_ordinal(cdna_a, cdna_b, ordinals)
|
|
24
|
+
dna_b = combine_on_ordinal(cdna_b, cdna_a, ordinals)
|
|
25
|
+
|
|
26
|
+
[dna_a, dna_b]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.n_point_crossover(dna_a, dna_b, ordinals)
|
|
30
|
+
ret_a = []
|
|
31
|
+
ret_b = []
|
|
32
|
+
|
|
33
|
+
old_ordinal = 0
|
|
34
|
+
toggle = true
|
|
35
|
+
ordinals << dna_a.length + 1
|
|
36
|
+
|
|
37
|
+
ordinals.each do |ordinal|
|
|
38
|
+
if toggle
|
|
39
|
+
ret_a += dna_a[old_ordinal..ordinal]
|
|
40
|
+
ret_b += dna_b[old_ordinal..ordinal]
|
|
41
|
+
else
|
|
42
|
+
ret_a += dna_b[old_ordinal..ordinal]
|
|
43
|
+
ret_b += dna_a[old_ordinal..ordinal]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
old_ordinal = ordinal + 1
|
|
47
|
+
toggle = !toggle
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
[ret_a, ret_b]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.combine_on_ordinal(dna_a, dna_b, ordinals)
|
|
54
|
+
dna_a[0..ordinals[0]] + dna_b[(ordinals[0] + 1)..ordinals[1]] + dna_a[(ordinals[1] + 1)..dna_a.length - 1]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, ordinal_range, synchronous)
|
|
58
|
+
pdnas = [pdna_a, pdna_b]
|
|
59
|
+
pdnas.reverse! unless synchronous
|
|
60
|
+
cdna_a += pdnas[0][ordinal_range]
|
|
61
|
+
cdna_b += pdnas[1][ordinal_range]
|
|
62
|
+
|
|
63
|
+
[cdna_a, cdna_b]
|
|
64
|
+
end
|
|
65
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: evopop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Elvin Lucero
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-
|
|
11
|
+
date: 2017-09-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A simple library for implementing simple genetic algorithms.
|
|
14
14
|
email: elvin+evopop@1au.io
|
|
@@ -21,6 +21,7 @@ files:
|
|
|
21
21
|
- lib/evopop.rb
|
|
22
22
|
- lib/evopop/candidate.rb
|
|
23
23
|
- lib/evopop/crossover.rb
|
|
24
|
+
- lib/evopop/crossover_array.rb
|
|
24
25
|
- lib/evopop/dna.rb
|
|
25
26
|
- lib/evopop/population.rb
|
|
26
27
|
homepage: https://rubygems.org/gems/evopop
|