public static <T> double[] crowdingDistance(
		final Seq<? extends T> set,
		final ElementComparator<? super T> comparator,
		final ElementDistance<? super T> distance,
		final ToIntFunction<? super T> dimension
	) {
		requireNonNull(set);
		requireNonNull(comparator);
		requireNonNull(distance);

		final double[] result = new double[set.size()];
		if (set.size() < 3) {
			Arrays.fill(result, POSITIVE_INFINITY);
		} else {
			final int[] idx = new int[set.size()];
			final IndexSorter sorter = IndexSorter.sorter(set.size());

			for (int m = 0, d = dimension.applyAsInt(set.get(0)); m < d; ++m) {
				sorter.sort(set, init(idx), comparator.ofIndex(m));

				result[idx[0]] = POSITIVE_INFINITY;
				result[idx[set.size() - 1]] = POSITIVE_INFINITY;

				final T max = set.get(idx[0]);
				final T min = set.get(idx[set.size() - 1]);
				final double dm = distance.distance(max, min, m);

				if (Double.compare(dm, 0) > 0) {
					for (int i = 1, n = set.size() - 1; i < n; ++i) {
						final double dist = distance.distance(
							set.get(idx[i - 1]),
							set.get(idx[i + 1]),
							m
						);

						result[idx[i]] += dist/dm;
					}
				}
			}
		}

		return result;
	}
public static < T > double [ ] crowdingDistance ( final Seq < ? extends T > set , final ElementComparator < ? super T > comparator , final ElementDistance < ? super T > distance , final ToIntFunction < ? super T > dimension ) { requireNonNull ( set ) ; requireNonNull ( comparator ) ; requireNonNull ( distance ) ; final double [ ] result = new double [ set . size ( ) ] ; if ( set . size ( ) < 3 ) { Arrays . fill ( result , POSITIVE_INFINITY ) ; } else { final int [ ] idx = new int [ set . size ( ) ] ; final IndexSorter sorter = IndexSorter . sorter ( set . size ( ) ) ; for ( int m = 0 , d = dimension . applyAsInt ( set . get ( 0 ) ) ; m < d ; ++ m ) { sorter . sort ( set , init ( idx ) , comparator . ofIndex ( m ) ) ; result [ idx [ 0 ] ] = POSITIVE_INFINITY ; result [ idx [ set . size ( ) - 1 ] ] = POSITIVE_INFINITY ; final T max = set . get ( idx [ 0 ] ) ; final T min = set . get ( idx [ set . size ( ) - 1 ] ) ; final double dm = distance . distance ( max , min , m ) ; if ( Double . compare ( dm , 0 ) > 0 ) { for ( int i = 1 , n = set . size ( ) - 1 ; i < n ; ++ i ) { final double dist = distance . distance ( set . get ( idx [ i - 1 ] ) , set . get ( idx [ i + 1 ] ) , m ) ; result [ idx [ i ] ] += dist / dm ; } } } } return result ; }
The crowding distance value of a solution provides an estimate of the
density of solutions surrounding that solution. The <em>crowding
distance</em> value of a particular solution is the average distance of
its two neighboring solutions.

@apiNote
Calculating the crowding distance has a time complexity of
{@code O(d*n*log(n))}, where {@code d} is the number of dimensions and
{@code n} the {@code set} size.

@see #crowdingDistance(Seq)

@param set the point set used for calculating the <em>crowding distance</em>
@param comparator the comparator which defines the (total) order of the
vector elements of {@code T}
@param distance the distance of two vector elements
@param dimension the dimension of vector type {@code T}
@param <T> the vector type
@return the crowded distances of the {@code set} points
@throws NullPointerException if one of the arguments is {@code null}