io.jenetics.ext.moea.NSGA2Selector Maven / Gradle / Ivy
/*
* Java Genetic Algorithm Library (jenetics-8.1.0).
* Copyright (c) 2007-2024 Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter ([email protected])
*/
package io.jenetics.ext.moea;
import static java.util.Objects.requireNonNull;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.ToIntFunction;
import java.util.stream.IntStream;
import io.jenetics.Gene;
import io.jenetics.Optimize;
import io.jenetics.Phenotype;
import io.jenetics.Selector;
import io.jenetics.util.ISeq;
import io.jenetics.util.ProxySorter;
import io.jenetics.util.Seq;
/**
* This selector selects the first {@code count} elements of the population,
* which has been sorted by the Crowded-Comparison Operator, as
* described in
* A Fast and Elitist Multiobjective Genetic Algorithm: NSGA-II
*
* Reference:
* K. Deb, A. Pratap, S. Agarwal, and T. Meyarivan. 2002. A fast and elitist
* multiobjective genetic algorithm: NSGA-II. Trans. Evol. Comp 6, 2
* (April 2002), 182-197. DOI=
* 10.1109/4235.996017
*
* @author Franz Wilhelmstötter
* @version 4.1
* @since 4.1
*/
public class NSGA2Selector<
G extends Gene, G>,
C extends Comparable super C>
>
implements Selector
{
private final Comparator> _dominance;
private final ElementComparator> _comparator;
private final ElementDistance> _distance;
private final ToIntFunction> _dimension;
/**
* Creates a new {@code NSGA2Selector} with the functions needed for
* handling the multi-objective result type {@code C}. For the {@link Vec}
* classes, a selector is created like in the following example:
* {@snippet lang="java":
* new NSGA2Selector<>(
* Vec::dominance,
* Vec::compare,
* Vec::distance,
* Vec::length
* );
* }
*
* @see #ofVec()
*
* @param dominance the pareto dominance comparator
* @param comparator the vector element comparator
* @param distance the vector element distance
* @param dimension the dimensionality of vector type {@code C}
*/
public NSGA2Selector(
final Comparator super C> dominance,
final ElementComparator super C> comparator,
final ElementDistance super C> distance,
final ToIntFunction super C> dimension
) {
requireNonNull(dominance);
requireNonNull(comparator);
requireNonNull(distance);
requireNonNull(dimension);
_dominance = (a, b) -> dominance.compare(a.fitness(), b.fitness());
_comparator = comparator.map(Phenotype::fitness);
_distance = distance.map(Phenotype::fitness);
_dimension = v -> dimension.applyAsInt(v.fitness());
}
@Override
public ISeq> select(
final Seq> population,
final int count,
final Optimize opt
) {
final CrowdedComparator> cc = new CrowdedComparator<>(
population,
opt,
_dominance,
_comparator,
_distance,
_dimension
);
final int[] idx = ProxySorter.sort(
init(new int[population.size()]),
population.size(),
(a, i, j) -> cc.compare(a[j], a[i])
);
final List> result = new ArrayList<>();
while (result.size() < count) {
IntStream.of(idx)
.limit(count - result.size())
.mapToObj(population)
.forEach(result::add);
}
return ISeq.of(result);
}
private static int[] init(final int[] indexes) {
for (int i = 0; i < indexes.length; ++i) indexes[i] = i;
return indexes;
}
/**
* Return a new selector for the given result type {@code V}. This method is
* a shortcut for
* {@snippet lang="java":
* new NSGA2Selector<>(
* Vec::dominance,
* Vec::compare,
* Vec::distance,
* Vec::length
* );
* }
*
* @param the gene type
* @param the array type, e.g. {@code double[]}
* @param the multi object result type vector
* @return a new selector for the given result type {@code V}
*/
public static , T, V extends Vec>
NSGA2Selector ofVec() {
return new NSGA2Selector<>(
Vec::dominance,
Vec::compare,
Vec::distance,
Vec::length
);
}
}