public void rankSelection()
	{
		// calculate fitness, filter invalid elements
		List<Individual> okList = new ArrayList<Individual>();
		for (Individual ind : individuals) {
			if (ind.fitness(MIN_G))
				okList.add(ind);
		}

		// sort in preparation to calculate rank
		Collections.sort(okList, new Comparator<Individual>() {
			@Override
			public int compare(Individual o1, Individual o2)
			{
				/*
				 * We want to assign the highest rank the lowest fitness value
				 * because we want to minimize f().
				 * This sorts the biggest element first.
				 */
				return (int) Double.compare(o2.fitness, o1.fitness);
			}
		});

		// set rank based on position in sorted list
		int ranks = 0;
		for (int i = 0; i < okList.size(); i++) {
			okList.get(i).rank = i + 1;
			ranks += i + 1;
		}

		// calculate a start value between 0.0 and 1.0 based on rank
		double start = 0;
		for (Individual ind : okList) {
			ind.start = start;
			start += 1D / (double) ranks * (double) ind.rank;
		}

		// randomly select individuals
		List<Individual> selectedInd = new ArrayList<Individual>();
		for (int i = 0; i < individuals.size(); i++) {
			double r = rand.nextDouble();
			for (int j = okList.size() - 1; j >= 0; j--) {
				Individual ind = okList.get(j);
				if (ind.start <= r) {
					Individual tmp = ind.duplicate();
					tmp.index = i;
					selectedInd.add(tmp);
					break;
				}
			}
		}

		individuals = selectedInd;
	}