/**           __  __
 *    _____ _/ /_/ /_    Computational Intelligence Library (CIlib)
 *   / ___/ / / / __ \   (c) CIRG @ UP
 *  / /__/ / / / /_/ /   http://cilib.net
 *  \___/_/_/_/_.___/
 */
package net.sourceforge.cilib.pso.iterationstrategies;

import com.google.common.collect.Lists;
import java.util.Collections;
import java.util.List;
import net.sourceforge.cilib.algorithm.population.AbstractIterationStrategy;
import net.sourceforge.cilib.algorithm.population.IterationStrategy;
import net.sourceforge.cilib.controlparameter.ConstantControlParameter;
import net.sourceforge.cilib.controlparameter.ControlParameter;
import net.sourceforge.cilib.entity.Topologies;
import net.sourceforge.cilib.entity.Topology;
import net.sourceforge.cilib.entity.comparator.DescendingFitnessComparator;
import net.sourceforge.cilib.entity.comparator.SocialBestFitnessComparator;
import net.sourceforge.cilib.entity.operators.crossover.parentprovider.BestParentProvider;
import net.sourceforge.cilib.entity.operators.crossover.real.ParentCentricCrossoverStrategy;
import net.sourceforge.cilib.math.random.generator.Rand;
import net.sourceforge.cilib.pso.PSO;
import net.sourceforge.cilib.pso.crossover.ParticleCrossoverStrategy;
import net.sourceforge.cilib.pso.particle.Particle;
import net.sourceforge.cilib.util.selection.Samples;
import net.sourceforge.cilib.util.selection.recipes.RandomSelector;

/**
 * Reference:
 * <p>
 * "Enhanced Performance of Particle Swarm Optimization with Generalized Generation 
 * Gap Model with Parent-Centric Recombination Operator", by C. Worasucheep, 
 * C Pipopwatthana, S Srimontha, W. Phanmak, in ECTI Transactions on Computer 
 * and Information Technology, vol 6, Non 2, 2012
 * </p>
 */
public class PSPGIterationStrategy extends AbstractIterationStrategy<PSO> {
    
    private ControlParameter iterationProbability;
    private ParticleCrossoverStrategy crossoverStrategy;
    private IterationStrategy iterationStrategy;
    
    public PSPGIterationStrategy() {
        ParentCentricCrossoverStrategy pcx = new ParentCentricCrossoverStrategy();
        pcx.setNumberOfParents(ConstantControlParameter.of(3));
        pcx.setNumberOfOffspring(ConstantControlParameter.of(2));
        pcx.setParentProvider(new BestParentProvider());
        
        ParticleCrossoverStrategy xover = new ParticleCrossoverStrategy();
        xover.setCrossoverStrategy(pcx);
        
        this.crossoverStrategy = xover;
        this.iterationProbability = ConstantControlParameter.of(0.05);
        this.iterationStrategy = new SynchronousIterationStrategy();
    }

    public PSPGIterationStrategy(PSPGIterationStrategy copy) {
        this.iterationProbability = copy.iterationProbability.getClone();
        this.crossoverStrategy = copy.crossoverStrategy.getClone();
    }

    @Override
    public PSPGIterationStrategy getClone() {
        return new PSPGIterationStrategy(this);
    }

    @Override
    public void performIteration(PSO algorithm) {
        if (Rand.nextDouble() < iterationProbability.getParameter()) {
            crossoverStep(algorithm);
        } else {
            iterationStrategy.performIteration(algorithm);
        }
    }

    private void crossoverStep(PSO algorithm) {
        Topology<Particle> topology = algorithm.getTopology();
        Particle gbest = Topologies.getBestEntity(topology, new SocialBestFitnessComparator<>());
        
        // Get parents
        List<Particle> parents = Lists.newArrayList(new RandomSelector<Particle>()
                .on(topology)
                .exclude(gbest)
                .select(Samples.first(crossoverStrategy.getNumberOfParents() - 1)));
        parents.add(gbest);
        // Add offspring
        parents.addAll(crossoverStrategy.crossover(parents));
        Collections.sort(parents, new DescendingFitnessComparator<>());
        
        // Get particles to replace
        List<Particle> rp = Lists.newArrayList(new RandomSelector<Particle>()
                .on(topology)
                .exclude(gbest)
                .select(Samples.first(crossoverStrategy.getNumberOfParents() - 1)));
        rp.add(gbest);
        
        // Replace particles
        int counter = 0;
        for (Particle p : rp) {
            topology.set(topology.indexOf(p), parents.get(counter++));
        }
        
        // Update nhood
        for (Particle current : topology) {
            for (Particle other : topology.neighbourhood(current)) {
                if (current.getSocialFitness().compareTo(other.getNeighbourhoodBest().getSocialFitness()) > 0) {
                    other.setNeighbourhoodBest(current);
                }
            }
        }
    }

    public void setIterationStrategy(IterationStrategy iterationStrategy) {
        this.iterationStrategy = iterationStrategy;
    }

    public void setIterationProbability(ControlParameter iterationProbability) {
        this.iterationProbability = iterationProbability;
    }

    public void setCrossoverStrategy(ParticleCrossoverStrategy crossoverStrategy) {
        this.crossoverStrategy = crossoverStrategy;
    }

}

@@ -285,16 +285,29 @@
 .Lists;%0A
+import fj.F;%0A
 import j
@@ -328,16 +328,43 @@
 ctions;%0A
+import java.util.Iterator;%0A
 import j
@@ -712,54 +712,8 @@
 es;%0A
-import net.sourceforge.cilib.entity.Topology;%0A
 impo
@@ -3232,24 +3232,28 @@
         
-Topology
+fj.data.List
 %3CParticl
@@ -3421,32 +3421,38 @@
 parents%0A        
+final 
 List%3CParticle%3E p
@@ -3897,16 +3897,22 @@
         
+final 
 List%3CPar
@@ -4193,137 +4193,364 @@
     
+f
 in
-t counter = 0;%0A        for (Particle p : rp) %7B%0A            topology.set(topology.indexOf(p), parents.get(counter++));%0A        %7D
+al Iterator%3CParticle%3E iter = parents.iterator();%0A        algorithm.setTopology(topology.map(new F%3CParticle, Particle%3E() %7B%0A            @Override%0A            public Particle f(Particle a) %7B%0A                if (rp.contains(a)) %7B%0A                    return iter.next();%0A                %7D%0A                %0A                return a;%0A            %7D%0A        %7D));
 %0A   
@@ -4611,24 +4611,39 @@
 rrent : 
-t
+algorithm.getT
 opology
+()
 ) %7B%0A    
@@ -4676,31 +4676,49 @@
 r : 
-topology.neighbourhood(
+algorithm.getNeighbourhood().f(topology, 
 curr

Rebase fixes.