evopop 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|