```module Util

# This class implements a necessary logic for ALPS strategy. See:
# http://www.cs.york.ac.uk/rts/docs/GECCO_2006/docs/p815.pdf
module AlpsIndividual

# Set the AGE_GAP parameter of the ALPS. Required for AlpsIndividual.age_limits computation.
# This is the multiplier of the age_limits serie.
def AlpsIndividual.age_gap gap
@@age_gap = gap
@@limits = nil
end

# Set the aging scheme parameter. Required for AlpsIndividual.age_limits computation.
# Allowed values are:
#   :linear .. 1, 2, 3, 4, 5...
#   :fibonacci .. 1, 2, 3, 5, 8, 13, 21...
#   :polynomial .. 1, 2, 4, 9, 16, 25, 49...
#   :exponential .. 1, 2, 4, 8, 16, 32, 64...
#
def AlpsIndividual.aging_scheme scheme
@@aging_scheme = scheme
@@limits = nil
end

# Set the maximum number of layers (the requred length of the AlpsIndividual.age_limits serie).
def AlpsIndividual.layers layers
raise "AlpsIndividual: not enough layers, needed at least 2" if layers < 2
@@layers = layers
@@limits = nil
end

# Get the age limit for each layer. The result is the AlpsIndividual.aging_scheme serie
# of the AlpsIndividual.layers length, multiplied by AlpsIndividual.age_gap.
def AlpsIndividual.age_limits
return @@limits unless @@limits.nil?

case @@aging_scheme

when :linear
s = [ 1 ]
s << s.last + 1 while s.size < @@layers

when :fibonacci
s = [ 1, 2 ] # as defined in the original paper, there is a missing F1=1 member
s << s.last + s[ s.size-2 ] while s.size < @@layers

when :polynomial
s = []
(1..@@layers).each { |i| s << i * i }

when :exponential
s = []
(0...@@layers).each { |i| s << 2 ** i }

else
raise "AlpsIndividual: a scheme '#{@@aging_scheme}' not supported"

end

return @@limits = s.map { |i| i * @@age_gap }
end

# The age of the individual. The newly created one has the age 0.
# If the genome of the individual is based of the genome(s) of the parent(s),
# AlpsIndividual#parents method is to be used.
#
def age
@age = 0 unless defined? @age
@age
end

# Compute the AlpsIndividual#age of the individual from ages of it's parent(s).
# If p1 and p2 are AlpsIndividual parents, the age will be:
#   my.age = 1 + max( p1.age, p2.age )
#
def parents( p1, p2=nil )
@age = 1 + ( ( p2.nil? or p1.age > p2.age ) ? p1.age : p2.age )
end

# Compute the index of the layer the individual belongs to.
# The result depends on AlpsIndividual.age_limits and AlpsIndividual#age.
#
def layer
return nil unless defined? @@limits
AlpsIndividual.age_limits.each_with_index do |max,i|
return i if self.age <= max
end
return @@limits.size
end

end

end```