All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jenetics.ProbabilitySelector Maven / Gradle / Ivy

There is a newer version: 3.6.0
Show newest version
/*
 * Java Genetic Algorithm Library (jenetics-3.1.0).
 * Copyright (c) 2007-2015 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 org.jenetics;

import static java.lang.Math.abs;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.jenetics.internal.math.arithmetic.pow;
import static org.jenetics.internal.math.base.ulpDistance;
import static org.jenetics.internal.util.IndexSorter.sort;

import java.util.Random;
import java.util.function.Function;

import org.jenetics.internal.math.DoubleAdder;
import org.jenetics.internal.util.array;

import org.jenetics.util.RandomRegistry;

/**
 * Probability selectors are a variation of fitness proportional selectors and
 * selects individuals from a given population based on it's selection
 * probability P(i).
 * 

* Selection *

* Fitness proportional selection works as shown in the figure above. The * runtime complexity of the implemented probability selectors is * O(n+log(n)) instead of O(n2) as for the naive * approach: A binary (index) search is performed on the summed probability * array. * * @author Franz Wilhelmstötter * @since 1.0 * @version 3.0 */ public abstract class ProbabilitySelector< G extends Gene, C extends Comparable > implements Selector { private static final int SERIAL_INDEX_THRESHOLD = 35; private static final long MAX_ULP_DISTANCE = pow(10, 10); private final Function _reverter; /** * Create a new {@code ProbabilitySelector} with the given {@code sorting} * flag. This flag must set to {@code true} if the selector * implementation is sorting the population in the * {@link #probabilities(Population, int)} method. * * @param sorted {@code true} if the implementation is sorting the * population when calculating the selection probabilities, * {@code false} otherwise. */ protected ProbabilitySelector(final boolean sorted) { _reverter = sorted ? array::revert : ProbabilitySelector::sortAndRevert; } /** * Create a new selector with {@code sorted = false}. */ protected ProbabilitySelector() { this(false); } @Override public Population select( final Population population, final int count, final Optimize opt ) { requireNonNull(population, "Population"); requireNonNull(opt, "Optimization"); if (count < 0) { throw new IllegalArgumentException(format( "Selection count must be greater or equal then zero, but was %s.", count )); } final Population selection = new Population<>(count); if (count > 0) { final double[] prob = probabilities(population, count, opt); assert (population.size() == prob.length) : "Population size and probability length are not equal."; assert (sum2one(prob)) : "Probabilities doesn't sum to one."; incremental(prob); final Random random = RandomRegistry.getRandom(); selection.fill( () -> population.get(indexOf(prob, random.nextDouble())), count ); } return selection; } /** * This method takes the probabilities from the * {@link #probabilities(Population, int)} method and inverts it if needed. * * @param population The population. * @param count The number of phenotypes to select. * @param opt Determines whether the individuals with higher fitness values * or lower fitness values must be selected. This parameter * determines whether the GA maximizes or minimizes the fitness * function. * @return Probability array. */ protected final double[] probabilities( final Population population, final int count, final Optimize opt ) { return requireNonNull(opt) == Optimize.MINIMUM ? _reverter.apply(probabilities(population, count)) : probabilities(population, count); } // Package private for testing. static double[] sortAndRevert(final double[] array) { final int[] indexes = sort(array); // Copy the elements in reversed order. final double[] result = new double[array.length]; for (int i = 0; i < result.length; ++i) { result[indexes[result.length - 1 - i]] = array[indexes[i]]; } return result; } /** *

* Return an Probability array, which corresponds to the given Population. * The probability array and the population must have the same size. The * population is not sorted. If a subclass needs a sorted population, the * subclass is responsible to sort the population. *

* The implementer always assumes that higher fitness values are better. The * base class inverts the probabilities, by reverting the returned * probability array, if the GA is supposed to minimize the fitness function. * * @param population The unsorted population. * @param count The number of phenotypes to select. This parameter is not * needed for most implementations. * @return Probability array. The returned probability array must have the * length {@code population.size()} and must sum to * one. The returned value is checked with * {@code assert(Math.abs(math.sum(probabilities) - 1.0) < 0.0001)} * in the base class. */ protected abstract double[] probabilities( final Population population, final int count ); /** * Check if the given probabilities sum to one. * * @param probabilities the probabilities to check. * @return {@code true} if the sum of the probabilities are within the error * range, {@code false} otherwise. */ static boolean sum2one(final double[] probabilities) { final double sum = DoubleAdder.sum(probabilities); return abs(ulpDistance(sum, 1.0)) < MAX_ULP_DISTANCE; } static int indexOf(final double[] incr, final double v) { return incr.length <= SERIAL_INDEX_THRESHOLD ? indexOfSerial(incr, v) : indexOfBinary(incr, v); } /** * Perform a binary-search on the summed probability array. */ static int indexOfBinary(final double[] incr, final double v) { int imin = 0; int imax = incr.length; int index = -1; while (imax > imin && index == -1) { final int imid = (imin + imax) >>> 1; if (imid == 0 || (incr[imid] >= v && incr[imid - 1] < v)) { index = imid; } else if (incr[imid] <= v) { imin = imid + 1; } else if (incr[imid] > v) { imax = imid; } } return index; } /** * Perform a serial-search on the summed probability array. */ static int indexOfSerial(final double[] incr, final double v) { int index = -1; for (int i = 0; i < incr.length && index == -1; ++i) { if (incr[i] >= v) { index = i; } } return index; } /** * In-place summation of the probability array. */ static double[] incremental(final double[] values) { final DoubleAdder adder = new DoubleAdder(values[0]); for (int i = 1; i < values.length; ++i) { values[i] = adder.add(values[i]).doubleValue(); } return values; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy