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 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