/** {@inheritDoc} */
  @Override
  public <T extends Entity> T create(T targetEntity, T current, Topology<T> topology) {
    T bestEntity = Topologies.getBestEntity(topology);
    List<T> participants =
        Selection.copyOf(topology)
            .exclude(targetEntity, bestEntity, current)
            .orderBy(new RandomArrangement())
            .select(Samples.first((int) numberOfDifferenceVectors.getParameter()).unique());
    Vector differenceVector = determineDistanceVector(participants);

    Vector targetVector =
        ((Vector) targetEntity.getCandidateSolution())
            .multiply(1 - greedynessParameter.getParameter());
    Vector bestVector =
        ((Vector) bestEntity.getCandidateSolution()).multiply(greedynessParameter.getParameter());

    Vector trialVector =
        bestVector.plus(
            targetVector.plus(differenceVector.multiply(scaleParameter.getParameter())));

    T trialEntity = (T) current.getClone();
    trialEntity.setCandidateSolution(trialVector);

    return trialEntity;
  }
  /** {@inheritDoc} */
  @Override
  public <T extends Entity> T create(T targetEntity, T current, fj.data.List<T> topology) {
    int number = Double.valueOf(this.numberOfDifferenceVectors.getParameter()).intValue();
    List<T> participants =
        Selection.copyOf(topology)
            .exclude(targetEntity, current)
            .orderBy(new RandomArrangement())
            .select(Samples.first(number).unique());
    Vector differenceVector = determineDistanceVector(participants);

    Vector targetVector = (Vector) targetEntity.getCandidateSolution();
    Vector trialVector =
        targetVector.plus(
            differenceVector.multiply(
                new P1<Number>() {
                  @Override
                  public Number _1() {
                    return scaleParameter.getParameter();
                  }
                }));

    T trialEntity = (T) current.getClone();
    trialEntity.setCandidateSolution(trialVector);

    return trialEntity;
  }
  @Override
  public void performIteration(PSO algorithm) {
    delegate.performIteration(algorithm);
    Topology<Particle> topology = algorithm.getTopology();

    // calculate vAvg
    Vector avgV =
        Vectors.mean(
            Lists.transform(
                topology,
                new Function<Particle, Vector>() {
                  @Override
                  public Vector apply(Particle f) {
                    return (Vector) f.getVelocity();
                  }
                }));

    Vector.Builder builder = Vector.newBuilder();
    for (Numeric n : avgV) {
      if (Math.abs(n.doubleValue()) > vMax.getParameter()) {
        builder.add(vMax.getParameter());
      } else {
        builder.add(n);
      }
    }

    avgV = builder.build();

    // mutation
    Particle gBest = Topologies.getBestEntity(topology, new SocialBestFitnessComparator());
    Particle mutated = gBest.getClone();
    Vector pos = (Vector) gBest.getBestPosition();
    final Bounds bounds = pos.boundsOf(0);

    pos =
        pos.plus(
            avgV.multiply(
                new Supplier<Number>() {
                  @Override
                  public Number get() {
                    return distribution.getRandomNumber() * bounds.getRange()
                        + bounds.getLowerBound();
                  }
                }));

    mutated.setCandidateSolution(pos);
    mutated.calculateFitness();

    if (gBest.getBestFitness().compareTo(mutated.getFitness()) < 0) {
      gBest.getProperties().put(EntityType.Particle.BEST_FITNESS, mutated.getBestFitness());
      gBest.getProperties().put(EntityType.Particle.BEST_POSITION, mutated.getBestPosition());
    }
  }
  /**
   * Calculate the {@linkplain Vector} that is the resultant of several difference vectors.
   *
   * @param participants The {@linkplain Entity} list to create the difference vectors from. It is
   *     very important to note that the {@linkplain Entity} objects within this list should not
   *     contain duplicates. If duplicates are contained, this will severely reduce the diversity of
   *     the population as not all entities will be considered.
   * @return A {@linkplain Vector} representing the resultant of all calculated difference vectors.
   */
  protected <T extends Entity> Vector determineDistanceVector(List<T> participants) {
    Vector distanceVector = Vector.fill(0.0, participants.get(0).getCandidateSolution().size());
    Iterator<T> iterator = participants.iterator();

    while (iterator.hasNext()) {
      Vector first = (Vector) iterator.next().getCandidateSolution();
      Vector second = (Vector) iterator.next().getCandidateSolution();

      Vector difference = first.subtract(second);
      distanceVector = distanceVector.plus(difference);
    }

    return distanceVector;
  }
  @Override
  public Vector get(Particle particle) {
    Vector newPos = (Vector) delegate.get(particle);

    Particle tmp = particle.getClone();
    tmp.setPosition(newPos);
    Fitness newFitness = particle.getBehaviour().getFitnessCalculator().getFitness(tmp);

    final UniformDistribution uniform = new UniformDistribution();
    Vector newPBest =
        newPos.plus(
            Vector.newBuilder()
                .repeat(newPos.size(), Real.valueOf(1.0))
                .build()
                .multiply(
                    new P1<Number>() {
                      @Override
                      public Number _1() {
                        return uniform.getRandomNumber(
                            -granularity.getParameter(), granularity.getParameter());
                      }
                    }));
    tmp.setPosition(newPos);
    Fitness newPBestFitness = particle.getBehaviour().getFitnessCalculator().getFitness(tmp);

    if (newPBestFitness.compareTo(newFitness) < 0) {
      Vector tmpVector = Vector.copyOf(newPos);
      newPos = newPBest;
      newPBest = tmpVector;

      newPBestFitness = newFitness;
    }

    double dot =
        ((Vector) particle.getNeighbourhoodBest().getBestPosition())
            .subtract(newPos)
            .dot(newPBest.subtract(newPos));

    if (dot < 0) {
      return (Vector) particle.getPosition();
    }

    particle.put(Property.BEST_POSITION, newPBest);
    particle.put(Property.BEST_FITNESS, newPBestFitness);

    return newPos;
  }
  /** {@inheritDoc} */
  @Override
  public Entity create(Entity targetEntity, Entity current, Topology<? extends Entity> topology) {
    List<Entity> participants =
        (List<Entity>)
            Selection.copyOf(topology).exclude(targetEntity, current).select(Samples.all());
    Vector differenceVector = determineDistanceVector(participants);

    Vector targetVector = (Vector) targetEntity.getCandidateSolution();
    Vector trialVector =
        targetVector.plus(
            differenceVector.multiply(
                new P1<Number>() {
                  @Override
                  public Number _1() {
                    return scaleParameter.getParameter();
                  }
                }));

    Entity trialEntity = current.getClone();
    trialEntity.setCandidateSolution(trialVector);

    return trialEntity;
  }
  /** {@inheritDoc} */
  @Override
  public Vector get(Particle particle) {
    double averageParticleVelocity = 0.0;

    Vector averageVelocity = null; // velocity.getClone();
    //        averageVelocity.reset();
    PSO pso = (PSO) AbstractAlgorithm.get();
    for (Particle p : pso.getTopology()) {
      if (averageVelocity == null) {
        averageVelocity = (Vector) p.getVelocity();
        continue;
      }
      Vector particleVelocity = (Vector) p.getVelocity();
      averageVelocity = averageVelocity.plus(particleVelocity);
      averageParticleVelocity += particleVelocity.norm();
    }
    averageVelocity = averageVelocity.divide(particle.getDimension());
    averageParticleVelocity /= particle.getDimension();

    double swarmCenterVelocity = averageVelocity.norm();
    double swarmCoherence = calculateSwarmCoherence(swarmCenterVelocity, averageParticleVelocity);

    double sigmoidValue = this.sigmoid.apply(swarmCoherence);

    Vector standardVelocity = this.delegate.get(particle);

    Vector.Builder builder = Vector.newBuilder();
    for (int i = 0; i < particle.getDimension(); ++i) {
      double coherenceVelocity =
          this.scalingFactor.getParameter()
              * sigmoidValue
              * averageVelocity.doubleValueOf(i)
              * this.randomNumber.getRandomNumber();
      builder.add(coherenceVelocity);
    }
    Vector coherence = builder.build();

    return Vectors.sumOf(standardVelocity, coherence);

    //        float social = socialRandomGenerator.nextFloat();
    //        float cognitive = cognitiveRandomGenerator.nextFloat();
    //
    //        //DistanceMeasure adm = new AbsoluteDistanceMeasure();
    //        //DistanceMeasure dm = new MetricDistanceMeasure();
    //
    //        double avgv = 0.0;
    //        double swv = 0.0;
    //        Topology<Particle> topology = ((PSO)Algorithm.get()).getTopology();
    //          Iterator<? extends Particle> it = topology.neighbourhood(null);
    //          double[] al = new double[particle.getDimension()];
    //           while (it.hasNext()) {
    //               Particle pl = it.next();
    //               double tmpv = 0.0;
    //               //double tmpsv = 0.0;
    //               for(int dim = 0; dim < particle.getDimension(); dim++) {
    //                al[dim] = al[dim]+((Vector)pl.getVelocity()).getReal(dim);
    //                   tmpv += Math.pow(((Vector)pl.getVelocity()).getReal(dim), 2);
    //               }
    //               tmpv = Math.sqrt(tmpv);
    //               avgv += tmpv;
    //           }
    //           for(int i = 0; i < particle.getDimension(); i++) {
    //            //al.set(i, ;
    //            swv += (al[i]/topology.size()) * (al[i]/topology.size());
    //        }
    //        swv = Math.sqrt(swv);
    //
    //        for (int i = 0; i < particle.getDimension(); ++i) {
    //            double tmp = 0.0;
    //            tmp = inertiaWeight.getParameter()*velocity.getReal(i)
    //                + cognitive * (bestPosition.getReal(i) - position.getReal(i)) *
    // cognitiveAcceleration.getParameter()
    //                + social * (nBestPosition.getReal(i) - position.getReal(i)) *
    // socialAcceleration.getParameter();
    //
    //            double avgdim = 0.0;
    //              it = topology.neighbourhood(null);
    //               while (it.hasNext()) {
    //                   avgdim += ((Vector)(it.next().getVelocity())).getReal(i);
    //               }
    //            avgdim /= particle.getDimension();
    //
    //            double cvelocity = MathUtil.sigmoid(swv/avgv)*avgdim*randomNumber.getCauchy();
    //
    //            System.out.println(cvelocity);
    //            tmp += cvelocity;
    //
    //            velocity.setReal(i, tmp);
    //
    //            clamp(velocity, i);
    //        }
  }
  /** {@inheritDoc} */
  @Override
  public <E extends Entity> List<E> crossover(List<E> parentCollection) {
    checkState(
        parentCollection.size() >= 3,
        "There must be a minimum of three parents to perform UNDX crossover.");
    checkState(
        numberOfOffspring > 0,
        "At least one offspring must be generated. Check 'numberOfOffspring'.");

    List<Vector> solutions = Entities.<Vector>getCandidateSolutions(parentCollection);
    List<E> offspring = Lists.newArrayListWithCapacity(numberOfOffspring);
    UniformDistribution randomParent = new UniformDistribution();
    final int k = solutions.size();
    final int n = solutions.get(0).size();

    for (int os = 0; os < numberOfOffspring; os++) {
      // get index of main parent and put its solution at the end of the list
      int parent = (int) randomParent.getRandomNumber(0.0, k);
      Collections.swap(solutions, parent, k - 1);

      List<Vector> e_zeta = new ArrayList<Vector>();

      // calculate mean of parents except main parent
      Vector g = Vectors.mean(solutions.subList(0, k - 1));

      // basis vectors defined by parents
      for (int i = 0; i < k - 1; i++) {
        Vector d = solutions.get(i).subtract(g);

        if (!d.isZero()) {
          double dbar = d.length();
          Vector e = d.orthogonalize(e_zeta);

          if (!e.isZero()) {
            e_zeta.add(e.normalize().multiply(dbar));
          }
        }
      }

      final double D = solutions.get(k - 1).subtract(g).length();

      // create the remaining basis vectors
      List<Vector> e_eta = Lists.newArrayList();
      e_eta.add(solutions.get(k - 1).subtract(g));

      for (int i = 0; i < n - e_zeta.size() - 1; i++) {
        Vector d = Vector.newBuilder().copyOf(g).buildRandom();
        e_eta.add(d);
      }

      e_eta = Vectors.orthonormalize(e_eta);

      // construct the offspring
      Vector variables = Vector.copyOf(g);

      if (!useIndividualProviders) {
        for (int i = 0; i < e_zeta.size(); i++) {
          variables =
              variables.plus(
                  e_zeta.get(i).multiply(random.getRandomNumber(0.0, sigma1.getParameter())));
        }

        for (int i = 0; i < e_eta.size(); i++) {
          variables =
              variables.plus(
                  e_eta
                      .get(i)
                      .multiply(
                          D * random.getRandomNumber(0.0, sigma2.getParameter() / Math.sqrt(n))));
        }
      } else {
        for (int i = 0; i < e_zeta.size(); i++) {
          variables =
              variables.plus(
                  e_zeta
                      .get(i)
                      .multiply(
                          new Supplier<Number>() {

                            @Override
                            public Number get() {
                              return random.getRandomNumber(0.0, sigma1.getParameter());
                            }
                          }));
        }

        for (int i = 0; i < e_eta.size(); i++) {
          variables =
              variables.plus(
                  e_eta
                      .get(i)
                      .multiply(
                          new Supplier<Number>() {

                            @Override
                            public Number get() {
                              return D
                                  * random.getRandomNumber(
                                      0.0, sigma2.getParameter() / Math.sqrt(n));
                            }
                          }));
        }
      }

      E child = (E) parentCollection.get(parent).getClone();
      child.setCandidateSolution(variables);

      offspring.add(child);
    }

    return offspring;
  }