Individuals

This section covers the class Individual in more detail.

Class Summary

_images/individual-class-diagram.svg

Figure 1: The `Individual` class This class diagram shows the detail for Individual. In additional to the association with Decoder and ProbLem, each Individual has a genome and fitness. There are also several member functions for cloning, decoding, and evaluating individuals. Not shown are such member functions as __repr__() and __str__().

An Individual poses a unique instance of a solution to the associated Problem. Each Individual has a genome, which contains state representing that posed solution. The genome can be a sequence or a matrix or a tree or some other data structure, but in practice a genome is usually a binary or a real-value sequence. Every Individual is connected to an associated Problem and relies on the Problem to evaluate its fitness and to compare itself with another Individual to determine the better of the two.

The clone() method will create a duplicate of a given Individual; the new Individual gets a deep copy of the genome and refers to the same Problem and Decoder. evaluate() calls evaluate_imp()`that, in turn, calls `decode()`to translate the `genome into phenomes, or values meaningful to the Problem, and then passes those values to the Problem where it returns a fitness. This fitness is then assigned to the Individual.

The reason for the indirection using evaluate_imp() is that evaluate_imp() allows sub-classes to pass ancillary information to Problem during evaluation. For example, an Individual may have a UUID that the Problem needs in order to create a file or sub-directory using that UUID. evaluate_imp() can be over-ridden in a sub-class to pass along the UUID in addition to the decoded genome.

The @total_ordering class wrapper is used to expand the member functions __lt__() and __eq__() that are, in turn, heavily used in sorting, selection, and comparison operators.

RobustIndividual

RobustIndividual is a sub-class of Individual that over-rides evaluate() to handle exceptions thrown during evaluation. If no exceptions are thrown, then self.is_viable is set to True. If an exception happens, then the following occurs:

  • self.is_viable is set to False

  • self.fitness is set to math.nan

  • self.exception is assigned the Exception object

In turn, this class has another sub-class leap_ec.distributed.individual.DistributedIndividual.

Class API

Inheritance diagram of leap_ec.individual.RobustIndividual
class leap_ec.individual.Individual(genome, decoder=None, problem=None)

Represents a single solution to a Problem.

We represent an Individual by a genome and a fitness. Individual also maintains a reference to the Problem it will be evaluated on, and an decoder, which defines how genomes are converted into phenomes for fitness evaluation.

__init__(genome, decoder=None, problem=None)

Initialize an Individual with a given genome.

We also require Individual`s to maintain a reference to the `Problem:

>>> from leap_ec.binary_rep.problems import MaxOnes
>>> from leap_ec.decoder import IdentityDecoder
>>> ind = Individual([0, 0, 1, 0, 1], decoder=IdentityDecoder(), problem=MaxOnes())
>>> ind.genome
[0, 0, 1, 0, 1]

Fitness defaults to None:

>>> ind.fitness is None
True
Parameters
  • genome – is the genome representing the solution. This can be any arbitrary type that your mutation operators, probes, etc., know how to read and manipulate—a list, class, etc.

  • decoder – is a function or callable that converts a genome into a phenome.

  • problem – is the Problem associated with this individual.

clone()

Create a ‘clone’ of this Individual, copying the genome, but not fitness.

A deep copy of the genome will be created, so if your Individual has a custom genome type, it’s important that it implements the __deepcopy__() method.

>>> from leap_ec.binary_rep.problems import MaxOnes
>>> from leap_ec.decoder import IdentityDecoder
>>> ind = Individual([0, 1, 1, 0], IdentityDecoder(), MaxOnes())
>>> ind_copy = ind.clone()
>>> ind_copy.genome == ind.genome
True
>>> ind_copy.problem == ind.problem
True
>>> ind_copy.decoder == ind.decoder
True
classmethod create_population(n, initialize, decoder, problem)

A convenience method for initializing a population of the appropriate subtype.

Parameters
  • n – The size of the population to generate

  • initialize – A function f(m) that initializes a genome

  • decoder – The decoder to attach individuals to

  • problem – The problem to attach individuals to

Returns

A list of n individuals of this class’s (or subclass’s) type

decode(*args, **kwargs)
Returns

the decoded value for this individual

evaluate()

determine this individual’s fitness

This is done by outsourcing the fitness evaluation to the associated Problem object since it “knows” what is good or bad for a given phenome.

See also

ScalarProblem.worse_than

Returns

the calculated fitness

evaluate_imp()

This is the evaluate ‘implementation’ called by self.evaluate(). It’s intended to be optionally over-ridden by sub-classes to give an opportunity to pass in ancillary data to the evaluate process either by tailoring the problem interface or that of the given decoder.

classmethod evaluate_population(population)

Convenience function for bulk serial evaluation of a given population

Parameters

population – to be evaluated

Returns

evaluated population

class leap_ec.individual.RobustIndividual(genome, decoder=None, problem=None)

This adds exception handling for evaluations

After evaluation self.is_viable is set to True if all went well. However, if an exception is thrown during evaluation, the following happens:

  • self.is_viable is set to False

  • self.fitness is set to math.nan

  • self.exception is assigned the exception

evaluate()

determine this individual’s fitness

Note that if an exception is thrown during evaluation, the fitness is set to NaN and self.is_viable to False; also, the returned exception is assigned to self.exception for possible later inspection. If the individual was successfully evaluated, self.is_viable is set to true. NaN fitness values will figure into comparing individuals in that NaN will always be considered worse than non-NaN fitness values.

Returns

the calculated fitness