/**
   * Just reevaluate the {@link Entity entities} inside the topology. An entity's implementation
   * should handle updating anything else that is necessary, e.g. a {@link StandardParticle}'s
   * <code>personal best position</code> in the case of {@link PSO}.
   *
   * <p>{@inheritDoc}
   */
  @Override
  public void performReaction(E algorithm) {
    Topology<? extends Entity> entities = algorithm.getTopology();
    int reevaluateCount = (int) Math.floor(reevaluationRatio * entities.size());

    reevaluate(entities, reevaluateCount);
  }
  /**
   * Respond to environment change by re-evaluating each particle's position, personal best and
   * neighbourhood best, and reinitializing the positions of a specified percentage of particles.
   *
   * @param algorithm PSO algorithm that has to respond to environment change
   */
  @Override
  public void respond(E algorithm) {

    Topology<? extends Entity> topology = algorithm.getTopology();

    // Reevaluate current position. Update personal best (done by reevaluate()).
    Iterator<? extends Entity> iterator = topology.iterator();
    int reinitCounter = 0;
    int keepCounter = 0;
    int populationSize = algorithm.getTopology().size();
    while (iterator.hasNext()) {
      DynamicParticle current = (DynamicParticle) iterator.next();
      ZeroTransformation zt = new ZeroTransformation();

      // makes sure the charged particles are randomly positionned accross the topology
      if (reinitCounter < Math.floor(populationSize * reinitialisationRatio)
          && randomiser.nextDouble() < reinitialisationRatio
          && current != (algorithm).getTopology().getBestEntity()) {
        current.getPosition().randomize(this.randomiser);
        current
            .getProperties()
            .put(EntityType.Particle.VELOCITY, Vectors.transform(current.getVelocity(), zt));
        current
            .getProperties()
            .put(EntityType.Particle.BEST_POSITION, current.getPosition().getClone());
        ++reinitCounter;
      } // if
      else if (keepCounter > Math.floor(populationSize * (1.0 - reinitialisationRatio))
          && current != (algorithm).getTopology().getBestEntity()) {
        current.getPosition().randomize(this.randomiser);
        current
            .getProperties()
            .put(EntityType.Particle.VELOCITY, Vectors.transform(current.getVelocity(), zt));
        current
            .getProperties()
            .put(EntityType.Particle.BEST_POSITION, current.getPosition().getClone());
        ++reinitCounter;
      } // else if
      else {
        ++keepCounter;
      } // else
    }

    // Re-evaluate:
    reevaluateParticles(algorithm); // super class method
  }
  /**
   * Reinitialises all the output weights of a cascade network within a PSO.
   *
   * <p>{@inheritDoc}
   */
  @Override
  public void performReaction(E algorithm) {
    NNDataTrainingProblem problem = (NNDataTrainingProblem) algorithm.getOptimisationProblem();
    NeuralNetwork network = problem.getNeuralNetwork();

    int precedingLayersSize =
        network.getArchitecture().getArchitectureBuilder().getLayerConfigurations().get(0).getSize()
            + network
                .getArchitecture()
                .getArchitectureBuilder()
                .getLayerConfigurations()
                .get(1)
                .getSize();
    if (network.getArchitecture().getArchitectureBuilder().getLayerConfigurations().get(0).isBias())
      precedingLayersSize++;

    int outputLayerSize =
        network
            .getArchitecture()
            .getArchitectureBuilder()
            .getLayerConfigurations()
            .get(2)
            .getSize();
    int nrOfweightsToDo = precedingLayersSize * outputLayerSize;

    Topology<? extends Entity> entities = algorithm.getTopology();

    for (Entity entity : entities) {
      DynamicParticle particle = (DynamicParticle) entity;

      Vector position = (Vector) particle.getPosition();
      Vector velocity = (Vector) particle.getVelocity();
      for (int curElement = position.size() - nrOfweightsToDo;
          curElement < position.size();
          ++curElement) {
        ((Real) position.get(curElement)).randomize(randomGenerator);
        velocity.setReal(curElement, 0.0);
      }
    }
  }