module Operator # Classic two-point crossover. It assumes two parents has the form of Arrays. # First, the cutting points in both parents are randomly selected, # then the middle parts are swapped, forming two new offsprings. # # Note the valid cutting point can be placed before the first element or after the last element of the array. # class CrossoverTwoPoints # Create a new two-point crossover operator. def initialize @random = Kernel end # The source of randomness, used for calling "random.rand( limit )", defaulting to 'Kernel' class. attr_accessor :random # Take parent1, parent2 arguments and produce [offspring1, offspring2]. # For instance: # # parent1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] # parent2 = [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ] # xover = CrossoverTwoPoints.new # # now producing the offsprings: # offspring1, offspring2 = xover.crossover( parent1, parent2 ) # offspring1 is [ 1, 2, 3, 4, 5, 16, 17, 18, 8, 9, 10 ] # offspring2 is [ 11, 12, 13, 14, 6, 7, 15, 19, 20, 21, 22, 23 ] # # This is a stochastic process, thus repeating: # offspring1, offspring2 = xover.crossover( parent1, parent2 ) # produces: # offspring1 is [ 1, 2, 20 ] # offspring2 is [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 3, 4, 5, 6, 7, 8, 9, 10, 21, 22, 23 ] # def crossover( parent1, parent2, dummy1=nil, dummy2=nil ) return parent1.clone, parent2.clone if parent1.empty? or parent2.empty? pt11 = @random.rand(parent1.size+1) pt12 = @random.rand(parent1.size+1) pt11,pt12 = [pt12,pt11] if pt11 > pt12 pt21 = @random.rand(parent2.size+1) pt22 = @random.rand(parent2.size+1) pt21,pt22 = [pt22,pt21] if pt21 > pt22 offs1 = parent1[0...pt11].clone offs1 = offs1.concat parent2[pt21...pt22] offs1 = offs1.concat parent1[pt12...parent1.size] offs2 = parent2[0...pt21].clone offs2 = offs2.concat parent1[pt11...pt12] offs2 = offs2.concat parent2[pt22...parent2.size] return offs1, offs2 end end end