Commit fd20788a authored by Christian Reuschling's avatar Christian Reuschling
Browse files

added metadata concept - this enables sophisticated use cases, e.g. deep...

added metadata concept - this enables sophisticated use cases, e.g. deep learning population based training
parent 685636c1
Pipeline #16340 passed with stages
in 53 seconds
.idea/
logs/
target/
testCache
......@@ -25,8 +25,8 @@ showMonitorGui=true
weakRefCache=false
# If set, a persistent cache is used. If the value is empty, GenIe uses an in-memory cache
persistentCacheDir=
# Parallelize the vector fitness calculations. If multithreaded, the system uses as many threads as cpu cores
singleThreaded=true
# The number of threads that will be used to calculate fitness calculations in parallel. If set < 1, the system uses as many threads as cpu cores
threadCount=1
# GenIe first performs a loop over all given values of all parameters, whereby the default value of the other parameters stay fixed. The default
......@@ -128,9 +128,20 @@ firstGenerationParentMetadata=
# The fitness function call for a candidate vector recieves the metadata of the top N candidate vectors from its parent population for information.
# This can e.g. be used for population based training. Here you can specify the count for the top N list. This value has NO influence to the genetic
# optimization, it is just about metadata for the fitness function
# optimization, it is just about metadata for the fitness function. The fitness function also gets a randomly selected entry from this list of top N
# parent population candidates for population based training. This entry can also be empty, by random
eliteMetadataCount=3
# The fitnessScore of a candidate vector can be potentially calculated by the cost function with this information: 1. candidate vector entries,
# 2. metadata parts from the parents, 3. metadata parts from the population elite, 4. metadata parts from the randomly selected elite candidate (if picked).
# For cache lookup, GenIe needs to know all relevant parts beside the vector entries, that are somehow relevant for fitnessScore calculation.
# If not specified correctly, GenIe picks formerly calculated fitnessScores by the vector entries only, which can yield to wrong values
#e.g. selectedEliteMetadataAtts4cacheLookup=attName1,attName2,attNameN
parentMetadataAtts4cacheLookup=
eliteMetadataAtts4cacheLookup=
selectedEliteMetadataAtts4cacheLookup=
# For using GenIe standalone, you can specify an exec call for the fitness function. This executable will be called for each candidate vector
# evaluation, receiving the candidate vector values as invocation arguments (just strings from the configured value range), or over stdIn if enabled.
# The forelast invocation argument will be the parents metadata (json), the last argument the metadata from the top N candidate vectors of the parent
......
......@@ -32,11 +32,11 @@
<distributionManagement>
<repository>
<id>artifactory-libs-releases-local</id>
<url>http://www.dfki.uni-kl.de/artifactory/libs-releases-local</url>
<url>https://www.dfki.uni-kl.de/artifactory/libs-releases-local</url>
</repository>
<snapshotRepository>
<id>artifactory-libs-snapshots-local</id>
<url>http://www.dfki.uni-kl.de/artifactory/libs-snapshots-local</url>
<url>https://www.dfki.uni-kl.de/artifactory/libs-snapshots-local</url>
</snapshotRepository>
</distributionManagement>
......@@ -44,11 +44,11 @@
<repositories>
<repository>
<id>artifactory-libs-releases</id>
<url>http://www.dfki.uni-kl.de/artifactory/libs-releases</url>
<url>https://www.dfki.uni-kl.de/artifactory/libs-releases</url>
</repository>
<repository>
<id>artifactory-libs-snapshots</id>
<url>http://www.dfki.uni-kl.de/artifactory/libs-snapshots</url>
<url>https://www.dfki.uni-kl.de/artifactory/libs-snapshots</url>
</repository>
</repositories>
......
......@@ -29,14 +29,14 @@ import java.util.regex.Pattern;
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_str", "m_l", "m_hs", "m_s", "m_", "d", "f", "str", "l", "hs", "s", ""})
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_str", "m_l", "m_i", "m_hs", "m_s", "m_", "d", "f", "str", "l", "hs", "s", ""})
public class GenIe extends GeneticParamOptimizer
{
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_str", "m_l", "m_hs", "m_s", "m_", "d", "f", "str", "l", "hs", "s", ""})
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_str", "m_l", "m_i", "m_hs", "m_s", "m_", "d", "f", "str", "l", "hs", "s", ""})
@Data
public static class FitnessFunctionStdInInput
{
......@@ -44,6 +44,7 @@ public class GenIe extends GeneticParamOptimizer
List<String> candidateVector;
List<HashMap<String, String>> parentsMetadata;
List<HashMap<String, String>> eliteMetadata;
HashMap<String, String> selectedEliteMetadata;
}
......@@ -119,8 +120,12 @@ public class GenIe extends GeneticParamOptimizer
lCommand.add(strJson4ParentMetadata);
// elite
String strJson4TopNMetadata =
JsonWriter.objectToJson(candidate.getTopNParentGenerationMetadata(), CollectionUtilz.createHashMap(JsonWriter.TYPE, false, JsonWriter.PRETTY_PRINT, true));
JsonWriter.objectToJson(candidate.getParentsGenEliteMetadata(), CollectionUtilz.createHashMap(JsonWriter.TYPE, false, JsonWriter.PRETTY_PRINT, true));
lCommand.add(strJson4TopNMetadata);
// selected elite
String strJson4SelectedTopNMetadata = JsonWriter.objectToJson(candidate.getParentsGenSelectedEliteMetadata(),
CollectionUtilz.createHashMap(JsonWriter.TYPE, false, JsonWriter.PRETTY_PRINT, true));
lCommand.add(strJson4SelectedTopNMetadata);
}
ProcessBuilder builder = new ProcessBuilder(lCommand);
......@@ -131,7 +136,8 @@ public class GenIe extends GeneticParamOptimizer
FitnessFunctionStdInInput stdInInput =
new FitnessFunctionStdInInput().setCandidateVectorParamNames(candidate.getCandidateVectorParamNames()).setCandidateVector(candidate.getCandidateVector())
.setParentsMetadata(candidate.getParentMetadata()).setEliteMetadata(candidate.getTopNParentGenerationMetadata());
.setParentsMetadata(candidate.getParentMetadata()).setEliteMetadata(candidate.getParentsGenEliteMetadata())
.setSelectedEliteMetadata(candidate.getParentsGenSelectedEliteMetadata());
String strJson4StdInInput = JsonWriter.objectToJson(stdInInput, CollectionUtilz.createHashMap(JsonWriter.TYPE, false, JsonWriter.PRETTY_PRINT, true));
outputStreamWriter.write(strJson4StdInInput);
outputStreamWriter.close();
......
......@@ -2,17 +2,22 @@ package de.dfki.sds.genie.genetic;
import de.dfki.inquisitor.collections.CollectionUtilz;
import de.dfki.inquisitor.text.EncryptionUtils;
import de.dfki.inquisitor.text.StringUtils;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_str", "m_l", "m_hs", "m_s", "m_", "d", "f", "str", "l", "hs", "s", ""})
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_str", "m_l", "m_i", "m_hs", "m_s", "m_", "d", "f", "str", "l", "hs", "s", ""})
// @Builder(toBuilder=true)
@Data
public class CandidateVectorWithMetadata
......@@ -27,31 +32,41 @@ public class CandidateVectorWithMetadata
*/
List<String> m_lCandidateVectorParamNames;
/**
* TODO - wollen wir hier wirklich eine HashMap oder schleifen wir die einfach unverarbeitet durch
* Optional. Some arbitrary metadata given from the cost function (or maybe initially from the config for the first generation)
* Dealing with metadata is optional. Some arbitrary metadata given from the cost function (or maybe initially from the config for the first generation)
*/
HashMap<String, String> m_hsMetadata = new HashMap<>();
/**
* Optional. The metadata of the parents, will be given to the cost function for information
* Dealing with metadata is optional. The metadata of the parents, will be given to the cost function for information
*/
List<HashMap<String, String>> m_lParentMetadata;
/**
* Optional. The metadata of the topN parent generation candidates, will be given to the cost function for information
* Dealing with metadata is optional. The metadata of the topN parent generation candidates, will be given to the cost function for information
*/
List<HashMap<String, String>> m_lTopNParentGenerationMetadata;
List<HashMap<String, String>> m_lParentsGenEliteMetadata;
/**
* Dealing with metadata is optional. A randomly selected entry from the list of the topN parent generation candidate metadata. This can be used for population based
* training. Will be given to the
* cost function for information. Note that the cache lookup keys will be generated according the candidates vector entries plus selected metadata attribute entries out of
* this member variable
*/
HashMap<String, String> m_hsParentsGenSelectedEliteMetadata = new HashMap<>();
/**
* Optional. The scores of the parents in the same order as the parents metadata. Will be given to the cost function for information
* Will be set by the system (by crossover.mate(..)). The scores of the parents in the same order as the parents metadata. Will be given to the cost function for information
*/
List<Double> m_lParentScores;
/**
* Optional. The scores of the topN parent generation candidates in the same order as the according metadata list. Will be given to the cost function for information
* Will be set by the system (by the evolutionEngine). The scores of the topN parent generation candidates in the same order as the according metadata list. Will be given to
* the cost function for information
*/
List<Double> m_lTopNParentGenerationScores;
/**
* Will be set by the system
* Will be set by the system (by the cost function)
*/
Double m_dFitnessScore = Double.NaN;
public CandidateVectorWithMetadata(List<String> candidateVectorParamNames)
{
m_lCandidateVectorParamNames = candidateVectorParamNames;
......@@ -71,22 +86,73 @@ public class CandidateVectorWithMetadata
clone.setMetadata(new HashMap<>(this.getMetadata()));
if (this.getParentMetadata() != null)
{
List<HashMap<String, String>> lParentMetadataNew = this.getParentMetadata().stream().map(HashMap::new).toList();
List<HashMap<String, String>> lParentMetadataNew = this.getParentMetadata().stream().map(HashMap::new).collect(Collectors.toList());
clone.setParentMetadata(lParentMetadataNew);
}
if (this.getParentScores() != null)
clone.setParentScores(new ArrayList<>(this.getParentScores()));
if (this.getTopNParentGenerationMetadata() != null)
if (this.getParentsGenEliteMetadata() != null)
{
List<HashMap<String, String>> lTopNMetadataNew = this.getParentMetadata().stream().map(HashMap::new).toList();
clone.setTopNParentGenerationMetadata(lTopNMetadataNew);
List<HashMap<String, String>> lTopNMetadataNew = this.getParentMetadata().stream().map(HashMap::new).collect(Collectors.toList());
clone.setParentsGenEliteMetadata(lTopNMetadataNew);
}
if (this.getTopNParentGenerationScores() != null)
clone.setTopNParentGenerationScores(new ArrayList<>(this.getTopNParentGenerationScores()));
if (this.getParentsGenSelectedEliteMetadata() != null)
clone.setParentsGenSelectedEliteMetadata(new HashMap<>(this.getParentsGenSelectedEliteMetadata()));
clone.setFitnessScore(this.getFitnessScore());
return clone;
}
/**
* For looking into the cache wether a candidate vector was formerly evaluated or not two criterias will be considered:
* 1. The entries of the candidate vector itself
* 2. Optionally if set, some attribute values out of a randomly selected topN parent generation candidate. This can be used for population based training, where a metadatum
* can yield to another fitness value.
*/
public String generateCacheLookupKey(Set<String> parentMetadataAtts4cacheLookup, Set<String> eliteMetadataAtts4cacheLookup,
Set<String> selectedEliteEntryMetadataAtts4cacheLookup)
{
StringBuilder strbCacheKey = new StringBuilder();
strbCacheKey.append(m_lCandidateVector.toString());
if (CollectionUtilz.notNullOrEmpty(m_lParentMetadata) && CollectionUtilz.notNullOrEmpty(parentMetadataAtts4cacheLookup))
{
strbCacheKey.append("_parentsData_");
for (HashMap<String, String> hsParentData : m_lParentMetadata)
{
strbCacheKey.append("___");
for (String strAttName : parentMetadataAtts4cacheLookup)
strbCacheKey.append('_').append(strAttName).append(':').append(hsParentData.getOrDefault(strAttName, "null"));
}
}
if (CollectionUtilz.notNullOrEmpty(m_lParentsGenEliteMetadata) && CollectionUtilz.notNullOrEmpty(eliteMetadataAtts4cacheLookup))
{
strbCacheKey.append("_parentsGenEliteData_");
for (HashMap<String, String> hsParentsGenEliteData : m_lParentsGenEliteMetadata)
{
strbCacheKey.append("___");
for (String strAttName : eliteMetadataAtts4cacheLookup)
strbCacheKey.append('_').append(strAttName).append(':').append(hsParentsGenEliteData.getOrDefault(strAttName, "null"));
}
}
if (m_hsParentsGenSelectedEliteMetadata != null && CollectionUtilz.notNullOrEmpty(selectedEliteEntryMetadataAtts4cacheLookup))
{
strbCacheKey.append("_parentsGenSelectedEliteData_");
for (String strAttName : selectedEliteEntryMetadataAtts4cacheLookup)
strbCacheKey.append('_').append(strAttName).append(':').append(m_hsParentsGenSelectedEliteMetadata.getOrDefault(strAttName, "null"));
}
return StringUtils.cut(m_lCandidateVector.toString(), 123) +"__"+ EncryptionUtils.md5Hash( strbCacheKey.toString());
}
}
package de.dfki.sds.genie.genetic;
import org.uncommons.util.concurrent.ConfigurableThreadFactory;
import org.uncommons.util.id.IDSource;
import org.uncommons.util.id.IntSequenceIDSource;
import org.uncommons.util.id.StringPrefixIDSource;
import org.uncommons.watchmaker.framework.EvaluatedCandidate;
import java.util.concurrent.*;
public class ConfigurableFitnessEvaluationWorker
{
// Provide each worker instance with a unique name with which to prefix its threads.
private static final IDSource<String> WORKER_ID_SOURCE = new StringPrefixIDSource("ConfigurableFitnessEvaluationWorker", new IntSequenceIDSource());
/**
* Thread pool that performs concurrent fitness evaluations.
*/
protected final ThreadPoolExecutor executor;
public ConfigurableFitnessEvaluationWorker(int numberOfThreads)
{
ConfigurableThreadFactory threadFactory = new ConfigurableThreadFactory(WORKER_ID_SOURCE.nextID(), Thread.NORM_PRIORITY, true);
LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
this.executor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads, 60, TimeUnit.SECONDS, workQueue, threadFactory);
executor.prestartAllCoreThreads();
}
/**
* A FitnessWorker cannot be garbage-collected if its thread pool has not been shutdown.
* This method, invoked on garabage collection (or maybe not at all), shuts down the thread
* pool so that the threads can be released.
*
* @throws Throwable Any exception or error that occurs during finalisation.
*/
@Override
protected void finalize() throws Throwable
{
executor.shutdown();
super.finalize();
}
public <T> Future<EvaluatedCandidate<T>> submit(Callable<EvaluatedCandidate<T>> task)
{
return executor.submit(task);
}
}
......@@ -88,10 +88,8 @@ public abstract class GeneticParamOptimizer
// CandidateVectorWithMetadata
List<List<String>> lVectors = m_listCrossover.publicMate(parent1.getCandidateVector(), parent2.getCandidateVector(), numberOfCrossoverPoints, rng);
CandidateVectorWithMetadata offspring1 =
new CandidateVectorWithMetadata(parent1.m_lCandidateVectorParamNames).setCandidateVector(lVectors.get(0));
CandidateVectorWithMetadata offspring2 =
new CandidateVectorWithMetadata(parent1.m_lCandidateVectorParamNames).setCandidateVector(lVectors.get(1));
CandidateVectorWithMetadata offspring1 = new CandidateVectorWithMetadata(parent1.m_lCandidateVectorParamNames).setCandidateVector(lVectors.get(0));
CandidateVectorWithMetadata offspring2 = new CandidateVectorWithMetadata(parent1.m_lCandidateVectorParamNames).setCandidateVector(lVectors.get(1));
// Die Nachkommen kriegen die Metadaten und die scores ihrer Eltern mit
......@@ -265,6 +263,7 @@ public abstract class GeneticParamOptimizer
protected List<GeneticParamOptimizerGod> m_lGods = new LinkedList<>();
protected LinkedHashMap<String, List<String>> m_lhsParamNames2DiscreteValSpace;
protected GeneticRunConfig m_geneticRunConfig = null;
protected ConfigurableFitnessEvaluationWorker m_fitnessEvaluationWorker;
......@@ -774,9 +773,11 @@ public abstract class GeneticParamOptimizer
else
{
m_cachedFitnessEvaluator =
new CachingFitnessEvaluatorWrapper<>(new ParamFitnessEvaluator()).setStringKeys(true).setPersist(m_geneticRunConfig.m_strPath2PersistentResultCache, true)
new CachingFitnessEvaluatorWrapper(new ParamFitnessEvaluator()).setStringKeys(true).setPersist(m_geneticRunConfig.m_strPath2PersistentResultCache, true)
.setLogMessageString("'" + this.getClass().getSimpleName() + "' ").setPermutationCount(lPermutations)
.setInterruptIfException(m_geneticRunConfig.m_bInterruptIfException);
.setInterruptIfException(m_geneticRunConfig.m_bInterruptIfException)
.setMetadataAtts4cacheLookup(m_geneticRunConfig.getParentMetadataAtts4cacheLookup(), m_geneticRunConfig.getEliteMetadataAtts4cacheLookup(),
m_geneticRunConfig.getSelectedEliteMetadataAtts4cacheLookup());
if (StringUtils.notNullOrWhitespace(m_geneticRunConfig.m_strPath2PersistentResultCache))
((CachingFitnessEvaluatorWrapper) m_cachedFitnessEvaluator).setCreateCsv4Results(m_geneticRunConfig.m_strPath2PersistentResultCache + "/cachedResults.csv",
......@@ -844,6 +845,15 @@ public abstract class GeneticParamOptimizer
else
selectionStrategy = new SigmaScaling();
// wir starten den Threadpool, falls wir multiThreaded fahren. Dieser ist über den Islands geshared, bei jedem Aufruf von optimzeParams wird die Anzahl Threads neu gesetzt
int iThreadCount = m_geneticRunConfig.getThreadCount();
if (iThreadCount < 1)
iThreadCount = Runtime.getRuntime().availableProcessors();
m_fitnessEvaluationWorker = new ConfigurableFitnessEvaluationWorker(iThreadCount);
if (m_geneticRunConfig.m_islandCount > 1)
{
......@@ -855,7 +865,6 @@ public abstract class GeneticParamOptimizer
NonShrinkingGenerationalEvolutionEngine subEngine =
new NonShrinkingGenerationalEvolutionEngine(candidateFactory, evolutionPipeline, m_cachedFitnessEvaluator, selectionStrategy, rng,
m_geneticRunConfig.m_populationSize, this);
subEngine.setSingleThreaded(m_geneticRunConfig.m_bSingleThreaded);
llIslandEvolutions.add(subEngine);
}
......@@ -887,7 +896,6 @@ public abstract class GeneticParamOptimizer
NonShrinkingGenerationalEvolutionEngine engine =
new NonShrinkingGenerationalEvolutionEngine(candidateFactory, evolutionPipeline, m_cachedFitnessEvaluator, selectionStrategy, rng,
m_geneticRunConfig.m_populationSize, this);
engine.setSingleThreaded(m_geneticRunConfig.m_bSingleThreaded);
engine.addEvolutionObserver(m_hallOfFameObserver);
......
......@@ -18,7 +18,7 @@ import java.util.LinkedList;
import java.util.List;
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_b", "m_str", "m_l", "m_hs", "m_s", "m_", "d", "f", "b", "str", "l", "hs", "s", ""})
@Accessors(chain = true, prefix = {"m_d", "m_f", "m_b", "m_str", "m_l", "m_i", "m_hs", "m_s", "m_", "d", "f", "b", "str", "l", "hs", "s", ""})
@Data
public class GeneticRunConfig
{
......@@ -34,7 +34,7 @@ public class GeneticRunConfig
public boolean m_bConstantRandomSeed = true;
public boolean m_bLowerScoreIsBetter = false;
public boolean m_bRuntimeFitness = false;
public boolean m_bSingleThreaded;
public int m_iThreadCount = 1;
public boolean m_bSkipGeneticRun = false;
public boolean m_bVerbose = false;
public boolean m_bWeakRefCache = false;
......@@ -55,6 +55,9 @@ public class GeneticRunConfig
public boolean m_bInterruptIfException;
public String m_strPath2PersistentResultCache;
public HashMap<String, String> m_firstGenerationParentMetadata = new HashMap<>();
public List<String> m_lParentMetadataAtts4cacheLookup;
public List<String> m_lEliteMetadataAtts4cacheLookup;
public List<String> m_lSelectedEliteMetadataAtts4cacheLookup;
......@@ -80,7 +83,7 @@ public class GeneticRunConfig
m_iEvaluateLastWinnersCount = geneticConfig.getUniqueAsInteger("evaluateLastWinnersCount");
m_showMonitorGui = geneticConfig.getUniqueAsBoolean("showMonitorGui");
m_bWeakRefCache = geneticConfig.getUniqueAsBoolean("weakRefCache");
m_bSingleThreaded = geneticConfig.getUniqueAsBoolean("singleThreaded");
m_iThreadCount = geneticConfig.getUniqueAsInteger("threadCount");
m_bConstantRandomSeed = geneticConfig.getUniqueAsBoolean("constantRandomSeed");
m_bSkipGeneticRun = geneticConfig.getUniqueAsBoolean("skipGeneticRun");
......@@ -117,6 +120,11 @@ public class GeneticRunConfig
.forEach(entry -> m_firstGenerationParentMetadata.put(entry.getKey(), entry.getValue().getAsString()));
m_eliteMetadataCount4Metadata = geneticConfig.getUniqueAsInteger("eliteMetadataCount");
m_lParentMetadataAtts4cacheLookup = geneticConfig.getFirstAsParsedEnumString("parentMetadataAtts4cacheLookup", null);
m_lEliteMetadataAtts4cacheLookup = geneticConfig.getFirstAsParsedEnumString("eliteMetadataAtts4cacheLookup", null);
m_lSelectedEliteMetadataAtts4cacheLookup = geneticConfig.getFirstAsParsedEnumString("selectedEliteMetadataAtts4cacheLookup", null);
return this;
}
......
......@@ -9,6 +9,8 @@ import org.uncommons.watchmaker.framework.interactive.InteractiveSelection;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
......@@ -34,13 +36,9 @@ public class NonShrinkingGenerationalEvolutionEngine extends GenerationalEvoluti
protected FitnessEvaluator<? super CandidateVectorWithMetadata> fitnessEvaluator;
protected CandidatesEntropyAnalyzer m_candidatesEntropyAnalyzer = new CandidatesEntropyAnalyzer();
protected int m_populationSize;
protected Set<EvolutionObserver<? super CandidateVectorWithMetadata>> observers = new CopyOnWriteArraySet<EvolutionObserver<? super CandidateVectorWithMetadata>>();
protected Random rng;
protected List<TerminationCondition> satisfiedTerminationConditions;
protected SelectionStrategy<? super CandidateVectorWithMetadata> selectionStrategy;
......@@ -104,6 +102,70 @@ public class NonShrinkingGenerationalEvolutionEngine extends GenerationalEvoluti
/**
* Takes a population, assigns a fitness score to each member and returns
* the members with their scores attached, sorted in descending order of
* fitness (descending order of fitness score for natural scores, ascending
* order of scores for non-natural scores).
*
* @param population The population to evaluate (each candidate is assigned
* a fitness score).
*
* @return The evaluated population (a list of candidates with attached fitness
* scores).
*/
protected List<EvaluatedCandidate<CandidateVectorWithMetadata>> evaluatePopulation(List<CandidateVectorWithMetadata> population)
{
// This is the code from AbstractEvolutionEngine, modificated to use a FitnessEvaluationWorker where you can specify the number of threads to generate, in the
// multithreading scenario. Sadly, the default worker only offers to use the current number of CPU cores
List<EvaluatedCandidate<CandidateVectorWithMetadata>> evaluatedPopulation = new ArrayList<>(population.size());
if (m_geneticParamOptimizer.m_geneticRunConfig.getThreadCount() == 1) // Do fitness evaluations on the request thread.
{
for (CandidateVectorWithMetadata candidate : population)
{
evaluatedPopulation.add(new EvaluatedCandidate<CandidateVectorWithMetadata>(candidate, fitnessEvaluator.getFitness(candidate, population)));
}
}
else
{
// Divide the required number of fitness evaluations equally among the
// available threads and coordinate the threads so that we do not
// proceed until all threads have finished processing.
try
{
List<CandidateVectorWithMetadata> unmodifiablePopulation = Collections.unmodifiableList(population);
List<Future<EvaluatedCandidate<CandidateVectorWithMetadata>>> results = new ArrayList<>(population.size());
// Submit tasks for execution and wait until all threads have finished fitness evaluations.
for (CandidateVectorWithMetadata candidate : population)
{
results.add(m_geneticParamOptimizer.m_fitnessEvaluationWorker.submit(
() -> new EvaluatedCandidate<>(candidate, fitnessEvaluator.getFitness(candidate, unmodifiablePopulation))));
}
for (Future<EvaluatedCandidate<CandidateVectorWithMetadata>> result : results)
{
evaluatedPopulation.add(result.get());
}
} catch (ExecutionException ex)
{
throw new IllegalStateException("Fitness evaluation task execution failed.", ex);
} catch (InterruptedException ex)
{
// Restore the interrupted status, allows methods further up the call-stack
// to abort processing if appropriate.
Thread.currentThread().interrupt();
}
}
return evaluatedPopulation;
}
/**
* {@inheritDoc}
*/
......@@ -257,8 +319,14 @@ public class NonShrinkingGenerationalEvolutionEngine extends GenerationalEvoluti
// When the evolution is finished, add the elite to the population.
lChildren.addAll(lElite);
// topN Elite as information to the cost function
lChildren.forEach(child -> child.setTopNParentGenerationMetadata(lEliteMetadata4Metadata));
lChildren.forEach(child -> child.setParentsGenEliteMetadata(lEliteMetadata4Metadata));
lChildren.forEach(child -> child.setTopNParentGenerationScores(lEliteScores4Metadata));
lChildren.forEach(child -> {
// a random one or nothing
int iIndex = rng.nextInt(lEliteMetadata4Metadata.size() + 1);
if (iIndex < lEliteMetadata4Metadata.size())
child.setParentsGenSelectedEliteMetadata(lEliteMetadata4Metadata.get(iIndex));
});
......
......@@ -18,16 +18,16 @@ public class Sum23Test
public static void main(String[] args)
{
// CandidateVectorWithMetadata bestVector = new GenIe().setFitnessCalculator((candidate, population) -> {
// int iSum = candidate.getCandidateVector().stream().mapToInt(Integer::valueOf).sum();
//
// if (iSum == 23)
// return 0.9d;
//
// return 0d;
// }).optimizeParams("src/test/java/de/dfki/sds/genie/geneticOptimization.conf");
CandidateVectorWithMetadata bestVector = new GenIe().optimizeParams("src/test/java/de/dfki/sds/genie/geneticOptimization.conf");
CandidateVectorWithMetadata bestVector = new GenIe().setFitnessCalculator((candidate, population) -> {
int iSum = candidate.getCandidateVector().stream().mapToInt(Integer::valueOf).sum();
if (iSum == 23)
return 0.9d;
return 0d;
}).optimizeParams("src/test/java/de/dfki/sds/genie/geneticOptimization.conf");
// CandidateVectorWithMetadata bestVector = new GenIe().optimizeParams("src/test/java/de/dfki/sds/genie/geneticOptimization.conf");
}