evopop 0.0.5 → 0.1.0

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: 04d8cc00d713a77a686106e3be50d26d95889ec0
4
- data.tar.gz: 0ee8bc2bca81622f24aa80184fa942fce901064d
3
+ metadata.gz: 5e6f9dc9b3385fbd06d69e3f4c8d062dab99b93b
4
+ data.tar.gz: e6ed6c011086a7901b5db7cad7c1e818827b7520
5
5
  SHA512:
6
- metadata.gz: 2cae28bdfd5bc8d7e9aa431bfd2ff5765cbe7c5e4a7e2e1f28fb07269b8b42daf90e0554c772dfbe060735c3a278937bdf59752a192c1e623dacce55fd51679f
7
- data.tar.gz: 6d418afe3bf3d4ec71e1e0f10d6877528fba2206759672d6299b27957e3d4f7e508740c5717fb13fab832933d4ebde93dbadf20849f52198950153f189ad9600
6
+ metadata.gz: 7cbcf3830e9c614853391008bce76aba3e55a74290cdc9059386af79a3681999fcc53c4bbda2e1c159a82d73300197f52fb2a9b9d45264e0976f84cb5f3a5c18
7
+ data.tar.gz: eb45100eee7f64bd1bfa03a2fbc3d050f852beaeb32c2e5f94ba6046773bbf06b0467ba19c26443c8018dbea391bce3ac8cbc3d7a3951da57e5a98fb0bac552d
data/README.md CHANGED
@@ -1,7 +1,11 @@
1
+ [![Build Status](https://travis-ci.org/elvinlucero/evopop.svg?branch=master)](https://travis-ci.org/elvinlucero/evopop)
2
+ [![Code Climate](https://codeclimate.com/github/elvinlucero/evopop/badges/gpa.svg)](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 over a fitness function.
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 candidate with a dna of #{population.candidates[0].dna} and a fitness of #{population.candidates[0].fitness}."
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
  ```
@@ -1,11 +1,22 @@
1
- # Public: Represents a candidate in the population. Candidates are abstracted
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
- # Simple initialization of candidate object.
8
- def initialize(dna = [])
9
- @dna = dna
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
@@ -1,101 +1,125 @@
1
- # Represents a collection of well known crossover functions.
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
- # Perform two point crossover over a pair of candidates. Will output two
27
- # children with genes spliced over the crossover points.
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
- def self.two_point(candidates, params)
30
- # Ordinals should be stored in params as a comma separated list. I.e. "1,2".
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
- # Initialize and assign the DNA of the children.
35
- cdna0 = candidates[0].dna
36
- cdna1 = candidates[1].dna
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
- children = [
39
- Candidate.new(cdna0[0..ordinals[0]] + cdna1[(ordinals[0] + 1)..ordinals[1]] + cdna0[(ordinals[1] + 1)..cdna0.length - 1]),
40
- Candidate.new(cdna1[0..ordinals[0]] + cdna0[(ordinals[0] + 1)..ordinals[1]] + cdna1[(ordinals[1] + 1)..cdna1.length - 1])
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
- children
44
- end
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
- # Perform n_point crossover for a pair of candidates. Will output two children from the n_point crossover.
47
- #
48
- # Example:
49
- # n_point
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
- pdna0 = candidates[0].dna
54
- pdna1 = candidates[1].dna
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
- dna_length = candidates[0].dna.length
68
+ pdna_a = candidates[0].dna
69
+ pdna_b = candidates[1].dna
57
70
 
58
- cdna0 = []
59
- cdna1 = []
71
+ dna_length = candidates[0].dna.length
60
72
 
61
- old_ordinal = 0
62
- synchronous = ordinals[0] == 0 ? false : true
73
+ cdna_a = []
74
+ cdna_b = []
63
75
 
64
- ordinals.each do |i|
65
- if synchronous
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
- synchronous = !synchronous
74
- old_ordinal = i + 1
79
+ ordinals.each do |i|
80
+ n_ordinal = old_ordinal..i
75
81
 
76
- next if ordinals.last != old_ordinal - 1
82
+ cdna_a, cdna_b = build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, n_ordinal, synchronous)
77
83
 
78
- if synchronous
79
- cdna0 += pdna0[old_ordinal..dna_length - 1]
80
- cdna1 += pdna1[old_ordinal..dna_length - 1]
81
- else
82
- cdna0 += pdna1[old_ordinal..dna_length - 1]
83
- cdna1 += pdna0[old_ordinal..dna_length - 1]
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
- [Candidate.new(cdna0), Candidate.new(cdna1)]
88
- end
93
+ [
94
+ Evopop::Candidate.new(cdna_a),
95
+ Evopop::Candidate.new(cdna_b)
96
+ ]
97
+ end
89
98
 
90
- def self.average(candidates, _params)
91
- child = Candidate.new
92
- dna_length = candidates[0].dna.length
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
- (0...dna_length).each do |j|
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
- [child]
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
@@ -1,110 +1,108 @@
1
-
2
- # Represents the population that is being trained. Has various methods
3
- # relevant to training.
4
- #
5
- #
6
- # Examples
7
- # population = Population.new
8
- # ... initialize population with parameters ...
9
- # population.train
10
- # population.crossover
11
- # population.mutate
12
- class Population
13
- attr_accessor :candidates, :population_size, :max_generations, :crossover_function, :crossover_params, :initial_range_min, :initial_range_max, :mutation_range_min, :mutation_range_max, :mutation_num, :fitness_function, :dna_len, :average_fitness
14
-
15
- # Initializes the attributes with default values. This is not guaranteed
16
- # to reach maxima.
17
- def initialize
18
- @average_fitness = []
19
- @population_size = 100
20
- @max_generations = 100
21
- @initial_range_min = -100
22
- @initial_range_max = 100
23
- @mutation_range_min = -10
24
- @mutation_range_max = 10
25
- @mutation_num = (0.10 * @population_size).to_i
26
- @dna_len = 1
27
- @crossover_params = { ordinal: (@dna_len / 2) }
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
- candidate
29
+ create
30
+ self
48
31
  end
49
- end
50
32
 
51
- # Determines the fitness of the population and thereafter sorts it
52
- # based on fitness descdending (high fitness first, low fitness last).
53
- def train
54
- average_fitness = 0
55
- @candidates.each do |c|
56
- c.fitness = fitness_function.call(c.dna)
57
- average_fitness += + c.fitness
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
- average_fitness /= @population_size
61
-
62
- @average_fitness << average_fitness
63
-
64
- @candidates = @candidates.sort_by(&:fitness)
65
- @candidates = @candidates.reverse
66
- end
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
- # Performs simple mechanism of crossover - in this case picks two
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
- new_generation = []
60
+ @average_fitness << average_fitness
77
61
 
78
- (0...@population_size).each do
79
- # For each of the top 75% of the population take 2
80
- couple = @candidates.sample(2)
81
- params = @crossover_params
62
+ @candidates = @candidates.sort_by(&:fitness)
63
+ @candidates = @candidates.reverse
64
+ end
82
65
 
83
- children = @crossover_function.call(couple, params)
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
- new_generation += children
84
+ @candidates = new_generation
85
+ end
86
86
 
87
- # When we go above set population_size, take the first population_size
88
- # candidates, ignore the rest.
89
- if new_generation.length >= population_size
90
- new_generation = new_generation.take(population_size)
91
- break
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
- @candidates = new_generation
96
- end
98
+ private
97
99
 
98
- # Performs simple mutation over the next generation. In this case,
99
- # it either adds or substracts an amount to each dimension given the
100
- # mutation range attributes.
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
- mutated.each do |c|
105
- (0...@dna_len).each do |i|
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.5
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: 2016-04-24 00:00:00.000000000 Z
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@pluots.io
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.4.5.1
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.