Module: Evopop::Crossover

Defined in:
lib/evopop/crossover.rb

Overview

Represents a collection of well known crossover functions.

Class Method Summary collapse

Class Method Details

.average(candidates, _params) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/evopop/crossover.rb', line 89

def self.average(candidates, _params)
  new_dna = Evopop::Dna.new(
    candidates[0].dna.min_range,
    candidates[0].dna.max_range,
    candidates[0].dna.min_mutation,
    candidates[0].dna.max_mutation,
    candidates[0].dna.length
  )
  new_dna.dna = []
  (0...candidates[0].dna.length).each do |j|
    # Initialize the dna of the child with the average of the parents' dna.
    new_dna.dna << (candidates[0].dna[j] + candidates[1].dna[j]) / 2.0
  end

  [Evopop::Candidate.new(new_dna)]
end

.combine_on_ordinal(dna_a, dna_b, ordinals) ⇒ Object



47
48
49
# File 'lib/evopop/crossover.rb', line 47

def self.combine_on_ordinal(dna_a, dna_b, ordinals)
  dna_a[0..ordinals[0]] + dna_b[(ordinals[0] + 1)..ordinals[1]] + dna_a[(ordinals[1] + 1)..dna_a.length - 1]
end

.n_point(candidates, params) ⇒ Object

Perform n_point crossover for a pair of candidates. Will output two children from the n_point crossover.

Example: n_point



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/evopop/crossover.rb', line 55

def self.n_point(candidates, params)
  ordinals = params[:ordinals].split(',').sort.collect(&:to_i)

  pdna_a = candidates[0].dna
  pdna_b = candidates[1].dna

  dna_length = candidates[0].dna.length

  cdna_a = []
  cdna_b = []

  old_ordinal = 0
  synchronous = ordinals[0] == 0 ? false : true

  ordinals.each do |i|
    n_ordinal = old_ordinal..i

    cdna_a, cdna_b = CrossoverArray.build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, n_ordinal, synchronous)

    synchronous = !synchronous
    next_ordinal = i + 1

    next if ordinals.last != next_ordinal - 1

    ordinal_range = next_ordinal..(dna_length - 1)
    cdna_a, cdna_b = CrossoverArray.build_dna_by_synchronous(cdna_a, cdna_b, pdna_a, pdna_b, ordinal_range, synchronous)
  end

  [
    Evopop::Candidate.new(cdna_a),
    Evopop::Candidate.new(cdna_b)
  ]
end

.one_point(candidates, params) ⇒ Object

Perform 1 point crossover for a pair of candidates at the ordinal. en.wikipedia.org/wiki/Crossover_(genetic_algorithm)#One-point_crossover



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/evopop/crossover.rb', line 9

def self.one_point(candidates, params)
  ordinal = params[:ordinal]
  arr_a, arr_b = CrossoverArray.one_point_crossover(candidates[0].dna, candidates[1].dna, ordinal)

  # TODO: Move this to its own class, DnaRange
  min_range = candidates[0].dna.min_range
  max_range = candidates[1].dna.max_range

  # TODO: Move this to its own class, DnaMutationRange
  min_mutation = candidates[1].dna.min_mutation
  max_mutation = candidates[1].dna.max_mutation

  dna_a = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation, arr_a)
  dna_b = Evopop::Dna.create(min_range, max_range, min_mutation, max_mutation, arr_b)

  # Initialize and assign DNA to children.
  [
    Evopop::Candidate.new(dna_a),
    Evopop::Candidate.new(dna_b)
  ]
end

.two_point(candidates, params) ⇒ Object

Perform two point crossover over a pair of candidates. Will output two children with genes spliced over the crossover points.



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/evopop/crossover.rb', line 34

def self.two_point(candidates, params)
  # Ordinals should be stored in params as a comma separated list. I.e. "1,2".
  # Make sure to sort.
  ordinals = params[:ordinals].split(',').sort.collect(&:to_i)

  cdna_a, cdna_b = CrossoverArray.two_point_crossover(candidates[0].dna, candidates[1].dna, ordinals)

  [
    Evopop::Candidate.new(cdna_a),
    Evopop::Candidate.new(cdna_b)
  ]
end