Interface Constraint<G extends Gene<?,G>,C extends Comparable<? super C>>

All Known Implementing Classes:
RetryConstraint

public interface Constraint<G extends Gene<?,G>,C extends Comparable<? super C>>
This interface allows you to define constraints on single phenotypes. It is a more advanced version of the Phenotype.isValid() method, which checks the validity of the underlying genotypes and/or chromosomes. Additionally, it is possible to repair invalid individuals. The evolution Engine is using the constraint in the following way: check the validity and repair invalid individuals.
for (int i = 0; i < population.size(); ++i) {
    final Phenotype<G, C> individual = population.get(i);
    if (!constraint.test(individual)) {
        population.set(i, constraint.repair(individual, generation));
    }
}
Note
Keep in mind, that this interface only repairs invalid individuals, which has been destroyed by the evolution process. Individuals, created by the given Factory<Genotype<G>>, are not validated and repaired. This means that it is still possible to have invalid individuals, created by the genotype factory. The constrain(Factory) will wrap the given factory which obeys this constraint. The following code will show how to create such a constrained genotype factory and use it for creating an evolution engine.
final Constraint<DoubleGene, Double> constraint = ...;
final Factory<Genotype<DoubleGene>> gtf = ...;
final Engine<DoubleGene, Double> engine = Engine
    .builder(fitness, constraint.constrain(gtf))
    .constraint(constraint)
    .build();
The following example illustrates how a constraint which its repair function can look like. Imagine that your problem domain consists of double values between [0, 2) and [8, 10). Since it is not possible

   +--+--+--+--+--+--+--+--+--+--+
   |  |  |  |  |  |  |  |  |  |  |
   0  1  2  3  4  5  6  7  8  9  10
   |-----|xxxxxxxxxxxxxxxxx|-----|
      ^  |llllllll|rrrrrrrr|  ^
      |       |        |      |
      +-------+        +------+
 
The invalid range is marked with x. Repairing an invalid value will map values in the l range on the valid range [0, 2), and value in the r range on the valid range [8, 10). This mapping guarantees an even distribution of the values in the valid ranges, which is an important characteristic of the repair function.
final InvertibleCodec<Double, DoubleGene> codec = Codecs.ofScalar(DoubleRange.of(0, 10));
final Constraint<DoubleGene, Double> constraint = Constraint.of(
    codec,
    v -> v < 2 || v >= 8,
    v -> {
        if (v >= 2 && v < 8) {
            return v < 5 ? ((v - 2)/3)*2 : ((8 - v)/3)*2 + 8;
        }
        return v;
    }
);
Alternative solution
Instead of repairing individuals, it is better to not create invalid one in the first place. Once you have a proper repair strategy, you can use it to create a Codec which only creates valid individuals, using your repair method.
final Codec<Double, DoubleGene> codec = Codecs
    .ofScalar(DoubleRange.of(0, 10))
    .map(v -> {
            if (v >= 2 && v < 8) {
                return v < 5 ? ((v - 2)/3)*2 : ((8 - v)/3)*2 + 8;
            }
            return v;
        });
The same example with an InvertibleCodec will look like this:
final InvertibleCodec<Double, DoubleGene> codec = Codecs
    .ofScalar(DoubleRange.of(0, 10))
    .map(v -> {
            if (v >= 2 && v < 8) {
                return v < 5 ? ((v - 2)/3)*2 : ((8 - v)/3)*2 + 8;
            }
            return v;
        },
        Function.identity());
Since:
5.0
Version:
6.1
See Also:
API Note:
This class is part of the more advanced API and is unnecessary for default use cases. If the Engine is created with an explicit constraint (Engine.Builder.constraint(Constraint)), the default validation mechanism via Phenotype.isValid() is overridden. Also keep in mind that a defined constraint doesn't protect the fitness function from invalid values. It is still necessary that the fitness function must handle invalid values accordingly. The constraint only filters invalid individuals after the selection and altering step.
  • Method Details

    • test

      boolean test(Phenotype<G,C> individual)
      Checks the validity of the given individual.
      Parameters:
      individual - the phenotype to check
      Returns:
      true if the given individual is valid, false otherwise
      Throws:
      NullPointerException - if the given individual is null
    • repair

      Phenotype<G,C> repair(Phenotype<G,C> individual, long generation)
      Tries to repair the given phenotype. This method is called by the evolution Engine if the test(Phenotype) method returned false.
      Parameters:
      individual - the phenotype to repair
      generation - the actual generation, where this method is called by the evolution engine
      Returns:
      a newly created, valid phenotype. The implementation is free to use the given invalid individual as a starting point for the created phenotype.
      Throws:
      NullPointerException - if the given individual is null
    • constrain

      Wraps the given genotype factory into a factory, which only creates individuals obeying this constraint. The following code will create an evolution engine, where also the genotype factory will only create valid individuals.
      final Constraint<DoubleGene, Double> constraint = ...;
      final Factory<Genotype<DoubleGene>> gtf = ...;
      final Engine<DoubleGene, Double> engine = Engine
          .builder(fitness, constraint.constrain(gtf))
          .constraint(constraint)
          .build();
      
      Parameters:
      gtf - the genotype factory to wrap
      Returns:
      a new constrained genotype factory.
      Throws:
      NullPointerException - if the given genotype factory is null
      Since:
      6.1
      See Also:
    • constrain

      default <T> Codec<T,G> constrain(Codec<T,G> codec)
      Wraps the given codec into a codec, which obeys this constraint.
      Type Parameters:
      T - the argument type of given problem
      Parameters:
      codec - the codec to wrap
      Returns:
      the wrapped codec, which obeys this constraint
      Throws:
      NullPointerException - if the given codec is null
      Since:
      6.1
      See Also:
    • constrain

      default <T> InvertibleCodec<T,G> constrain(InvertibleCodec<T,G> codec)
      Wraps the given codec into a codec, which obeys this constraint.
      Type Parameters:
      T - the argument type of given problem
      Parameters:
      codec - the codec to wrap
      Returns:
      the wrapped codec, which obeys this constraint
      Throws:
      NullPointerException - if the given codec is null
      Since:
      6.1
      See Also:
    • of

      static <G extends Gene<?, G>, C extends Comparable<? super C>> Constraint<G,C> of(Predicate<? super Phenotype<G,C>> validator, BiFunction<? super Phenotype<G,C>,Long,Phenotype<G,C>> repairer)
      Return a new constraint object with the given validator and repairer.
      Type Parameters:
      G - the gene type
      C - the fitness value type
      Parameters:
      validator - the phenotype validator used by the constraint
      repairer - the phenotype repairer used by the constraint
      Returns:
      a new constraint strategy
      Throws:
      NullPointerException - if one of the arguments is null
    • of

      static <G extends Gene<?, G>, C extends Comparable<? super C>> Constraint<G,C> of(Predicate<? super Phenotype<G,C>> validator)
      Return a new constraint object with the given validator. The used repairer just creates a new phenotype by using the phenotype to be repaired as a template. The repaired phenotype might still be invalid.
      Type Parameters:
      G - the gene type
      C - the fitness value type
      Parameters:
      validator - the phenotype validator used by the constraint
      Returns:
      a new constraint strategy
      Throws:
      NullPointerException - if one of the arguments is null
      See Also:
    • of

      static <T, G extends Gene<?, G>, C extends Comparable<? super C>> Constraint<G,C> of(InvertibleCodec<T,G> codec, Predicate<? super T> validator, Function<? super T,? extends T> repairer)
      Return a new constraint object with the given validator and repairer. The given invertible codec allows simplifying the necessary validator and repairer.
      Type Parameters:
      T - the type of the native problem domain
      G - the gene type
      C - the fitness value type
      Parameters:
      codec - the invertible codec used for simplify the necessary validator and repairer
      validator - the phenotype validator used by the constraint
      repairer - the phenotype repairer used by the constraint
      Returns:
      a new constraint strategy
      Throws:
      NullPointerException - if one of the arguments is null
      Since:
      5.2