Module: Evolvable

Extended by:
Forwardable
Defined in:
lib/evolvable.rb,
lib/evolvable/gene.rb,
lib/evolvable/goal.rb,
lib/evolvable/genome.rb,
lib/evolvable/version.rb,
lib/evolvable/mutation.rb,
lib/evolvable/community.rb,
lib/evolvable/evolution.rb,
lib/evolvable/selection.rb,
lib/evolvable/count_gene.rb,
lib/evolvable/evaluation.rb,
lib/evolvable/gene_space.rb,
lib/evolvable/population.rb,
lib/evolvable/serializer.rb,
lib/evolvable/gene_cluster.rb,
lib/evolvable/equalize_goal.rb,
lib/evolvable/maximize_goal.rb,
lib/evolvable/minimize_goal.rb,
lib/evolvable/point_crossover.rb,
lib/evolvable/gene_combination.rb,
lib/evolvable/rigid_count_gene.rb,
lib/evolvable/uniform_crossover.rb

Overview

Quick start:

  1. Include Evolvable in your Ruby class
  2. Define genes with the macro-style gene method
  3. Have the #fitness method return a numeric value
  4. Initialize a population and evolve it

Example population of "shirts" with various colors, buttons, and collars.

# Step 1
class Shirt
  include Evolvable

  # Step 2
  gene :color, type: ColorGene # count: 1 default
  gene :buttons, type: ButtonGene, count: 0..10 # Builds an array of genes that can vary in size
  gene :collar, type: CollarGene, count: 0..1 # Collar optional

  # Step 3
  attr_accessor :fitness
end

# Step 4
population = Shirt.new_population(size: 10)
population.evolvables.each { |shirt| shirt.fitness = style_rating }

You are free to tailor the genes to your needs and find a style that suits you.

The ColorGene could be as simple as this:

class ColorGene
  include Evolvable::Gene

  def to_s
    @to_s ||= %w[red green blue].sample
  end
end

Shirts aren't your style?

Here's a Hello World command line demo.

Defined Under Namespace

Modules: ClassMethods, Community, Gene, GeneCluster Classes: CountGene, EqualizeGoal, Error, Evaluation, Evolution, GeneCombination, GeneSpace, Genome, Goal, MaximizeGoal, MinimizeGoal, Mutation, PointCrossover, Population, RigidCountGene, Selection, Serializer, UniformCrossover

Constant Summary collapse

VERSION =
'2.0.0'
DOC_URL =
"https://mattruzicka.github.io/evolvable"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#fitnessObject

Returns the value of attribute fitness.



302
303
304
# File 'lib/evolvable.rb', line 302

def fitness
  @fitness
end

#generation_indexObject

Returns the value of attribute generation_index.



312
313
314
# File 'lib/evolvable.rb', line 312

def generation_index
  @generation_index
end

#genomeObject (readonly)

Returns the value of attribute genome.



312
313
314
# File 'lib/evolvable.rb', line 312

def genome
  @genome
end

#populationObject

Returns the value of attribute population.



312
313
314
# File 'lib/evolvable.rb', line 312

def population
  @population
end

Class Method Details

.included(base) ⇒ void

This method returns an undefined value.

Called when the Evolvable module is included in a class. Sets up the necessary instance variables and extends the class with ClassMethods.

Parameters:

  • base (Class)

    The class that is including the Evolvable module



89
90
91
92
93
# File 'lib/evolvable.rb', line 89

def self.included(base)
  base.instance_variable_set(:@gene_config, {})
  base.instance_variable_set(:@cluster_config, {})
  base.extend(ClassMethods)
end

.new_object(old_val, new_val, default_class) ⇒ Object

Helper method for creating or updating objects with hash parameters. This is used internally for creating evaluation, selection, mutation, etc. objects from configuration hashes.

Parameters:

  • old_val (Object, nil)

    The existing object to update, if any

  • new_val (Object, Hash)

    The new object or configuration hash

  • default_class (Class)

    The default class to instantiate if new_val is a Hash

Returns:

  • (Object)

    The new or updated object



105
106
107
# File 'lib/evolvable.rb', line 105

def self.new_object(old_val, new_val, default_class)
  new_val.is_a?(Hash) ? (old_val&.class || default_class).new(**new_val) : new_val
end

Instance Method Details

#after_initialize_evolvableObject



300
# File 'lib/evolvable.rb', line 300

def after_initialize_evolvable; end

#dump_genome(serializer: Serializer) ⇒ String

Dumps the genome to a serialized format. Useful for saving the state of an evolvable.

Parameters:

Returns:

  • (String)

    The serialized genome



363
364
365
# File 'lib/evolvable.rb', line 363

def dump_genome(serializer: Serializer)
  @genome.dump(serializer: serializer)
end

#find_geneObject



304
305
306
# File 'lib/evolvable.rb', line 304

def find_gene(...)
  @genome&.find_gene(...)
end

#find_gene_cluster(cluster) ⇒ Array<Evolvable::Gene>

Finds an array of genes that belong to the specified cluster. This is used internally when accessing gene clusters.

Parameters:

  • cluster (Symbol)

    The cluster name

Returns:



352
353
354
# File 'lib/evolvable.rb', line 352

def find_gene_cluster(cluster)
  find_genes(*self.class.cluster_config[cluster])
end

#find_genesObject



308
309
310
# File 'lib/evolvable.rb', line 308

def find_genes(...)
  @genome&.find_genes(...) || []
end

#genesObject



316
317
318
# File 'lib/evolvable.rb', line 316

def genes
  @genome&.genes || []
end

#load_and_merge_genome!(data, serializer: Serializer) ⇒ Evolvable::Genome

Loads a genome from serialized data and merges it with the current genome. Useful for combining genomes from different sources.

Parameters:

  • data (String)

    The serialized genome data

  • serializer (Evolvable::Serializer) (defaults to: Serializer)

    The serializer to use

Returns:



387
388
389
390
# File 'lib/evolvable.rb', line 387

def load_and_merge_genome!(data, serializer: Serializer)
  genome = Genome.load(data, serializer: serializer)
  merge_genome!(genome)
end

#load_genome(data, serializer: Serializer) ⇒ Evolvable::Genome

Loads a genome from serialized data. Useful for restoring the state of an evolvable.

Parameters:

  • data (String)

    The serialized genome data

  • serializer (Evolvable::Serializer) (defaults to: Serializer)

    The serializer to use

Returns:



375
376
377
# File 'lib/evolvable.rb', line 375

def load_genome(data, serializer: Serializer)
  @genome = Genome.load(data, serializer: serializer)
end

#make_evolvable(population: nil, genome: nil, generation_index: nil) ⇒ self

Makes this object evolvable by setting up its population, genome, and generation index. This is called internally by the class method new_evolvable.

Parameters:

  • population (Evolvable::Population, nil) (defaults to: nil)

    The population this evolvable belongs to

  • genome (Evolvable::Genome, nil) (defaults to: nil)

    The genome to initialize with

  • generation_index (Integer, nil) (defaults to: nil)

    The generation index

Returns:

  • (self)

    This evolvable object



329
330
331
332
333
334
# File 'lib/evolvable.rb', line 329

def make_evolvable(population: nil, genome: nil, generation_index: nil)
  self.population = population
  @genome = genome
  self.generation_index = generation_index
  self
end

#merge_genome!(other_genome) ⇒ Evolvable::Genome

Merges another genome into this evolvable's genome. Useful for combining genetic traits from different evolvables.

Parameters:

Returns:



399
400
401
# File 'lib/evolvable.rb', line 399

def merge_genome!(other_genome)
  @genome.merge!(other_genome)
end