class EpsilonNeighborhoodCoupler implements Coupler {

	protected List<Set<Individual>> createNeighborhoods(List<Individual> survivorPool) {
		List<Set<Individual>> neighborhoods = new ArrayList<>();
		Map<Objective, Double> objectiveAmplitudes = epsilonMapping
				.findObjectiveAmplitudes(new HashSet<>(survivorPool));
		List<Individual> survivors = new ArrayList<>(survivorPool);
		while (!survivors.isEmpty()) {
			// pick a random individual
			int idx = random.nextInt(survivors.size());
			Individual reference = survivors.remove(idx);
			Set<Individual> neighborhood = new HashSet<>();
			Objectives epsilonEnhancedObjectives = epsilonMapping.mapObjectives(reference.getObjectives(),
					adaptiveEpsilonNeighborhood.getEpsilon(), objectiveAmplitudes);
			// put the individuals epsilon-dominated by the reference into its
			// neighborhood
			for (Individual candidate : survivors) {
				if (epsilonEnhancedObjectives.dominates(candidate.getObjectives())) {
					neighborhood.add(candidate);
				}
			}
			survivors.removeAll(neighborhood);
			neighborhood.add(reference);
			neighborhoods.add(neighborhood);
		}
		// adapt the epsilon
		boolean epsilonTooBig = neighborhoods.size() < plannedNeighborhoodNumber;
		epsilonAdaption.adaptEpsilon(adaptiveEpsilonNeighborhood, epsilonTooBig);
		return neighborhoods;
	}

	@Inject public  EpsilonNeighborhoodCoupler(EpsilonMapping epsilonMapping, EpsilonAdaptation epsilonAdaption, Random random,
			@Constant(value = "neighborhoodNumber", namespace = EpsilonNeighborhoodCoupler.class) int plannedNeighborhoodNumber,
			@Constant(value = "epsilonNeighborhood", namespace = EpsilonNeighborhoodCoupler.class) double epsilonNeighborhood,
			@Constant(value = "epsilonNeighborhoodDelta", namespace = EpsilonNeighborhoodCoupler.class) double epsilonNeighborhoodDelta,
			@Constant(value = "epsilonNeighborhoodDeltaMax", namespace = EpsilonNeighborhoodCoupler.class) double epsilonNeighborhoodDeltaMax,
			@Constant(value = "epsilonNeighborhoodDeltaMin", namespace = EpsilonNeighborhoodCoupler.class) double epsilonNeighborhoodDeltaMin);

}