Menu

Tournament selection + elitarism

2016-01-26
2016-02-11
  • mfurlanetto

    mfurlanetto - 2016-01-26

    Hi, I do really like your work,
    but is there any way to apply two (parent) selectors?
    e.g., I would like to apply a truncation selector to keep the best phenotype, and then a Tournament to choose the others.
    Is this possible?

     
  • Franz Wilhelmstötter

    Hi, there is no Selector implementation in the library with this functionality. But it is not hard to implement a Selector which does what you want:

    public class CombinedSelector<
        G extends Gene<?, G>,
        C extends Comparable<? super C>
    >
        implements Selector<G, C>
    {
        private final TruncationSelector<G, C> _s1 = 
            new TruncationSelector<>();
        private final TournamentSelector<G, C> _s2 = 
            new TournamentSelector<>(3);
    
        @Override
        public Population<G, C> select(
            final Population<G, C> population,
            final int count,
            final Optimize opt
        ) {
            return population.isEmpty() || count <= 0
                ? new Population<>(0)
                : append(
                    _s1.select(population, 1, opt),
                    _s2.select(population, max(0, count - 1), opt));
        }
    
        private Population<G, C> append(
            final Population<G, C> p1,
            final Population<G, C> p2
        ) {
            p1.addAll(p2);
            return p2;
        }
    }
    
     
  • mfurlanetto

    mfurlanetto - 2016-01-27

    How lazy of me to not think that I could implement it myself.
    Thank you for your time.

     
  • mfurlanetto

    mfurlanetto - 2016-02-10

    Hi Franz,
    There is a thing that i cannot seem to understand:
    I've put a synchronized list in this selector to track down the fitness throught the generations, but at the end, the list has twice the elements than generations.
    e.g., if I build the engine with engine.stream().limit(200) I expect a list of 200 elements, but I get a 400 elements one instead.

    Is this a problem with my implementation or is a legit behaviour?

    Btw: I suppose that in the code you kindly provided me the append method should return p1, if it works like the Collection javadoc suggests.

     
    • Franz Wilhelmstötter

      Without the source code, it is hard to say what you want to achieve and whether its a bug in the library.

      I have a unit test (in EngineTest class), which checks the generation count:

      @Test(dataProvider = "generations")
      public void generationLimit(final Long generations) {
          final Engine<DoubleGene, Double> engine = Engine
              .builder(a -> a.getGene().getAllele(), DoubleChromosome.of(0, 1))
              .build();
      
          final EvolutionResult<DoubleGene, Double> result = engine.stream()
              .limit(limit.byFixedGeneration(generations))
              .collect(EvolutionResult.toBestEvolutionResult());
      
          Assert.assertEquals(
              generations.longValue(),
              result.getTotalGenerations());
      }
      

      And yes, the method sould return p1.

       

      Last edit: Franz Wilhelmstötter 2016-02-10
  • mfurlanetto

    mfurlanetto - 2016-02-10

    My bad, I'm not talking about bugs, but just to undarstand why the selector are called twice.
    But you are right, without source code it's pretty difficult.

    Here is my version of your code

    public class CombinedSelector<G extends Gene<?, G>, C extends Comparable<? super C>> implements Selector<G, C> {
        private final TruncationSelector<G, C> _s1;
        private final TournamentSelector<G, C> _s2;
        private ArrayList<C> fitnesses;
    
        public CombinedSelector(int tournamentSize) {
            _s1 = new TruncationSelector<>();
            _s2 = new TournamentSelector<>(tournamentSize);
            fitnesses = new ArrayList<>();
        }
    
        @Override
        public Population<G, C> select(final Population<G, C> population, final int count, final Optimize opt) {
            final Population<G, C> elite = _s1.select(population, 1, opt);
            Phenotype<G, C> best = elite.get(0);
            appendFitness(best.getFitness());
    
            return population.isEmpty() || count <= 0
                ? new Population<>(0)
                : append(
                    elite,
                    _s2.select(population, max(0, count - 1), opt));
        }
    
        private Population<G, C> append(
            final Population<G, C> p1,
            final Population<G, C> p2
        ) {
            p1.addAll(p2);
            return p1;
        }
    
        private synchronized void appendFitness(C fitness) {
            System.out.println(Thread.currentThread().getName()+"-"+fitnesses.size() + ") Best Fitness: " + fitness+" " + new Timestamp(System.currentTimeMillis()));
            fitnesses.add(fitness);
        }
    

    Notice the println in the apppendFitness method, that's what is called twice.

    And here is the code about the settings

    final Engine<IntegerGene, Float> engine = Engine
                    .builder(
                            StringsSimilarity::fitness,
                            IntegerChromosome.of(0, 255, 180))
                    .populationSize(50)
                    .executor(executor)
                    .optimize(Optimize.MINIMUM)
                    .selector(selector)
                    .alterers(
                            new Mutator<>(0.3),
                            new MultiPointCrossover<>(0.2, 2))
                    .build();
    
            final EvolutionStatistics<Float, ?> statistics = EvolutionStatistics.ofNumber();
            EvolutionResult<IntegerGene, Float> best = engine.stream()
                    .limit(200)
                    .peek(statistics)
                    .collect(EvolutionResult.toBestEvolutionResult());
    
     
  • Franz Wilhelmstötter

    The value of 400 makes totally sense. You are using the same selector for offspring and survivors. You have to choose a different selector for the offsprings.

    Engine.builder(...)
        .survivorsSelector(combinedSelector)
        .offspringSelector(otherSelector)
        ...
    
     
  • mfurlanetto

    mfurlanetto - 2016-02-11

    Thats the gear I was missing.
    Thank you again.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.