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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e6f9dc9b3385fbd06d69e3f4c8d062dab99b93b
4
- data.tar.gz: e6ed6c011086a7901b5db7cad7c1e818827b7520
3
+ metadata.gz: 7807b58e3f22619a088086082e9e487bfcaa367c
4
+ data.tar.gz: e8b1fe7390fe1bd84a2df0991c3b2106bb1e36b3
5
5
  SHA512:
6
- metadata.gz: 7cbcf3830e9c614853391008bce76aba3e55a74290cdc9059386af79a3681999fcc53c4bbda2e1c159a82d73300197f52fb2a9b9d45264e0976f84cb5f3a5c18
7
- data.tar.gz: eb45100eee7f64bd1bfa03a2fbc3d050f852beaeb32c2e5f94ba6046773bbf06b0467ba19c26443c8018dbea391bce3ac8cbc3d7a3951da57e5a98fb0bac552d
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 = 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
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 = 10
25
- population.crossover_params = { ordinal: (DNA_LEN / 2) }.freeze
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 = proc do |dna|
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 = 100
29
+ @population_size = 500
29
30
  @max_generations = 100
30
31
  @initial_range_min = -100
31
32
  @initial_range_max = 100
@@ -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
- # 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
-
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, 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)
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
- # Initialize and assign the DNA of the children.
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(combine_on_ordinal(cdna_a, cdna_b, ordinals)),
52
- Evopop::Candidate.new(combine_on_ordinal(cdna_b, cdna_a, ordinals))
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.0
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-07-08 00:00:00.000000000 Z
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