1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
//! The `operator` module defines the types of genetic operators as traits. //! A genetic operator defines a function that performs a specific stage in //! the genetic algorithm. Each of these genetic operator can be implemented //! in variety of ways using different algorithms and methods. //! //! The genetic operators are the building blocks of the genetic algorithm. //! Their different implementations can be combined in a variety of ways to //! make up the actual simulation of a specific problem. pub mod prelude; use algorithm::EvaluatedPopulation; use genetic::{Children, Fitness, Genotype, Offspring, Parents}; use random::Rng; /// Marker trait for genetic operators and functions that are used for /// single-objective optimization. pub trait SingleObjective {} /// Marker trait for genetic operators and functions that are used for /// multi-objective optimization. pub trait MultiObjective {} /// A `GeneticOperator` defines a function used to guide the genetic algorithm /// towards a solution to a given problem. There are three main types of /// operators - Selection, Crossover and Mutation - which must work in /// conjunction with one another in order for the algorithm to be successful. /// /// There are unary operators that operate on one genotype at a time, e.g. /// mutation operators, and binary operators that work on two genotypes /// at a time, e.g. crossover operators. pub trait GeneticOperator: Clone { /// The name of the operator used for display purposes. The name should /// make clear to the user of the simulation which implementation of which /// kind of operator is being performed. /// /// It is recommended to combine some name of the method implemented by /// this operator (first part) with some name for the kind of operator /// (second part), e.g. "Flip-Bit-Mutation" or "Roulette-Wheel-Selection". fn name() -> String; } /// A `SelectionOp` defines the function of how to select solutions for being /// the parents of the next generation. pub trait SelectionOp<G, F>: GeneticOperator where G: Genotype, F: Fitness { /// Selects individuals from the given population according to the /// implemented selection strategy. fn select_from<R>(&self, population: &EvaluatedPopulation<G, F>, rng: &mut R) -> Vec<Parents<G>> where R: Rng + Sized; } /// A `CrossoverOp` defines a function of how to crossover two /// `genetic::Genotype`s, often called parent genotypes, to derive new /// `genetic::Genotype`s. It is analogous to reproduction and biological /// crossover. Cross over is a process of taking two parent solutions and /// producing an offspring solution from them. pub trait CrossoverOp<G>: GeneticOperator where G: Genotype { /// Performs the crossover of the `genetic::Parents` and returns the result /// as a new vector of `genetic::Genotype` - the `genetic::Children`. fn crossover<R>(&self, parents: Parents<G>, rng: &mut R) -> Children<G> where R: Rng + Sized; } /// A `MutationOp` defines a function of how a `genetic::Genotype` mutates. It /// is used to maintain genetic diversity from one generation of a population /// of genetic algorithm genotypes to the next. It is analogous to biological /// mutation. Mutation alters one or more gene values in a chromosome from its /// initial state. In mutation, the solution may change entirely from the /// previous solution. Hence GA can come to a better solution by using /// mutation. Mutation occurs during evolution according to a user-definable /// mutation probability. This probability should be set low. If it is set too /// high, the search will turn into a primitive random search. pub trait MutationOp<G>: GeneticOperator where G: Genotype { /// Mutates the given 'Genotype' and returns it as a new 'Genotype'. fn mutate<R>(&self, genome: G, rng: &mut R) -> G where R: Rng + Sized; } /// A `ReinsertionOp` defines a function that combines the offspring with the /// current population to create the population for the next generation. /// At the end the new population must be of the same size as the original /// population. /// /// The `ReinsertionOp` may decide which individuals in the offspring will /// make it into the new population. It is not required that all individuals /// of the offspring are reinserted into the new population. /// /// The only hard requirement is that the new population is of same size as /// the original population. If the offspring contains less individuals than /// the size of the original population or not all individuals are moved /// to the new population then some individuals from the original population /// are taken over into the new population. If the size of the offspring is /// bigger than the size of the original population, then not all individuals /// from the offspring are inserted into the new population. pub trait ReinsertionOp<G, F>: GeneticOperator where G: Genotype, F: Fitness { /// Combines the given offspring with the current population to create /// the population of the next generation. /// /// The offspring parameter is passed as mutable borrow. It can be /// mutated to avoid cloning. The `genetic::Genotype`s that make it up into /// the new population should be moved instead of cloned. After this /// function finishes the offspring vector should hold only those /// `genetic::Genotype`s that have not been included in the resulting /// population. If by the end of this function all `genetic::Genotype`s in /// offspring have been moved to the resulting population the offspring /// vector should be left empty. fn combine<R>(&self, offspring: &mut Offspring<G>, population: &EvaluatedPopulation<G, F>, rng: &mut R) -> Vec<G> where R: Rng + Sized; }