evopop 0.0.5 → 0.1.0
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 +10 -4
- data/lib/evopop/candidate.rb +19 -8
- data/lib/evopop/crossover.rb +103 -79
- data/lib/evopop/dna.rb +73 -0
- data/lib/evopop/population.rb +89 -91
- data/lib/evopop.rb +41 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e6f9dc9b3385fbd06d69e3f4c8d062dab99b93b
|
4
|
+
data.tar.gz: e6ed6c011086a7901b5db7cad7c1e818827b7520
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cbcf3830e9c614853391008bce76aba3e55a74290cdc9059386af79a3681999fcc53c4bbda2e1c159a82d73300197f52fb2a9b9d45264e0976f84cb5f3a5c18
|
7
|
+
data.tar.gz: eb45100eee7f64bd1bfa03a2fbc3d050f852beaeb32c2e5f94ba6046773bbf06b0467ba19c26443c8018dbea391bce3ac8cbc3d7a3951da57e5a98fb0bac552d
|
data/README.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
[](https://travis-ci.org/elvinlucero/evopop)
|
2
|
+
[](https://codeclimate.com/github/elvinlucero/evopop)
|
3
|
+
|
1
4
|
Evopop
|
2
5
|
------------------------
|
3
6
|
|
4
|
-
This is a library for implementing simple genetic algorithms to evolve
|
7
|
+
This is a library for implementing simple genetic algorithms to evolve
|
8
|
+
over a fitness function.
|
5
9
|
|
6
10
|
|
7
11
|
``` ruby
|
@@ -9,7 +13,7 @@ This is a library for implementing simple genetic algorithms to evolve over a fi
|
|
9
13
|
require 'evopop'
|
10
14
|
|
11
15
|
# Initialize the population to be trained with good defaults.
|
12
|
-
population = Population.new
|
16
|
+
population = Evopop::Population.new
|
13
17
|
population.population_size = 1000
|
14
18
|
population.dna_len = 2
|
15
19
|
population.max_generations = 1000
|
@@ -19,7 +23,7 @@ population.mutation_range_min = -10.0
|
|
19
23
|
population.mutation_range_max = 10.0
|
20
24
|
population.mutation_num = 10
|
21
25
|
population.crossover_params = { ordinal: (DNA_LEN / 2) }.freeze
|
22
|
-
population.crossover_function = Crossover.method(:one_point)
|
26
|
+
population.crossover_function = Evopop::Crossover.method(:one_point)
|
23
27
|
population.fitness_function = proc do |dna|
|
24
28
|
Math.sin(dna[0]) + Math.cos(dna[1])
|
25
29
|
end
|
@@ -36,7 +40,9 @@ end
|
|
36
40
|
|
37
41
|
# Sort and print out candidate with highest fitness in the last generation.
|
38
42
|
population.train
|
39
|
-
puts "Finished #{population.max_generations} generations with the fittest
|
43
|
+
puts "Finished #{population.max_generations} generations with the fittest
|
44
|
+
candidate with a dna of #{population.candidates[0].dna} and a fitness
|
45
|
+
of #{population.candidates[0].fitness}."
|
40
46
|
|
41
47
|
|
42
48
|
```
|
data/lib/evopop/candidate.rb
CHANGED
@@ -1,11 +1,22 @@
|
|
1
|
-
#
|
2
|
-
# as a simple data structure which contains the DNA and fitness over the
|
3
|
-
# fitness function.
|
4
|
-
class Candidate
|
5
|
-
attr_accessor :dna, :fitness
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
module Evopop
|
4
|
+
# Public: Represents a candidate in the population.Evopop::Candidates are
|
5
|
+
# abstracted as a simple data structure which contains the DNA and fitness
|
6
|
+
# over the fitness function.
|
7
|
+
class Candidate
|
8
|
+
attr_accessor :dna, :fitness
|
9
|
+
|
10
|
+
# Simple initialization of candidate object.
|
11
|
+
def initialize(dna)
|
12
|
+
@dna = dna
|
13
|
+
end
|
14
|
+
|
15
|
+
def compose_parent_dna(c0, c1)
|
16
|
+
# Compose the dna of the first child from the first chunk of the
|
17
|
+
# first candidate and the second chunk of the second candidate
|
18
|
+
# dna0_left = c0.dna.take(ordinal)
|
19
|
+
# dna1_right = c1.dna.drop(ordinal)
|
20
|
+
end
|
10
21
|
end
|
11
22
|
end
|
data/lib/evopop/crossover.rb
CHANGED
@@ -1,101 +1,125 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
module Crossover
|
4
|
-
# Perform 1 point crossover for a pair of candidates at the ordinal.
|
5
|
-
# http://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)#One-point_crossover
|
6
|
-
def self.one_point(candidates, params)
|
7
|
-
ordinal = params[:ordinal]
|
8
|
-
|
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
|
-
dna0_left = candidates[0].dna.take(ordinal)
|
12
|
-
dna1_right = candidates[1].dna.drop(ordinal)
|
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
|
-
dna1_left = candidates[1].dna.take(ordinal)
|
17
|
-
dna0_right = candidates[0].dna.drop(ordinal)
|
18
|
-
|
19
|
-
# Initialize and assign DNA to children.
|
20
|
-
children = [Candidate.new(dna0_left + dna1_right),
|
21
|
-
Candidate.new(dna1_left + dna0_right)]
|
22
|
-
|
23
|
-
children
|
24
|
-
end
|
1
|
+
# frozen_string_literal: true
|
25
2
|
|
26
|
-
|
27
|
-
#
|
3
|
+
module Evopop
|
4
|
+
# Represents a collection of well known crossover functions.
|
5
|
+
#
|
6
|
+
module Crossover
|
7
|
+
# Perform 1 point crossover for a pair of candidates at the ordinal.
|
8
|
+
# http://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)#One-point_crossover
|
9
|
+
def self.one_point(candidates, params)
|
10
|
+
ordinal = params[:ordinal]
|
11
|
+
|
12
|
+
# Compose the dna of the first child from the first chunk of the
|
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
|
+
|
22
|
+
min_range = candidates[0].dna.min_range
|
23
|
+
max_range = candidates[1].dna.max_range
|
24
|
+
|
25
|
+
min_mutation = candidates[1].dna.min_mutation
|
26
|
+
max_mutation = candidates[1].dna.max_mutation
|
27
|
+
|
28
|
+
dna_a = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation, dna_a_left + dna_b_right)
|
29
|
+
dna_b = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation, dna_b_left + dna_a_right)
|
30
|
+
|
31
|
+
# Initialize and assign DNA to children.
|
32
|
+
[
|
33
|
+
Evopop::Candidate.new(dna_a),
|
34
|
+
Evopop::Candidate.new(dna_b)
|
35
|
+
]
|
36
|
+
end
|
28
37
|
|
29
|
-
|
30
|
-
#
|
31
|
-
# Make sure to sort.
|
32
|
-
ordinals = params[:ordinals].split(',').sort.collect(&:to_i)
|
38
|
+
# Perform two point crossover over a pair of candidates. Will output two
|
39
|
+
# children with genes spliced over the crossover points.
|
33
40
|
|
34
|
-
|
35
|
-
|
36
|
-
|
41
|
+
def self.two_point(candidates, params)
|
42
|
+
# Ordinals should be stored in params as a comma separated list. I.e. "1,2".
|
43
|
+
# Make sure to sort.
|
44
|
+
ordinals = params[:ordinals].split(',').sort.collect(&:to_i)
|
37
45
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
]
|
46
|
+
# Initialize and assign the DNA of the children.
|
47
|
+
cdna_a = candidates[0].dna
|
48
|
+
cdna_b = candidates[1].dna
|
42
49
|
|
43
|
-
|
44
|
-
|
50
|
+
[
|
51
|
+
Evopop::Candidate.new(combine_on_ordinal(cdna_a, cdna_b, ordinals)),
|
52
|
+
Evopop::Candidate.new(combine_on_ordinal(cdna_b, cdna_a, ordinals))
|
53
|
+
]
|
54
|
+
end
|
45
55
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
def self.n_point(candidates, params)
|
51
|
-
ordinals = params[:ordinals].split(',').sort.collect(&:to_i)
|
56
|
+
def self.combine_on_ordinal(dna_a, dna_b, ordinals)
|
57
|
+
# TODO: Would this be better in dna.rb?
|
58
|
+
dna_a[0..ordinals[0]] + dna_b[(ordinals[0] + 1)..ordinals[1]] + dna_a[(ordinals[1] + 1)..dna_a.length - 1]
|
59
|
+
end
|
52
60
|
|
53
|
-
|
54
|
-
|
61
|
+
# Perform n_point crossover for a pair of candidates. Will output two children from the n_point crossover.
|
62
|
+
#
|
63
|
+
# Example:
|
64
|
+
# n_point
|
65
|
+
def self.n_point(candidates, params)
|
66
|
+
ordinals = params[:ordinals].split(',').sort.collect(&:to_i)
|
55
67
|
|
56
|
-
|
68
|
+
pdna_a = candidates[0].dna
|
69
|
+
pdna_b = candidates[1].dna
|
57
70
|
|
58
|
-
|
59
|
-
cdna1 = []
|
71
|
+
dna_length = candidates[0].dna.length
|
60
72
|
|
61
|
-
|
62
|
-
|
73
|
+
cdna_a = []
|
74
|
+
cdna_b = []
|
63
75
|
|
64
|
-
|
65
|
-
|
66
|
-
cdna0 += pdna0[old_ordinal..i]
|
67
|
-
cdna1 += pdna1[old_ordinal..i]
|
68
|
-
else
|
69
|
-
cdna0 += pdna1[old_ordinal..i]
|
70
|
-
cdna1 += pdna0[old_ordinal..i]
|
71
|
-
end
|
76
|
+
old_ordinal = 0
|
77
|
+
synchronous = ordinals[0] == 0 ? false : true
|
72
78
|
|
73
|
-
|
74
|
-
|
79
|
+
ordinals.each do |i|
|
80
|
+
n_ordinal = old_ordinal..i
|
75
81
|
|
76
|
-
|
82
|
+
cdna_a, cdna_b = build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, n_ordinal, synchronous)
|
77
83
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
+
synchronous = !synchronous
|
85
|
+
next_ordinal = i + 1
|
86
|
+
|
87
|
+
next if ordinals.last != next_ordinal - 1
|
88
|
+
|
89
|
+
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)
|
84
91
|
end
|
85
|
-
end
|
86
92
|
|
87
|
-
|
88
|
-
|
93
|
+
[
|
94
|
+
Evopop::Candidate.new(cdna_a),
|
95
|
+
Evopop::Candidate.new(cdna_b)
|
96
|
+
]
|
97
|
+
end
|
89
98
|
|
90
|
-
|
91
|
-
|
92
|
-
|
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]
|
93
104
|
|
94
|
-
|
95
|
-
# Initialize the dna of the child with the average of the parents' dna.
|
96
|
-
child.dna << (candidates[0].dna[j] + candidates[1].dna[j]) / 2.0
|
105
|
+
[cdna_a, cdna_b]
|
97
106
|
end
|
98
107
|
|
99
|
-
|
108
|
+
def self.average(candidates, _params)
|
109
|
+
new_dna = Evopop::Dna.new(
|
110
|
+
candidates[0].dna.min_range,
|
111
|
+
candidates[0].dna.max_range,
|
112
|
+
candidates[0].dna.min_mutation,
|
113
|
+
candidates[0].dna.max_mutation,
|
114
|
+
candidates[0].dna.length
|
115
|
+
)
|
116
|
+
new_dna.dna = []
|
117
|
+
(0...candidates[0].dna.length).each do |j|
|
118
|
+
# Initialize the dna of the child with the average of the parents' dna.
|
119
|
+
new_dna.dna << (candidates[0].dna[j] + candidates[1].dna[j]) / 2.0
|
120
|
+
end
|
121
|
+
|
122
|
+
[Evopop::Candidate.new(new_dna)]
|
123
|
+
end
|
100
124
|
end
|
101
125
|
end
|
data/lib/evopop/dna.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Evopop
|
4
|
+
# Represents a Dna structure, like an array of floating point values
|
5
|
+
class Dna
|
6
|
+
attr_accessor :dna, :dna_len, :min_range, :max_range, :min_mutation, :max_mutation
|
7
|
+
|
8
|
+
def initialize(min_range, max_range, min_mutation, max_mutation, dna_len)
|
9
|
+
# TODO: Extract these to a DnaProperties class or something so we don't
|
10
|
+
# have to couple parameter passsing so much.
|
11
|
+
@min_range = min_range
|
12
|
+
@max_range = max_range
|
13
|
+
@min_mutation = min_mutation
|
14
|
+
@max_mutation = max_mutation
|
15
|
+
@dna = []
|
16
|
+
@dna_len = dna_len
|
17
|
+
|
18
|
+
dna_len_range.each do
|
19
|
+
@dna << random_dna_val
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.create(min_range, max_range, min_mutation, max_mutation, dna)
|
24
|
+
new_dna = new(min_range, max_range, min_mutation, max_mutation, dna.size)
|
25
|
+
new_dna.dna = dna
|
26
|
+
new_dna
|
27
|
+
end
|
28
|
+
|
29
|
+
def dna_len_range
|
30
|
+
0...@dna_len
|
31
|
+
end
|
32
|
+
|
33
|
+
def random_dna_val
|
34
|
+
Random.rand(@min_range...@max_range)
|
35
|
+
end
|
36
|
+
|
37
|
+
def random_mutation_val
|
38
|
+
Random.rand(@min_mutation...@max_mutation)
|
39
|
+
end
|
40
|
+
|
41
|
+
def mutate(i)
|
42
|
+
@dna[i] += [random_mutation_val, -1 * random_mutation_val].sample
|
43
|
+
end
|
44
|
+
|
45
|
+
def length
|
46
|
+
@dna.length
|
47
|
+
end
|
48
|
+
|
49
|
+
def take(num)
|
50
|
+
@dna.take(num)
|
51
|
+
end
|
52
|
+
|
53
|
+
def drop(ordinal)
|
54
|
+
@dna.drop(ordinal)
|
55
|
+
end
|
56
|
+
|
57
|
+
def [](key)
|
58
|
+
@dna[key]
|
59
|
+
end
|
60
|
+
|
61
|
+
def []=(key, value)
|
62
|
+
@dna[key] = value
|
63
|
+
end
|
64
|
+
|
65
|
+
def ==(other)
|
66
|
+
@dna == other.dna
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
@dna.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/evopop/population.rb
CHANGED
@@ -1,110 +1,108 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# population.
|
10
|
-
# population
|
11
|
-
# population.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@crossover_function = Crossover.method(:one_point)
|
30
|
-
@fitness_function = proc do |dna|
|
31
|
-
Math.sin(dna[0])
|
32
|
-
end
|
33
|
-
|
34
|
-
create
|
35
|
-
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
|
-
# Creates a new population class. Should be called after all the
|
40
|
-
# parameters have been set to the attributes.
|
41
|
-
def create
|
42
|
-
@candidates = Array.new(@population_size) do
|
43
|
-
candidate = Candidate.new
|
44
|
-
(0...@dna_len).each do
|
45
|
-
candidate.dna << Random.rand(@initial_range_min...@initial_range_max)
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Evopop
|
4
|
+
# Represents the population that is being trained. Has various methods
|
5
|
+
# relevant to training.
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
# population = Evopop::Population.new
|
10
|
+
# ... initialize population with parameters ...
|
11
|
+
# population.train
|
12
|
+
# population.crossover
|
13
|
+
# population.mutate
|
14
|
+
class Population
|
15
|
+
attr_accessor :candidates, :population_size, :max_generations,
|
16
|
+
:crossover_function, :crossover_params, :initial_range_min,
|
17
|
+
:initial_range_max, :mutation_range_min, :mutation_range_max,
|
18
|
+
:mutation_num, :fitness_function, :dna_len, :average_fitness
|
19
|
+
|
20
|
+
# Initializes the attributes with default values. This is not guaranteed
|
21
|
+
# to reach maxima.
|
22
|
+
def initialize
|
23
|
+
Evopop.config.instance_variables.each do |iv|
|
24
|
+
instance_variable_set(
|
25
|
+
iv,
|
26
|
+
Evopop.config.instance_variable_get(iv)
|
27
|
+
)
|
46
28
|
end
|
47
|
-
|
29
|
+
create
|
30
|
+
self
|
48
31
|
end
|
49
|
-
end
|
50
32
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
33
|
+
# Creates a new set of population. Should be called after all the
|
34
|
+
# parameters have been set to the attributes.
|
35
|
+
def create
|
36
|
+
@candidates = Array.new(@population_size) do
|
37
|
+
dna = Evopop::Dna.new(
|
38
|
+
@initial_range_min,
|
39
|
+
@initial_range_max,
|
40
|
+
@mutation_range_min,
|
41
|
+
@mutation_range_max,
|
42
|
+
@dna_len
|
43
|
+
)
|
44
|
+
candidate = Evopop::Candidate.new(dna)
|
45
|
+
candidate
|
46
|
+
end
|
58
47
|
end
|
59
48
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
49
|
+
# Determines the fitness of the population and thereafter sorts it
|
50
|
+
# based on fitness descdending (high fitness first, low fitness last).
|
51
|
+
def train
|
52
|
+
average_fitness = 0
|
53
|
+
@candidates.each do |c|
|
54
|
+
c.fitness = fitness_function.call(c.dna)
|
55
|
+
average_fitness += + c.fitness
|
56
|
+
end
|
67
57
|
|
68
|
-
|
69
|
-
# random candidates in from a top percentile of the population and
|
70
|
-
# performs one point crossover, producing new offspring equal to the
|
71
|
-
# population size attribute.
|
72
|
-
def crossover
|
73
|
-
# Define the candidates that can have children.
|
74
|
-
@candidates = @candidates.take((@population_size * 0.75).to_i)
|
58
|
+
average_fitness /= @population_size
|
75
59
|
|
76
|
-
|
60
|
+
@average_fitness << average_fitness
|
77
61
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
params = @crossover_params
|
62
|
+
@candidates = @candidates.sort_by(&:fitness)
|
63
|
+
@candidates = @candidates.reverse
|
64
|
+
end
|
82
65
|
|
83
|
-
|
66
|
+
# Performs simple mechanism of crossover - in this case picks two
|
67
|
+
# random candidates in from a top percentile of the population and
|
68
|
+
# performs one point crossover, producing new offspring equal to the
|
69
|
+
# population size attribute.
|
70
|
+
def crossover
|
71
|
+
new_generation = []
|
72
|
+
|
73
|
+
# For all the top candidates, take the top 2 and crossover
|
74
|
+
(0...@population_size).each do
|
75
|
+
children = @crossover_function.call(top_candidates.sample(2), @crossover_params)
|
76
|
+
new_generation += children
|
77
|
+
|
78
|
+
if new_generation.length >= population_size
|
79
|
+
new_generation = new_generation.take(population_size)
|
80
|
+
break
|
81
|
+
end
|
82
|
+
end
|
84
83
|
|
85
|
-
|
84
|
+
@candidates = new_generation
|
85
|
+
end
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
# Performs simple mutation over the next generation. In this case,
|
88
|
+
# it either adds or substracts an amount to each dimension given the
|
89
|
+
# mutation range attributes.
|
90
|
+
def mutate
|
91
|
+
mutated_candidates.each do |c|
|
92
|
+
c.dna.dna_len_range.each do |i|
|
93
|
+
c.dna.mutate(i)
|
94
|
+
end
|
92
95
|
end
|
93
96
|
end
|
94
97
|
|
95
|
-
|
96
|
-
end
|
98
|
+
private
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
def mutate
|
102
|
-
mutated = @candidates.sample(mutation_num)
|
100
|
+
def top_candidates
|
101
|
+
@candidates.take((@population_size * 0.75).to_i)
|
102
|
+
end
|
103
103
|
|
104
|
-
|
105
|
-
(
|
106
|
-
c.dna[i] = c.dna[i] + Random.rand(@mutation_range_min...@mutation_range_max)
|
107
|
-
end
|
104
|
+
def mutated_candidates
|
105
|
+
@candidates.sample(@mutation_num)
|
108
106
|
end
|
109
107
|
end
|
110
108
|
end
|
data/lib/evopop.rb
CHANGED
@@ -1,7 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'evopop/population'
|
2
4
|
require 'evopop/candidate'
|
3
5
|
require 'evopop/crossover'
|
6
|
+
require 'evopop/dna'
|
4
7
|
|
5
8
|
# Toplevel class for evopop project
|
6
9
|
module Evopop
|
10
|
+
class << self
|
11
|
+
attr_accessor :config
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.popconfig
|
15
|
+
@config ||= PopulationConfig.new
|
16
|
+
yield(@config)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Defines the configuration to be available to all of Evopop
|
20
|
+
class PopulationConfig
|
21
|
+
attr_accessor :average_fitness, :population_size, :max_generations,
|
22
|
+
:initial_range_min, :initial_range_max, :mutation_range_min,
|
23
|
+
:mutation_range_max, :mutation_num, :dna_len,
|
24
|
+
:crossover_params, :crossover_function, :fitness_function
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@average_fitness = []
|
28
|
+
@population_size = 100
|
29
|
+
@max_generations = 100
|
30
|
+
@initial_range_min = -100
|
31
|
+
@initial_range_max = 100
|
32
|
+
@mutation_range_min = -10
|
33
|
+
@mutation_range_max = 10
|
34
|
+
@mutation_num = (0.10 * @population_size).to_i
|
35
|
+
@dna_len = 1
|
36
|
+
@crossover_params = { ordinal: (@dna_len / 2) }
|
37
|
+
|
38
|
+
@crossover_function = Evopop::Crossover.method(:one_point)
|
39
|
+
@fitness_function = proc do |dna|
|
40
|
+
Math.sin(dna[0])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Evopop.popconfig do |config|
|
47
|
+
# Configure evopop here.
|
7
48
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evopop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elvin Lucero
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A simple library for implementing simple genetic algorithms.
|
14
|
-
email: elvin+evopop@
|
14
|
+
email: elvin+evopop@1au.io
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
@@ -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/dna.rb
|
24
25
|
- lib/evopop/population.rb
|
25
26
|
homepage: https://rubygems.org/gems/evopop
|
26
27
|
licenses:
|
@@ -42,7 +43,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
42
43
|
version: '0'
|
43
44
|
requirements: []
|
44
45
|
rubyforge_project:
|
45
|
-
rubygems_version: 2.
|
46
|
+
rubygems_version: 2.6.12
|
46
47
|
signing_key:
|
47
48
|
specification_version: 4
|
48
49
|
summary: A simple library for implementing simple genetic algorithms.
|