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

io.jenetics.engine.FutureEvaluator Maven / Gradle / Ivy

There is a newer version: 8.1.0
Show newest version
/*
 * Java Genetic Algorithm Library (jenetics-7.1.2).
 * Copyright (c) 2007-2023 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.engine;

import static java.util.Objects.requireNonNull;

import java.util.Iterator;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Function;

import io.jenetics.Gene;
import io.jenetics.Genotype;
import io.jenetics.Phenotype;
import io.jenetics.util.ISeq;
import io.jenetics.util.MSeq;
import io.jenetics.util.Seq;

/**
 * Example of an {@code Engine.Evaluator} where the fitness function returns
 * a {@link Future} of the fitness value instead the value itself.
 *
 * @author Franz Wilhelmstötter
 * @version 5.0
 * @since 5.0
 */
final class FutureEvaluator<
	G extends Gene,
	C extends Comparable
>
	implements Evaluator
{
	private final Function, ? extends Future> _fitness;

	FutureEvaluator(
		final Function, ? extends Future> fitness
	) {
		_fitness = requireNonNull(fitness);
	}

	@Override
	public ISeq> eval(final Seq> population) {
		final ISeq> evaluate = population.stream()
			.filter(Phenotype::nonEvaluated)
			.map(pt -> _fitness.apply(pt.genotype()))
			.collect(ISeq.toISeq());

		final ISeq> evaluated = population.stream()
			.filter(Phenotype::isEvaluated)
			.collect(ISeq.toISeq());

		join(evaluate);

		return evaluated.append(map(population, evaluate));
	}

	private static void join(final Iterable> futures) {
		final Iterator> it = futures.iterator();

		Exception exception = null;
		Future future = null;
		try {
			while (it.hasNext()) {
				future = it.next();
				future.get();
			}
			future = null;
		} catch (InterruptedException |
				ExecutionException |
				CancellationException e)
		{
			exception = e;
		}

		if (future != null) {
			future.cancel(true);
			while (it.hasNext()) {
				it.next().cancel(true);
			}
		}

		if (exception instanceof InterruptedException ie) {
			Thread.currentThread().interrupt();
			final var ce = new CancellationException(ie.getMessage());
			ce.initCause(ie);
			throw ce;
		} else if (exception instanceof CancellationException e) {
			throw e;
		} else if (exception != null) {
			throw new CompletionException(exception);
		}
	}

	private ISeq> map(
		final Seq> population,
		final Seq> fitnesses
	) {
		final ISeq> phenotypes = population.stream()
			.filter(Phenotype::nonEvaluated)
			.collect(ISeq.toISeq());
		assert phenotypes.length() == fitnesses.length();

		final MSeq> result = MSeq.ofLength(phenotypes.size());
		for (int i = 0; i < fitnesses.length(); ++i) {
			result.set(i, phenotypes.get(i).withFitness(get(fitnesses.get(i))));
		}

		return result.asISeq();
	}

	private static  T get(final Future future) {
		try {
			return future.get();
		} catch (InterruptedException|ExecutionException e) {
			throw new AssertionError(e);
		}
	}

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy