Merge branch 'irace-interface'

This commit is contained in:
Johann Dreo 2020-10-11 15:44:29 +02:00
commit ce10a6d4d2
35 changed files with 2024 additions and 137 deletions

View file

@ -0,0 +1,97 @@
######################################################################################
# Project settings
######################################################################################
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project("paradiseo-irace")
enable_language(CXX) # C++
set(CMAKE_CXX_STANDARD 17)
## Current version
set(VERSION_MAJOR 0 CACHE STRING "Major version number" )
set(VERSION_MINOR 1 CACHE STRING "Minor version number" )
set(VERSION_PATCH 0 CACHE STRING "Patch version number" )
mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH)
######################################################################################
# Configurable user settings
######################################################################################
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
# put binaries in the build directory
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# Dump used compiler flags.
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
######################################################################################
# Dependencies
######################################################################################
# ParadisEO
set(PARADISEO_ROOT "../../../../paradiseo" CACHE PATH "Where to find ParadisEO")
set(PARADISEO_BUILD "${PARADISEO_ROOT}/build" CACHE PATH "Build dir of ParadisEO")
include_directories(${PARADISEO_ROOT})
include_directories(${PARADISEO_ROOT}/eo/src)
link_directories(${PARADISEO_BUILD}/lib)
set(PARADISEO_LIBRARIES ga eoutils eo)
# IOH
set(IOH_ROOT "~/code/IOHexperimenter/" CACHE PATH "Where to find IOHexperimenter")
find_path(IOH_PROBLEM_H "IOHprofiler_problem.h" PATHS ${IOH_ROOT}/src/Template/)
find_library(IOH_LIBRARY "IOH" PATHS ${IOH_ROOT} PATH_SUFFIXES release Release debug Debug build Build)
if(EXISTS ${IOH_PROBLEM_H} AND EXISTS ${IOH_LIBRARY})
message(STATUS "Found IOH in ${IOH_ROOT}")
include_directories(${IOH_ROOT}/build/Cpp/src/)
link_directories(${IOH_ROOT}/build/Cpp/bin/)
# Workaround IOH's poorly designed headers inclusion scheme.
SET(PROBLEMS_BBOB_DIR "src/Problems/BBOB")
SET(PROBLEMS_BBOB_COMMON_DIR "src/Problems/BBOB/bbob_common_used_functions")
SET(PROBLEMS_COMMON_DIR "src/Problems/common_used_functions")
SET(PROBLEMS_PBO_DIR "src/Problems/PBO")
SET(PROBLEMS_WMODEL_DIR "src/Problems/WModel")
SET(PROBLEMS_PYTHON_DIR "src/Problems/Python")
SET(SUITES_DIR "src/Suites")
SET(TEMPLATE_DIR "src/Template")
SET(TEMPLATE_EXPERIMENTS_DIR "src/Template/Experiments")
SET(TEMPLATE_LOGGERS_DIR "src/Template/Loggers")
SET(IOHEXPERIMENTER_DIR
"${IOH_ROOT}/${PROBLEMS_COMMON_DIR}"
"${IOH_ROOT}/${PROBLEMS_BBOB_DIR}"
"${IOH_ROOT}/${PROBLEMS_BBOB_COMMON_DIR}"
"${IOH_ROOT}/${PROBLEMS_PBO_DIR}"
"${IOH_ROOT}/${PROBLEMS_WMODEL_DIR}"
"${IOH_ROOT}/${PROBLEMS_PYTHON_DIR}"
"${IOH_ROOT}/${SUITES_DIR}"
"${IOH_ROOT}/${TEMPLATE_DIR}"
"${IOH_ROOT}/${TEMPLATE_EXPERIMENTS_DIR}"
"${IOH_ROOT}/${TEMPLATE_LOGGERS_DIR}"
)
include_directories(${IOHEXPERIMENTER_DIR})
else()
if(NOT EXISTS ${IOH_PROBLEM_H})
message(FATAL_ERROR "Could not find `IOHprofiler_problem.h` in: ${IOH_ROOT}/src/Template/ (did you forget to compile it?)")
endif()
if(NOT EXISTS ${IOH_LIBRARIES})
message(FATAL_ERROR "Could not find `libIOH` in: ${IOH_ROOT}/[release|debug|build] (did you forget to compile it?)")
endif()
endif()
######################################################################################
# Start building
######################################################################################
add_executable(fastga fastga.cpp)
target_link_libraries(fastga ${PARADISEO_LIBRARIES} ${IOH_LIBRARY})

417
eo/contrib/irace/fastga.cpp Normal file
View file

@ -0,0 +1,417 @@
#include <iostream>
#include <cstdlib>
#include <string>
#include <eo>
#include <ga.h>
#include <utils/checkpointing>
#include <eoInt.h>
#include <problems/eval/eoEvalIOH.h>
#include <IOHprofiler_ecdf_logger.h>
#include <f_w_model_one_max.hpp>
// using Particle = eoRealParticle<eoMaximizingFitness>;
using Ints = eoInt<eoMaximizingFitnessT<int>, size_t>;
using Bits = eoBit<eoMaximizingFitnessT<int>, int>;
// by enumerating candidate operators and their parameters.
eoAlgoFoundryFastGA<Bits>& make_foundry(
eoFunctorStore& store,
eoInit<Bits>& init,
eoEvalFunc<Bits>& eval_onemax,
const size_t max_evals,
const size_t generations
)
{
// FIXME using max_restarts>1 does not allow to honor max evals.
auto& foundry = store.pack< eoAlgoFoundryFastGA<Bits> >(init, eval_onemax, max_evals, /*max_restarts=*/1);
/***** Continuators ****/
foundry.continuators.add< eoGenContinue<Bits> >(generations);
// for(size_t i=1; i<10; i++) {
// foundry.continuators.add< eoGenContinue<Bits> >(i);
// }
// for(size_t i=10; i < 100; i+=2 ) {
// foundry.continuators.add< eoSteadyFitContinue<Bits> >(10,i);
// }
for(double i=0.0; i<1.0; i+=0.2) {
foundry.crossover_rates.add<double>(i);
foundry.mutation_rates.add<double>(i);
}
/***** Offsprings size *****/
// for(size_t i=5; i<100; i+=10) {
// foundry.offspring_sizes.add<size_t>(i);
// }
foundry.offspring_sizes.add<size_t>(0); // 0 = use parents fixed pop size.
/***** Crossovers ****/
for(double i=0.1; i<1.0; i+=0.2) {
foundry.crossovers.add< eoUBitXover<Bits> >(i); // preference over 1
}
for(size_t i=1; i < 10; i+=2) {
foundry.crossovers.add< eoNPtsBitXover<Bits> >(i); // nb of points
}
foundry.crossovers.add< eo1PtBitXover<Bits> >();
/***** Mutations ****/
double p = 1.0; // Probability of flipping eath bit.
foundry.mutations.add< eoUniformBitMutation<Bits> >(p); // proba of flipping k bits, k drawn in uniform distrib
foundry.mutations.add< eoStandardBitMutation<Bits> >(p); // proba of flipping k bits, k drawn in binomial distrib
foundry.mutations.add< eoConditionalBitMutation<Bits> >(p); // proba of flipping k bits, k drawn in binomial distrib, minus zero
foundry.mutations.add< eoShiftedBitMutation<Bits> >(p); // proba of flipping k bits, k drawn in binomial distrib, changing zeros to one
foundry.mutations.add< eoNormalBitMutation<Bits> >(p); // proba of flipping k bits, k drawn in normal distrib
foundry.mutations.add< eoFastBitMutation<Bits> >(p); // proba of flipping k bits, k drawn in powerlaw distrib
for(size_t i=1; i < 11; i+=2) {
foundry.mutations.add< eoDetSingleBitFlip<Bits> >(i); // mutate k bits without duplicates
}
/***** Selectors *****/
for(eoOperatorFoundry<eoSelectOne<Bits>>& ops :
{std::ref(foundry.crossover_selectors),
std::ref(foundry.mutation_selectors) }) {
ops.add< eoRandomSelect<Bits> >();
ops.add< eoStochTournamentSelect<Bits> >(0.5);
ops.add< eoSequentialSelect<Bits> >();
ops.add< eoProportionalSelect<Bits> >();
for(size_t i=2; i < 11; i+=4) {
ops.add< eoDetTournamentSelect<Bits> >(i);
}
}
foundry.aftercross_selectors.add< eoRandomSelect<Bits> >();
/***** Replacements ****/
foundry.replacements.add< eoPlusReplacement<Bits> >();
foundry.replacements.add< eoCommaReplacement<Bits> >();
foundry.replacements.add< eoSSGAWorseReplacement<Bits> >();
for(double i=0.51; i<0.92; i+=0.2) {
foundry.replacements.add< eoSSGAStochTournamentReplacement<Bits> >(i);
}
for(size_t i=2; i < 11; i+=2) {
foundry.replacements.add< eoSSGADetTournamentReplacement<Bits> >(i);
}
return foundry;
}
Bits::Fitness fake_func(const Bits&) { return 0; }
void print_param_range(const eoParam& param, const size_t slot_size, std::ostream& out = std::cout)
{
// If there is no choice to be made on this operator, comment it out.
if(slot_size - 1 <= 0) {
out << "# ";
}
// irace doesn't support "-" in names.
std::string irace_name = param.longName();
irace_name.erase(std::remove(irace_name.begin(), irace_name.end(), '-'), irace_name.end());
out << irace_name
<< "\t\"--" << param.longName() << "=\""
<< "\ti";
if(slot_size -1 <= 0) {
out << "\t(0)";
} else {
out << "\t(0," << slot_size-1 << ")";
}
out << std::endl;
}
int main(int argc, char* argv[])
{
/***** Global parameters. *****/
enum { NO_ERROR = 0, ERROR_USAGE = 100 };
eoFunctorStore store;
eoParser parser(argc, argv, "FastGA interface for iRace");
const size_t dimension = parser.getORcreateParam<size_t>(1000,
"dimension", "Dimension size",
'd', "Problem").value();
const size_t max_evals = parser.getORcreateParam<size_t>(2 * dimension,
"max-evals", "Maximum number of evaluations",
'e', "Stopping criterion").value();
const size_t buckets = parser.getORcreateParam<size_t>(100,
"buckets", "Number of buckets for discretizing the ECDF",
'b', "Performance estimation").value();
uint32_t seed =
parser.getORcreateParam<uint32_t>(0,
"seed", "Random number seed (0 = epoch)",
'S').value();
if(seed == 0) {
seed = time(0);
}
// rng is a global
rng.reseed(seed);
auto problem_p = parser.getORcreateParam<size_t>(0,
"problem", "Problem ID",
'p', "Problem", /*required=*/true);
const size_t problem = problem_p.value();
auto pop_size_p = parser.getORcreateParam<size_t>(1,
"pop-size", "Population size",
'P', "Operator Choice", /*required=*/false);
const size_t pop_size = pop_size_p.value();
auto instance_p = parser.getORcreateParam<size_t>(0,
"instance", "Instance ID",
'i', "Instance", /*required=*/false);
const size_t instance = instance_p.value();
auto continuator_p = parser.getORcreateParam<size_t>(0,
"continuator", "Stopping criterion",
'o', "Operator Choice", /*required=*/false); // Single alternative, not required.
const size_t continuator = continuator_p.value();
auto crossover_rate_p = parser.getORcreateParam<size_t>(0,
"crossover-rate", "",
'C', "Operator Choice", /*required=*/true);
const size_t crossover_rate = crossover_rate_p.value();
auto crossover_selector_p = parser.getORcreateParam<size_t>(0,
"cross-selector", "How to selects candidates for cross-over",
's', "Operator Choice", /*required=*/true);
const size_t crossover_selector = crossover_selector_p.value();
auto crossover_p = parser.getORcreateParam<size_t>(0,
"crossover", "",
'c', "Operator Choice", /*required=*/true);
const size_t crossover = crossover_p.value();
auto aftercross_selector_p = parser.getORcreateParam<size_t>(0,
"aftercross-selector", "How to selects between the two individuals altered by cross-over which one will mutate",
'a', "Operator Choice", /*required=*/false); // Single alternative, not required.
const size_t aftercross_selector = aftercross_selector_p.value();
auto mutation_rate_p = parser.getORcreateParam<size_t>(0,
"mutation-rate", "",
'M', "Operator Choice", /*required=*/true);
const size_t mutation_rate = mutation_rate_p.value();
auto mutation_selector_p = parser.getORcreateParam<size_t>(0,
"mut-selector", "How to selects candidate for mutation",
'u', "Operator Choice", /*required=*/true);
const size_t mutation_selector = mutation_selector_p.value();
auto mutation_p = parser.getORcreateParam<size_t>(0,
"mutation", "",
'm', "Operator Choice", /*required=*/true);
const size_t mutation = mutation_p.value();
auto replacement_p = parser.getORcreateParam<size_t>(0,
"replacement", "",
'r', "Operator Choice", /*required=*/true);
const size_t replacement = replacement_p.value();
auto offspring_size_p = parser.getORcreateParam<size_t>(0,
"offspring-size", "Offsprings size (0 = same size than the parents pop, see --pop-size)",
'O', "Operator Choice", /*required=*/false); // Single alternative, not required.
const size_t offspring_size = offspring_size_p.value();
// Help + Verbose routines
make_verbose(parser);
make_help(parser, /*exit_after*/false, std::clog);
if(parser.userNeedsHelp()) {
// Fake operators, just to be able to call make_foundry
// to get the configured operators slots.
eoEvalFuncPtr<Bits> fake_eval(fake_func);
eoUniformGenerator<int> fake_gen(0, 1);
eoInitFixedLength<Bits> fake_init(/*bitstring size=*/1, fake_gen);
auto fake_foundry = make_foundry(store, fake_init, fake_eval, max_evals, /*generations=*/ 1);
size_t n =
fake_foundry.crossover_rates.size()
* fake_foundry.crossover_selectors.size()
* fake_foundry.crossovers.size()
* fake_foundry.aftercross_selectors.size()
* fake_foundry.mutation_rates.size()
* fake_foundry.mutation_selectors.size()
* fake_foundry.mutations.size()
* fake_foundry.replacements.size()
* fake_foundry.continuators.size()
* fake_foundry.offspring_sizes.size();
std::clog << std::endl;
std::clog << n << " possible algorithms configurations." << std::endl;
std::clog << "Ranges of configurable parameters (redirect the stdout in a file to use it with iRace): " << std::endl;
// Do not print problem and instances, as they are managed separately by irace.
std::cout << "# name\tswitch\ttype\trange" << std::endl;
print_param_range( continuator_p, fake_foundry.continuators .size(), std::cout);
print_param_range( crossover_rate_p, fake_foundry.crossover_rates .size(), std::cout);
print_param_range( crossover_selector_p, fake_foundry.crossover_selectors .size(), std::cout);
print_param_range(aftercross_selector_p, fake_foundry.aftercross_selectors.size(), std::cout);
print_param_range( crossover_p, fake_foundry.crossovers .size(), std::cout);
print_param_range( mutation_rate_p, fake_foundry.mutation_rates .size(), std::cout);
print_param_range( mutation_selector_p, fake_foundry.mutation_selectors .size(), std::cout);
print_param_range( mutation_p, fake_foundry.mutations .size(), std::cout);
print_param_range( replacement_p, fake_foundry.replacements .size(), std::cout);
print_param_range( offspring_size_p, fake_foundry.offspring_sizes .size(), std::cout);
// std::ofstream irace_param("fastga.params");
// irace_param << "# name\tswitch\ttype\tvalues" << std::endl;
exit(NO_ERROR);
}
const size_t generations = static_cast<size_t>(std::floor(
static_cast<double>(max_evals) / static_cast<double>(pop_size)));
// const size_t generations = std::numeric_limits<size_t>::max();
eo::log << eo::debug << "Number of generations: " << generations << std::endl;
// Problem configuration code.
struct Problem {
double dummy;
size_t epistasis;
size_t neutrality;
size_t ruggedness;
size_t max_target;
};
std::map<size_t, Problem> problem_config_mapping {
{ 0, {0, 0, 1, 0, 1000}},
{ 1, {0, 0, 3, 0, 333}},
{ 2, {0, 0, 5, 0, 200}},
{ 3, {0, 2, 1, 0, 1000}},
{ 4, {0, 2, 3, 0, 333}},
{ 5, {0, 2, 3, 0, 200}},
{ 6, {0, 4, 1, 0, 1000}},
{ 7, {0, 4, 3, 0, 333}},
{ 8, {0, 4, 5, 0, 200}},
{ 9, {0.5, 0, 1, 0, 500}},
{10, {0.5, 0, 3, 0, 166}},
{11, {0.5, 0, 5, 0, 100}},
{12, {0.5, 2, 1, 0, 500}},
{13, {0.5, 2, 3, 0, 166}},
{14, {0.5, 2, 5, 0, 100}},
{15, {0.5, 4, 1, 0, 500}},
{16, {0.5, 4, 3, 0, 166}},
{17, {0.5, 4, 5, 0, 100}},
};
assert(0 <= problem and problem < problem_config_mapping.size());
/***** IOH logger *****/
auto max_target_para = problem_config_mapping[problem].max_target;
IOHprofiler_RangeLinear<size_t> target_range(0, max_target_para, buckets);
IOHprofiler_RangeLinear<size_t> budget_range(0, max_evals, buckets);
IOHprofiler_ecdf_logger<int, size_t, size_t> logger(
target_range, budget_range,
/*use_known_optimum*/false);
logger.set_complete_flag(true);
logger.set_interval(0);
logger.activate_logger();
/***** IOH problem *****/
double w_model_suite_dummy_para = problem_config_mapping[problem].dummy;
int w_model_suite_epitasis_para = problem_config_mapping[problem].epistasis;
int w_model_suite_neutrality_para = problem_config_mapping[problem].neutrality;
int w_model_suite_ruggedness_para = problem_config_mapping[problem].ruggedness;
W_Model_OneMax w_model_om;
std::string problem_name = "OneMax";
problem_name = problem_name
+ "_D" + std::to_string((int)(w_model_suite_dummy_para * dimension))
+ "_E" + std::to_string(w_model_suite_epitasis_para)
+ "_N" + std::to_string(w_model_suite_neutrality_para)
+ "_R" + std::to_string(w_model_suite_ruggedness_para);
/// This must be called to configure the w-model to be tested.
w_model_om.set_w_setting(w_model_suite_dummy_para,w_model_suite_epitasis_para,
w_model_suite_neutrality_para,w_model_suite_ruggedness_para);
/// Set problem_name based on the configuration.
w_model_om.IOHprofiler_set_problem_name(problem_name);
/// Set problem_id as 1
w_model_om.IOHprofiler_set_problem_id(problem); // FIXME check what that means
// w_model_om.IOHprofiler_set_instance_id(instance); // FIXME changing the instance seems to change the target upper bound.
/// Set dimension.
w_model_om.IOHprofiler_set_number_of_variables(dimension);
/***** Bindings *****/
logger.track_problem(w_model_om);
eoEvalIOHproblem<Bits> onemax_pb(w_model_om, logger);
// eoEvalPrint<Bits> eval_print(onemax_pb, std::clog, "\n");
eoEvalFuncCounter<Bits> eval_count(onemax_pb);
eoPopLoopEval<Bits> onemax_eval(eval_count);
/***** Instanciate and run the algo *****/
eoBooleanGenerator<int> bgen;
eoInitFixedLength<Bits> onemax_init(/*bitstring size=*/dimension, bgen);
auto& foundry = make_foundry(store, onemax_init, eval_count, max_evals - pop_size, generations);
Ints encoded_algo(foundry.size());
encoded_algo[foundry.crossover_rates .index()] = crossover_rate;
encoded_algo[foundry.crossover_selectors .index()] = crossover_selector;
encoded_algo[foundry.crossovers .index()] = crossover;
encoded_algo[foundry.aftercross_selectors.index()] = aftercross_selector;
encoded_algo[foundry.mutation_rates .index()] = mutation_rate;
encoded_algo[foundry.mutation_selectors .index()] = mutation_selector;
encoded_algo[foundry.mutations .index()] = mutation;
encoded_algo[foundry.replacements .index()] = replacement;
encoded_algo[foundry.continuators .index()] = continuator;
encoded_algo[foundry.offspring_sizes .index()] = offspring_size;
std::clog << "Encoded algorithm:" << std::endl;
foundry.select(encoded_algo);
std::clog << foundry.name() << std::endl;
// // Evaluation of a forged encoded_algo on the sub-problem
// eoEvalFoundryFastGA<Ints, Bits> eval_foundry(
// foundry, pop_size,
// onemax_init, onemax_eval,
// /*penalization=*/ dimension, // Worst case penalization.
// /*normalized=*/ false); // Use direct integer encoding.
//
// // Actually instanciate and run the algorithm.
// eval_foundry(encoded_algo);
eoPop<Bits> pop;
pop.append(pop_size, onemax_init);
onemax_eval(pop,pop);
foundry(pop); // Actually run the selected algorithm.
/***** IOH perf stats *****/
IOHprofiler_ecdf_sum ecdf_sum;
// iRace expects minimization
long perf = ecdf_sum(logger.data());
// assert(0 < perf and perf <= buckets*buckets);
if(perf <= 0 or buckets*buckets < perf) {
std::cerr << "WARNING: illogical performance: " << perf
<< ", check the bounds or the algorithm." << std::endl;
}
// std::clog << "After " << eval_count.getValue() << " / " << max_evals << " evaluations" << std::endl;
// Output
std::cout << -1 * perf << std::endl;
}

View file

@ -0,0 +1,87 @@
#!/bin/bash
###############################################################################
# This script is the command that is executed every run.
# Check the examples in examples/
#
# This script is run in the execution directory (execDir, --exec-dir).
#
# PARAMETERS:
# $1 is the candidate configuration number
# $2 is the instance ID
# $3 is the seed
# $4 is the instance name
# The rest ($* after `shift 4') are parameters to the run
#
# RETURN VALUE:
# This script should print one numerical value: the cost that must be minimized.
# Exit with 0 if no error, with 1 in case of error
###############################################################################
error() {
echo "`TZ=UTC date`: $0: error: $@"
exit 1
}
EXE="/home/aaziz-alaoui/Documents/GitHub/paradiseo/eo/contrib/irace/irace-algo-search/bin/fastga"
FIXED_PARAMS=""
CONFIG_ID=$1
INSTANCE_ID=$2
SEED=$3
INSTANCE=$4
CROSSOVER_RATE=$5
CROSSOVER_SELECTOR=$6
CROSSOVER=$7
MUTATION_RATE=$8
MUT_SELECTOR=$9
MUTATION=${10}
REPLACEMENT=${11}
shift 11 || error "Not enough parameters"
CONFIG_PARAMS=$*
STDOUT=c${CONFIG_ID}-${INSTANCE_ID}-${SEED}.stdout
STDERR=c${CONFIG_ID}-${INSTANCE_ID}-${SEED}.stderr
if [ ! -x "${EXE}" ]; then
error "${EXE}: not found or not executable (pwd: $(pwd))"
fi
# If the program just prints a number, we can use 'exec' to avoid
# creating another process, but there can be no other commands after exec.
#exec $EXE ${FIXED_PARAMS} -i $INSTANCE ${CONFIG_PARAMS}
# exit 1
#
# Otherwise, save the output to a file, and parse the result from it.
# (If you wish to ignore segmentation faults you can use '{}' around
# the command.)
$EXE ${FIXED_PARAMS} --instance=$INSTANCE --seed=${SEED} --crossover-rate=${CROSSOVER_RATE} --cross-selector=${CROSSOVER_SELECTOR} --crossover=${CROSSOVER} --mutation-rate=${MUTATION_RATE} --mut-selector=${MUT_SELECTOR} --mutation=${MUTATION} --replacement=${REPLACEMENT} 1> ${STDOUT} 2> ${STDERR}
#echo ${cmd}
# --instance=$INSTANCE --seed=$SEED
# remplacer config param par la même config que seed et instance id
# This may be used to introduce a delay if there are filesystem
# issues.
#SLEEPTIME=1
#while [ ! -s "${STDOUT}" ]; do
# sleep $SLEEPTIME
# let "SLEEPTIME += 1"
#done
# This is an example of reading a number from the output.
# It assumes that the objective value is the first number in
# the first column of the last line of the output.
if [ -s "${STDOUT}" ]; then
COST=$(tail -n 1 ${STDOUT} | grep -e '^[[:space:]]*[+-]\?[0-9]' | cut -f1)
echo "$COST"
rm -f "${STDOUT}" "${STDERR}"
exit 0
else
error "${STDOUT}: No such file or directory"
fi

View file

@ -0,0 +1,48 @@
## This is an example of specifying instances with a file.
# Each line is an instance relative to trainInstancesDir
# (see scenario.txt.tmpl) and an optional sequence of instance-specific
# parameters that will be passed to target-runnerx when invoked on that
# instance.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

View file

@ -0,0 +1,227 @@
###################################################### -*- mode: r -*- #####
## Scenario setup for Iterated Race (irace).
############################################################################
## To use the default value of a parameter of iRace, simply do not set
## the parameter (comment it out in this file, and do not give any
## value on the command line).
## File that contains the description of the parameters of the target
## algorithm.
parameterFile = "./fastga.param"
## Directory where the programs will be run.
execDir = "."
## File to save tuning results as an R dataset, either absolute path or
## relative to execDir.
# logFile = "./irace.Rdata"
## Previously saved log file to recover the execution of irace, either
## absolute path or relative to the current directory. If empty or NULL,
## recovery is not performed.
# recoveryFile = ""
## Directory where training instances are located; either absolute path or
## relative to current directory. If no trainInstancesFiles is provided,
## all the files in trainInstancesDir will be listed as instances.
trainInstancesDir = "."
## File that contains a list of training instances and optionally
## additional parameters for them. If trainInstancesDir is provided, irace
## will search for the files in this folder.
trainInstancesFile = "./default.instances"
## File that contains a table of initial configurations. If empty or NULL,
## all initial configurations are randomly generated.
# configurationsFile = ""
## File that contains a list of logical expressions that cannot be TRUE
## for any evaluated configuration. If empty or NULL, do not use forbidden
## expressions.
# forbiddenFile = ""
## Script called for each configuration that executes the target algorithm
## to be tuned. See templates.
targetRunner = "./target-runner"
## Number of times to retry a call to targetRunner if the call failed.
# targetRunnerRetries = 0
## Optional data passed to targetRunner. This is ignored by the default
## targetRunner function, but it may be used by custom targetRunner
## functions to pass persistent data around.
# targetRunnerData = ""
## Optional R function to provide custom parallelization of targetRunner.
# targetRunnerParallel = ""
## Optional script or R function that provides a numeric value for each
## configuration. See templates/target-evaluator.tmpl
# targetEvaluator = ""
## Maximum number of runs (invocations of targetRunner) that will be
## performed. It determines the maximum budget of experiments for the
## tuning.
maxExperiments = 2000
## Maximum total execution time in seconds for the executions of
## targetRunner. targetRunner must return two values: cost and time.
# maxTime = 60
## Fraction (smaller than 1) of the budget used to estimate the mean
## computation time of a configuration. Only used when maxTime > 0
# budgetEstimation = 0.02
## Maximum number of decimal places that are significant for numerical
## (real) parameters.
digits = 2
## Debug level of the output of irace. Set this to 0 to silence all debug
## messages. Higher values provide more verbose debug messages.
# debugLevel = 0
## Number of iterations.
# nbIterations = 0
## Number of runs of the target algorithm per iteration.
# nbExperimentsPerIteration = 0
## Randomly sample the training instances or use them in the order given.
# sampleInstances = 1
## Statistical test used for elimination. Default test is always F-test
## unless capping is enabled, in which case the default test is t-test.
## Valid values are: F-test (Friedman test), t-test (pairwise t-tests with
## no correction), t-test-bonferroni (t-test with Bonferroni's correction
## for multiple comparisons), t-test-holm (t-test with Holm's correction
## for multiple comparisons).
# testType = "F-test"
## Number of instances evaluated before the first elimination test. It
## must be a multiple of eachTest.
# firstTest = 5
## Number of instances evaluated between elimination tests.
# eachTest = 1
## Minimum number of configurations needed to continue the execution of
## each race (iteration).
# minNbSurvival = 0
## Number of configurations to be sampled and evaluated at each iteration.
# nbConfigurations = 0
## Parameter used to define the number of configurations sampled and
## evaluated at each iteration.
# mu = 5
## Confidence level for the elimination test.
# confidence = 0.95
## If the target algorithm is deterministic, configurations will be
## evaluated only once per instance.
# deterministic = 0
## Seed of the random number generator (by default, generate a random
## seed).
# seed = NA
## Number of calls to targetRunner to execute in parallel. Values 0 or 1
## mean no parallelization.
# parallel = 0
## Enable/disable load-balancing when executing experiments in parallel.
## Load-balancing makes better use of computing resources, but increases
## communication overhead. If this overhead is large, disabling
## load-balancing may be faster.
# loadBalancing = 1
## Enable/disable MPI. Use Rmpi to execute targetRunner in parallel
## (parameter parallel is the number of slaves).
# mpi = 0
## Specify how irace waits for jobs to finish when targetRunner submits
## jobs to a batch cluster: sge, pbs, torque or slurm. targetRunner must
## submit jobs to the cluster using, for example, qsub.
# batchmode = 0
## Enable/disable the soft restart strategy that avoids premature
## convergence of the probabilistic model.
# softRestart = 1
## Soft restart threshold value for numerical parameters. If NA, NULL or
## "", it is computed as 10^-digits.
# softRestartThreshold = ""
## Directory where testing instances are located, either absolute or
## relative to current directory.
# testInstancesDir = ""
## File containing a list of test instances and optionally additional
## parameters for them.
# testInstancesFile = ""
## Number of elite configurations returned by irace that will be tested if
## test instances are provided.
# testNbElites = 1
## Enable/disable testing the elite configurations found at each
## iteration.
# testIterationElites = 0
## Enable/disable elitist irace.
# elitist = 1
## Number of instances added to the execution list before previous
## instances in elitist irace.
# elitistNewInstances = 1
## In elitist irace, maximum number per race of elimination tests that do
## not eliminate a configuration. Use 0 for no limit.
# elitistLimit = 2
## User-defined R function that takes a configuration generated by irace
## and repairs it.
# repairConfiguration = ""
## Enable the use of adaptive capping, a technique designed for minimizing
## the computation time of configurations. This is only available when
## elitist is active.
# capping = 0
## Measure used to obtain the execution bound from the performance of the
## elite configurations: median, mean, worst, best.
# cappingType = "median"
## Method to calculate the mean performance of elite configurations:
## candidate or instance.
# boundType = "candidate"
## Maximum execution bound for targetRunner. It must be specified when
## capping is enabled.
# boundMax = 0
## Precision used for calculating the execution time. It must be specified
## when capping is enabled.
# boundDigits = 0
## Penalization constant for timed out executions (executions that reach
## boundMax execution time).
# boundPar = 1
## Replace the configuration cost of bounded executions with boundMax.
# boundAsTimeout = 1
## Percentage of the configuration budget used to perform a postselection
## race of the best configurations of each iteration after the execution
## of irace.
# postselection = 0
## Enable/disable AClib mode. This option enables compatibility with
## GenericWrapper4AC as targetRunner script.
# aclib = 0
## END of scenario file
############################################################################

View file

@ -0,0 +1,87 @@
#!/bin/bash
###############################################################################
# This script is the command that is executed every run.
# Check the examples in examples/
#
# This script is run in the execution directory (execDir, --exec-dir).
#
# PARAMETERS:
# $1 is the candidate configuration number
# $2 is the instance ID
# $3 is the seed
# $4 is the instance name
# The rest ($* after `shift 4') are parameters to the run
#
# RETURN VALUE:
# This script should print one numerical value: the cost that must be minimized.
# Exit with 0 if no error, with 1 in case of error
###############################################################################
error() {
echo "`TZ=UTC date`: $0: error: $@"
exit 1
}
EXE="./fastga"
LOG_DIR="irace_logs"
FIXED_PARAMS="--problem=0"
CONFIG_ID=$1
INSTANCE_ID=$2
SEED=$3
INSTANCE=$(echo $4 | sed 's/\//\n/g'|tail -n 1)
CROSSOVER_RATE=$5
CROSSOVER_SELECTOR=$6
CROSSOVER=$7
MUTATION_RATE=$8
MUT_SELECTOR=$9
MUTATION=${10}
REPLACEMENT=${11}
shift 11 || error "Not enough parameters"
INSTANCE_PARAMS=$*
# STDOUT=${LOG_DIR}/c${CONFIG_ID}_i${INSTANCE_ID}_s${SEED}.stdout
# STDERR=${LOG_DIR}/c${CONFIG_ID}_i${INSTANCE_ID}_s${SEED}.stderr
STDOUT="/dev/null"
STDERR="/dev/null"
if [ ! -x "${EXE}" ]; then
error "${EXE}: not found or not executable (pwd: $(pwd))"
fi
# If the program just prints a number, we can use 'exec' to avoid
# creating another process, but there can be no other commands after exec.
#exec $EXE ${FIXED_PARAMS} -i $INSTANCE ${INSTANCE_PARAMS}
# exit 1
#
# Otherwise, save the output to a file, and parse the result from it.
# (If you wish to ignore segmentation faults you can use '{}' around
# the command.)
cmd="$EXE ${FIXED_PARAMS} --instance=${INSTANCE} --seed=${SEED} ${CROSSOVER_RATE} ${CROSSOVER_SELECTOR} ${CROSSOVER} ${MUTATION_RATE} ${MUT_SELECTOR} ${MUTATION} ${REPLACEMENT}"
# NOTE: irace seems to capture both stderr and stdout, so you should not output to stderr
echo ${cmd} > ${STDERR}
$cmd 2> ${STDERR} | tee ${STDOUT}
# The following code is useless if the binary only output a single number on stdout.
# This may be used to introduce a delay if there are filesystem
# issues.
# SLEEPTIME=1
# while [ ! -s "${STDOUT}" ]; do
# sleep $SLEEPTIME
# let "SLEEPTIME += 1"
# done
# This is an example of reading a number from the output.
# It assumes that the objective value is the first number in
# the first column of the last line of the output.
# if [ -s "${STDOUT}" ]; then
# COST=$(tail -n 1 ${STDOUT} | grep -e '^[[:space:]]*[+-]\?[0-9]' | cut -f1)
# echo "$COST"
# rm -f "${STDOUT}" "${STDERR}"
# exit 0
# else
# error "${STDOUT}: No such file or directory"
# fi

19
eo/contrib/irace/run_irace.sh Executable file
View file

@ -0,0 +1,19 @@
#!/bin/bash
if [[ $# != 1 ]] ; then
echo "ERROR: build dir not indicated"
exit 1
fi
cd $1
pwd
# Fore some reason, irace absolutely need those files...
cp ../irace-config/example.scen .
cp ../irace-config/target-runner .
cp ../irace-config/default.instances .
# Generate the parameter list file.
./fastga -h > fastga.param 2>/dev/null
/usr/lib/R/site-library/irace/bin/irace --scenario example.scen 2>&1 | tee irace.log

View file

@ -85,6 +85,7 @@
#include "eoEvalKeepBest.h"
#include "eoEvalTimeThrowException.h"
#include "eoEvalUserTimeThrowException.h"
#include "eoEvalPrint.h"
// Continuators - all include eoContinue.h
#include "eoCombinedContinue.h"
@ -146,6 +147,7 @@
// Algorithms
#include "eoEasyEA.h"
#include "eoSGA.h"
#include "eoFastGA.h"
// #include "eoEvolutionStrategy.h" removed for a while - until eoGenOp is done
#include "eoAlgoReset.h"
#include "eoAlgoRestart.h"
@ -164,6 +166,7 @@
#include "eoAlgoFoundryEA.h"
#include "eoAlgoFoundryFastGA.h"
#include "eoEvalFoundryEA.h"
#include "eoEvalFoundryFastGA.h"
//-----------------------------------------------------------------------------
// to be continued ...

View file

@ -76,7 +76,7 @@ class eoOperatorFoundry : public eoForgeVector< Itf >
* In a second step, the operators to be used should be selected
* by indicating their index, just like if the foundry was an array:
* @code
* foundry = {0, 1, 2};
* foundry.select({0, 1, 2});
* // ^ ^ ^
* // | | |
* // | | + 3d operator

View file

@ -27,30 +27,30 @@
#include <tuple>
#include <limits>
/** A class that assemble an eoEasyEA on the fly, given a combination of available operators.
/** A class that assemble an eoFastGA on the fly, given a combination of available operators.
*
* The foundry should first be set up with sets of operators
* for the main modules of an EA:
* continuators, crossovers, mutations, selection and replacement operators.
* for the main modules of a FastGA:
* continuators, crossovers, mutations, selections, replacement operators, etc.
*
* This is done through public member variable's `add` method,
* which takes the class name as template and its constructor's parameters
* as arguments. For example:
* @code
* foundry.selectors.add< eoStochTournamentSelect<EOT> >( 0.5 );
* foundry.selectors.add< eoRandomSelect<EOT> >();
* @endcode
*
* @warning If the constructor takes a reference YOU SHOULD ABSOLUTELY wrap it
* in a `std::ref`, or it will silently be passed as a copy,
* which would effectively disable any link between operators.
* which would effectively disable any link with other operator(s).
*
* In a second step, the operators to be used should be selected
* by indicating their index, passing an array of eight elements:
* by indicating their index, passing an array of 10 elements:
* @code
* foundry.select({0, 1, 2, 3, 4, 5, 6, 7});
* foundry.select({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
* @endcode
*
* @note: by default, the firsts of the eight operators are selected.
* @note: by default, the firsts of the 10 operators are selected.
*
* If you don't (want to) recall the order of the operators in the encoding,
* you can use the `index()` member, for example:
@ -58,7 +58,7 @@
* foundry.at(foundry.continuators.index()) = 2; // select the third continuator
* @endcode
*
* Now, you can call the fourdry just like any eoAlgo, by passing it an eoPop:
* Now, you can call the foundry just like any eoAlgo, by passing it an eoPop:
* @code
* foundry(pop);
* @encode
@ -69,7 +69,7 @@
* Every instantiation is deferred upon actual use. That way, you can still reconfigure them
* at any time with `eoForgeOperator::setup`, for example:
* @code
* foundry.selector.at(0).setup(0.5); // using constructor's arguments
* foundry.selector.at(0).setup(0.5); // Will call constructor's arguments
* @endcode
*
* @ingroup Foundry
@ -82,16 +82,26 @@ class eoAlgoFoundryFastGA : public eoAlgoFoundry<EOT>
/** The constructon only take an eval, because all other operators
* are stored in the public containers.
*/
eoAlgoFoundryFastGA( eoInit<EOT> & init, eoEvalFunc<EOT>& eval, size_t max_evals = 10000, size_t max_restarts = std::numeric_limits<size_t>::max() ) :
eoAlgoFoundry<EOT>(8),
continuators(0, true), // Always re-instantiate continuators, because they hold a state.
crossover_rates(1, false),
eoAlgoFoundryFastGA(
eoInit<EOT> & init,
eoEvalFunc<EOT>& eval,
size_t max_evals = 10000,
size_t max_restarts = std::numeric_limits<size_t>::max()
) :
eoAlgoFoundry<EOT>(10),
crossover_rates(0, false),
crossover_selectors(1, false),
crossovers(2, false),
mutation_rates(3, false),
mutations(4, false),
selectors(5, false),
pop_sizes(6, false),
aftercross_selectors(3, false),
mutation_rates(4, false),
mutation_selectors(5, false),
mutations(6, false),
replacements(7, false),
continuators(8, true), // Always re-instantiate continuators, because they hold a state.
offspring_sizes(9, false),
_eval(eval),
_init(init),
_max_evals(max_evals),
@ -101,93 +111,89 @@ class eoAlgoFoundryFastGA : public eoAlgoFoundry<EOT>
public:
/* Operators containers @{ */
eoOperatorFoundry< eoContinue<EOT> > continuators;
eoOperatorFoundry< double > crossover_rates;
eoOperatorFoundry< eoSelectOne<EOT> > crossover_selectors;
eoOperatorFoundry< eoQuadOp<EOT> > crossovers;
eoOperatorFoundry< eoSelectOne<EOT> > aftercross_selectors;
eoOperatorFoundry< double > mutation_rates;
eoOperatorFoundry< eoSelectOne<EOT> > mutation_selectors;
eoOperatorFoundry< eoMonOp<EOT> > mutations;
eoOperatorFoundry< eoSelectOne<EOT> > selectors;
eoOperatorFoundry< size_t > pop_sizes;
eoOperatorFoundry< eoReplacement<EOT> > replacements;
eoOperatorFoundry< eoContinue<EOT> > continuators;
eoOperatorFoundry< size_t > offspring_sizes;
/* @} */
/** instantiate and call the pre-selected algorithm.
*/
void operator()(eoPop<EOT>& pop)
{
assert(continuators.size() > 0); assert(this->at(continuators.index()) < continuators.size());
assert( crossover_rates.size() > 0); assert(this->at( crossover_rates.index()) < crossover_rates.size());
assert( crossover_selectors.size() > 0); assert(this->at( crossover_selectors.index()) < crossover_selectors.size());
assert( crossovers.size() > 0); assert(this->at( crossovers.index()) < crossovers.size());
assert(aftercross_selectors.size() > 0); assert(this->at(aftercross_selectors.index()) < aftercross_selectors.size());
assert( mutation_rates.size() > 0); assert(this->at( mutation_rates.index()) < mutation_rates.size());
assert( mutation_selectors.size() > 0); assert(this->at( mutation_selectors.index()) < mutation_selectors.size());
assert( mutations.size() > 0); assert(this->at( mutations.index()) < mutations.size());
assert( selectors.size() > 0); assert(this->at( selectors.index()) < selectors.size());
assert( pop_sizes.size() > 0); assert(this->at( pop_sizes.index()) < pop_sizes.size());
assert( replacements.size() > 0); assert(this->at( replacements.index()) < replacements.size());
// Crossover or clone
double cross_rate = this->crossover_rate();
eoProportionalOp<EOT> cross;
// Cross-over that produce only one offspring,
// made by wrapping the quad op (which produce 2 offsprings)
// in a bin op (which ignore the second offspring).
eoQuad2BinOp<EOT> single_cross(this->crossover());
cross.add(single_cross, cross_rate);
eoBinCloneOp<EOT> cross_clone;
cross.add(cross_clone, 1 - cross_rate); // Clone
// Mutation or clone
double mut_rate = this->mutation_rate();
eoProportionalOp<EOT> mut;
mut.add(this->mutation(), mut_rate);
eoMonCloneOp<EOT> mut_clone;
mut.add(mut_clone, 1 - mut_rate); // FIXME TBC
// Apply mutation after cross-over.
eoSequentialOp<EOT> variator;
variator.add(cross,1.0);
variator.add(mut,1.0);
// All variatiors
double lambda = this->pop_size();
eoGeneralBreeder<EOT> breeder(this->selector(), variator, lambda, /*as rate*/false);
assert( continuators.size() > 0); assert(this->at( continuators.index()) < continuators.size());
assert( offspring_sizes.size() > 0); assert(this->at( offspring_sizes.index()) < offspring_sizes.size());
// Objective function calls counter
eoEvalCounterThrowException<EOT> eval(_eval, _max_evals);
eo::log << eo::xdebug << "Evaluations: " << eval.value() << " / " << _max_evals << std::endl;
eoPopLoopEval<EOT> pop_eval(eval);
// Algorithm itself
eoEasyEA<EOT> algo = eoEasyEA<EOT>(this->continuator(), pop_eval, breeder, this->replacement());
eoFastGA<EOT> algo(
this->crossover_rate(),
this->crossover_selector(),
this->crossover(),
this->aftercross_selector(),
this->mutation_rate(),
this->mutation_selector(),
this->mutation(),
pop_eval,
this->replacement(),
this->continuator(),
this->offspring_size()
);
// Restart wrapper
eoAlgoPopReset<EOT> reset_pop(_init, pop_eval);
eoGenContinue<EOT> restart_cont(_max_restarts);
eoAlgoRestart<EOT> restart(eval, algo, restart_cont, reset_pop);
// eoAlgoPopReset<EOT> reset_pop(_init, pop_eval);
// eoGenContinue<EOT> restart_cont(_max_restarts);
// eoAlgoRestart<EOT> restart(eval, algo, restart_cont, reset_pop);
try {
restart(pop);
// restart(pop);
algo(pop);
} catch(eoMaxEvalException e) {
#ifndef NDEBUG
eo::log << eo::debug << "Reached maximum evaluations: " << eval.getValue() << " / " << _max_evals << std::endl;
#endif
// In case some solutions were not evaluated when max eval occured.
eoPopLoopEval<EOT> pop_last_eval(_eval);
pop_last_eval(pop,pop);
// FIXME can this even be considered legal?
// eoPopLoopEval<EOT> pop_last_eval(_eval);
// pop_last_eval(pop,pop);
}
}
/** Return an approximate name of the selected algorithm.
*
* @note: does not take into account parameters of the operators,
* only show class names.
*/
std::string name()
{
std::ostringstream name;
name << this->at(continuators.index()) << " (" << this->continuator().className() << ") + ";
name << this->at(crossover_rates.index()) << " (" << this->crossover_rate().className() << ") + ";
name << this->at(crossovers.index()) << " (" << this->crossover().className() << ") + ";
name << this->at(mutation_rates.index()) << " (" << this->mutation_rate().className() << ") + ";
name << this->at(mutations.index()) << " (" << this->mutation().className() << ") + ";
name << this->at(selectors.index()) << " (" << this->selector().className() << ") + ";
name << this->at(pop_sizes.index()) << " (" << this->pop_size().className() << ")";
name << this->at(replacements.index()) << " (" << this->replacement().className() << ")";
name << "crossover_rates: " << this->at( crossover_rates.index()) << " (" << this-> crossover_rate() << ") + ";
name << "crossover_selectors: " << this->at( crossover_selectors.index()) << " (" << this-> crossover_selector().className() << ") + ";
name << "aftercross_selector: " << this->at(aftercross_selectors.index()) << " (" << this->aftercross_selector().className() << ") + ";
name << "crossovers: " << this->at( crossovers.index()) << " (" << this-> crossover().className() << ") + ";
name << "mutation_rates: " << this->at( mutation_rates.index()) << " (" << this-> mutation_rate() << ") + ";
name << "mutation_selectors: " << this->at( mutation_selectors.index()) << " (" << this-> mutation_selector().className() << ") + ";
name << "mutations: " << this->at( mutations.index()) << " (" << this-> mutation().className() << ") + ";
name << "replacements: " << this->at( replacements.index()) << " (" << this-> replacement().className() << ") + ";
name << "continuators: " << this->at( continuators.index()) << " (" << this-> continuator().className() << ") + ";
name << "offspring_sizes: " << this->at( offspring_sizes.index()) << " (" << this-> offspring_size() << ")";
return name.str();
}
@ -228,16 +234,28 @@ class eoAlgoFoundryFastGA : public eoAlgoFoundry<EOT>
return mutations.instantiate(this->at(mutations.index()));
}
eoSelectOne<EOT>& selector()
eoSelectOne<EOT>& crossover_selector()
{
assert(this->at(selectors.index()) < selectors.size());
return selectors.instantiate(this->at(selectors.index()));
assert(this->at(crossover_selectors.index()) < crossover_selectors.size());
return crossover_selectors.instantiate(this->at(crossover_selectors.index()));
}
size_t& pop_size()
eoSelectOne<EOT>& aftercross_selector()
{
assert(this->at(pop_sizes.index()) < pop_sizes.size());
return pop_sizes.instantiate(this->at(pop_sizes.index()));
assert(this->at(aftercross_selectors.index()) < aftercross_selectors.size());
return aftercross_selectors.instantiate(this->at(aftercross_selectors.index()));
}
eoSelectOne<EOT>& mutation_selector()
{
assert(this->at(mutation_selectors.index()) < mutation_selectors.size());
return mutation_selectors.instantiate(this->at(mutation_selectors.index()));
}
size_t& offspring_size()
{
assert(this->at(offspring_sizes.index()) < offspring_sizes.size());
return offspring_sizes.instantiate(this->at(offspring_sizes.index()));
}
eoReplacement<EOT>& replacement()

View file

@ -147,6 +147,9 @@ public:
virtual void operator()(eoPop<EOT> & pop)
{
do {
#ifndef NDEBUG
eo::log << eo::debug << "Restart" << std::endl;
#endif
_reseter(pop);
_algo(pop);
} while( _continue(pop) );

View file

@ -272,7 +272,7 @@ template<class EOT> class eoEasyEA: public eoAlgo<EOT>
replace(_pop, offspring); // after replace, the new pop. is in _pop
std::cout << _pop << std::endl;
// std::cout << _pop << std::endl;
if (pSize > _pop.size())
throw eoException("Population shrinking!");

View file

@ -64,20 +64,18 @@ public :
// bypass already evaluated individuals
if (eo.invalid()) {
// increment the value of the self parameter
// (eoEvalFuncCounter inherits from @see eoValueParam)
value()++;
// evaluate
this->eoEvalFuncCounter<EOT>::operator()(eo);
// No need to increment value(), it is done in the superclass.
// increment t
// if we have reached the maximum
if ( value() >= _threshold ) {
if ( this->value() >= _threshold ) {
// go back through the stack until catched
throw eoMaxEvalException(_threshold);
}
// evaluate
this->eoEvalFuncCounter<EOT>::operator()(eo);
} // if invalid
}

View file

@ -92,12 +92,19 @@ public:
*/
std::vector<size_t> decode( const EOT& sol ) const
{
// Denormalize
size_t cont = static_cast<size_t>(std::ceil( sol[i_cont] * _foundry.continuators.size() ));
size_t cros = static_cast<size_t>(std::ceil( sol[i_cros] * _foundry.crossovers .size() ));
size_t muta = static_cast<size_t>(std::ceil( sol[i_muta] * _foundry.mutations .size() ));
size_t sele = static_cast<size_t>(std::ceil( sol[i_sele] * _foundry.selectors .size() ));
size_t repl = static_cast<size_t>(std::ceil( sol[i_repl] * _foundry.replacements.size() ));
// // Denormalize
// size_t cont = static_cast<size_t>(std::ceil( sol[i_cont] * _foundry.continuators.size() ));
// size_t cros = static_cast<size_t>(std::ceil( sol[i_cros] * _foundry.crossovers .size() ));
// size_t muta = static_cast<size_t>(std::ceil( sol[i_muta] * _foundry.mutations .size() ));
// size_t sele = static_cast<size_t>(std::ceil( sol[i_sele] * _foundry.selectors .size() ));
// size_t repl = static_cast<size_t>(std::ceil( sol[i_repl] * _foundry.replacements.size() ));
// Direct encoding
size_t cont = static_cast<size_t>(std::ceil( sol[i_cont] ));
size_t cros = static_cast<size_t>(std::ceil( sol[i_cros] ));
size_t muta = static_cast<size_t>(std::ceil( sol[i_muta] ));
size_t sele = static_cast<size_t>(std::ceil( sol[i_sele] ));
size_t repl = static_cast<size_t>(std::ceil( sol[i_repl] ));
return {cont, cros, muta, sele, repl};
}

View file

@ -0,0 +1,224 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
© 2020 Thales group
Authors:
Johann Dreo <johann.dreo@thalesgroup.com>
*/
#ifndef _eoEvalFoundryFastGA_H_
#define _eoEvalFoundryFastGA_H_
#include "eoEvalFunc.h"
#include "eoAlgoFoundryFastGA.h"
#include "eoInit.h"
#include "eoPopEvalFunc.h"
/** Evaluate an algorithm assembled by an eoAlgoFoundryFastGA, encoded as a numeric vector.
*
* Allows to plug another search algorithm on top of an eoAlgoFoundryFastGA,
* so as to find the best configuration.
*
* The first template EOT is the encoding of the high-level algorithm selection problem,
* the second template SUB is the encoding of the low-level generic problem.
*
* @ingroup Evaluation
* @ingroup Foundry
*/
template<class EOT, class SUB>
class eoEvalFoundryFastGA : public eoEvalFunc<EOT>
{
public:
/** Takes the necessary parameters to perform a search on the sub-problem.
*
* @param foundry The set of algorithms among which to select.
* @param subpb_init An initilizer for sub-problem encoding.
* @param offspring_size Population size for the sub-problem solver.
* @param subpb_eval The sub-problem itself.
* @param penalization If any solution to the high-level algorithm selection problem is out of bounds, set it to this value.
*/
eoEvalFoundryFastGA(
eoAlgoFoundryFastGA<SUB>& foundry,
const size_t pop_size,
eoInit<SUB>& subpb_init,
eoPopEvalFunc<SUB>& subpb_eval,
const typename SUB::Fitness penalization,
const bool normalized = false
) :
_pop_size(pop_size),
_subpb_init(subpb_init),
_subpb_eval(subpb_eval),
_foundry(foundry),
_penalization(penalization),
_normalized(normalized),
i_crat(foundry.crossover_rates.index()),
i_crsl(foundry.crossover_selectors.index()),
i_cros(foundry.crossovers.index()),
i_afcr(foundry.aftercross_selectors.index()),
i_mrat(foundry.mutation_rates.index()),
i_musl(foundry.mutation_selectors.index()),
i_muta(foundry.mutations.index()),
i_repl(foundry.replacements.index()),
i_cont(foundry.continuators.index()),
i_offs(foundry.offspring_sizes.index())
{ }
protected:
const size_t i_crat;
const size_t i_crsl;
const size_t i_cros;
const size_t i_afcr;
const size_t i_mrat;
const size_t i_musl;
const size_t i_muta;
const size_t i_repl;
const size_t i_cont;
const size_t i_offs;
public:
/** Decode the high-level problem encoding as an array of indices.
*
* @note: If the EOT is an eoInt, this will be optimized out.
*
* May be useful for getting a solution back into an eoAlgoFoundryFastGA.
* @code
* foundry = eval.decode(pop.best_element());
* std::cout << foundry.name() << std::endl;
* auto& cont = foundry.continuator(); // Get the configured operator
* @encode
*/
std::vector<size_t> decode( const EOT& sol ) const
{
size_t crat;
size_t crsl;
size_t cros;
size_t afcr;
size_t mrat;
size_t musl;
size_t muta;
size_t repl;
size_t cont;
size_t offs;
if(_normalized) {
crat = static_cast<size_t>(std::ceil( sol[i_crat] * _foundry.crossover_rates.size() ));
crsl = static_cast<size_t>(std::ceil( sol[i_crsl] * _foundry.crossover_selectors.size() ));
cros = static_cast<size_t>(std::ceil( sol[i_cros] * _foundry.crossovers.size() ));
afcr = static_cast<size_t>(std::ceil( sol[i_afcr] * _foundry.aftercross_selectors.size() ));
mrat = static_cast<size_t>(std::ceil( sol[i_mrat] * _foundry.mutation_rates.size() ));
musl = static_cast<size_t>(std::ceil( sol[i_musl] * _foundry.mutation_selectors.size() ));
muta = static_cast<size_t>(std::ceil( sol[i_muta] * _foundry.mutations.size() ));
repl = static_cast<size_t>(std::ceil( sol[i_repl] * _foundry.replacements.size() ));
cont = static_cast<size_t>(std::ceil( sol[i_cont] * _foundry.continuators.size() ));
offs = static_cast<size_t>(std::ceil( sol[i_offs] * _foundry.offspring_sizes.size() ));
} else {
crat = static_cast<size_t>(std::ceil( sol[i_crat] ));
crsl = static_cast<size_t>(std::ceil( sol[i_crsl] ));
cros = static_cast<size_t>(std::ceil( sol[i_cros] ));
afcr = static_cast<size_t>(std::ceil( sol[i_afcr] ));
mrat = static_cast<size_t>(std::ceil( sol[i_mrat] ));
musl = static_cast<size_t>(std::ceil( sol[i_musl] ));
muta = static_cast<size_t>(std::ceil( sol[i_muta] ));
repl = static_cast<size_t>(std::ceil( sol[i_repl] ));
cont = static_cast<size_t>(std::ceil( sol[i_cont] ));
offs = static_cast<size_t>(std::ceil( sol[i_offs] ));
}
return {crat, crsl, cros, afcr, mrat, musl, muta, repl, cont, offs};
}
/** Perform a sub-problem search with the configuration encoded in the given solution
* and set its (high-level) fitness to the best (low-level) fitness found.
*
* You may want to overload this to perform multiple runs or solve multiple sub-problems.
*/
virtual void operator()(EOT& sol)
{
if(not sol.invalid()) {
return;
}
auto config = decode(sol);
double crat = config[i_crat];
double crsl = config[i_crsl];
double cros = config[i_cros];
double afcr = config[i_afcr];
double mrat = config[i_mrat];
double musl = config[i_musl];
double muta = config[i_muta];
double repl = config[i_repl];
double cont = config[i_cont];
double offs = config[i_offs];
if(
0 <= crat and crat < _foundry.crossover_rates.size()
and 0 <= crsl and crsl < _foundry.crossover_selectors.size()
and 0 <= cros and cros < _foundry.crossovers.size()
and 0 <= afcr and afcr < _foundry.aftercross_selectors.size()
and 0 <= mrat and mrat < _foundry.mutation_rates.size()
and 0 <= musl and musl < _foundry.mutation_selectors.size()
and 0 <= muta and muta < _foundry.mutations.size()
and 0 <= repl and repl < _foundry.replacements.size()
and 0 <= cont and cont < _foundry.continuators.size()
and 0 <= offs and offs < _foundry.offspring_sizes.size()
) {
_foundry.select(config);
// Reset pop
eoPop<SUB> pop;
pop.append( _pop_size, _subpb_init);
_subpb_eval(pop,pop);
// Actually perform a search
_foundry(pop);
sol.fitness( pop.best_element().fitness() );
} else {
eo::log << eo::warnings << "WARNING: encoded algo is out of bounds, penalize to: " << _penalization << std::endl;
sol.fitness( _penalization ); // penalization
}
}
protected:
const size_t _pop_size;
eoInit<SUB>& _subpb_init;
eoPopEvalFunc<SUB>& _subpb_eval;
eoAlgoFoundryFastGA<SUB>& _foundry;
const typename EOT::Fitness _penalization;
const bool _normalized;
};
/** Helper function to instanciate an eoEvalFoundryFastGA without having to indicate the template for the sub-problem encoding.
*
* The template is deduced from the constructor's parameters.
* Not sure it's more concise than a classical instanciation…
*/
template<class EOT, class SUB>
eoEvalFoundryFastGA<EOT,SUB>&
make_eoEvalFoundryFastGA(
eoInit<SUB>& subpb_init,
eoPopEvalFunc<SUB>& subpb_eval,
eoAlgoFoundryFastGA<SUB>& foundry,
const typename SUB::Fitness penalization,
const bool normalized = false )
{
return *(new eoEvalFoundryFastGA<EOT,SUB>(subpb_init, subpb_eval, foundry, penalization, normalized));
}
#endif // _eoEvalFoundryFastGA_H_

View file

@ -45,8 +45,9 @@ template<class EOT> class eoEvalFuncCounter : public eoEvalFunc<EOT>, public eoV
{
if (_eo.invalid())
{
value()++;
func(_eo);
value()++;
eo::log << eo::xdebug << "eoEvalFuncCounter: " << value() << std::endl;
}
}

23
eo/src/eoEvalPrint.h Normal file
View file

@ -0,0 +1,23 @@
template< class EOT>
class eoEvalPrint: public eoEvalFunc<EOT>
{
protected:
std::ostream& _out;
eoEvalFunc<EOT>& _eval;
std::string _sep;
public:
eoEvalPrint(eoEvalFunc<EOT>& eval, std::ostream& out=std::cout, std::string sep="\n") :
_out(out),
_eval(eval),
_sep(sep)
{}
void operator()( EOT& sol )
{
_eval(sol);
_out << sol << _sep;
}
};

159
eo/src/eoFastGA.h Normal file
View file

@ -0,0 +1,159 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _eoFastGA_H_
#define _eoFastGA_H_
/** The Fast Genetic Algorithm.
*
* @ingroup Algorithms
*/
template<class EOT>
class eoFastGA : public eoAlgo<EOT>
{
protected:
double _rate_crossover;
eoSelectOne<EOT>& _select_cross;
eoQuadOp<EOT>& _crossover;
eoSelectOne<EOT>& _select_aftercross;
double _rate_mutation;
eoSelectOne<EOT>& _select_mut;
eoMonOp<EOT>& _mutation;
eoPopEvalFunc<EOT>& _pop_eval;
eoReplacement<EOT>& _replace;
eoContinue<EOT>& _continuator;
double _offsprings_size;
public:
eoFastGA(
double rate_crossover,
eoSelectOne<EOT>& select_cross,
eoQuadOp<EOT>& crossover,
eoSelectOne<EOT>& select_aftercross,
double rate_mutation,
eoSelectOne<EOT>& select_mut,
eoMonOp<EOT>& mutation,
eoPopEvalFunc<EOT>& pop_eval,
eoReplacement<EOT>& replace,
eoContinue<EOT>& continuator,
double offsprings_size = 0
) :
_rate_crossover(rate_crossover),
_select_cross(select_cross),
_crossover(crossover),
_select_aftercross(select_aftercross),
_rate_mutation(rate_mutation),
_select_mut(select_mut),
_mutation(mutation),
_pop_eval(pop_eval),
_replace(replace),
_continuator(continuator),
_offsprings_size(offsprings_size)
{
}
void operator()(eoPop<EOT>& pop)
{
#ifndef NDEBUG
assert(pop.size() > 0);
for(auto sol : pop) {
assert(not sol.invalid());
}
#endif
// Set lambda to the pop size
// if it was not set up at construction.
if(_offsprings_size == 0) {
// eo::log << eo::debug << "Set offspring size to: " << pop.size() << std::endl;
_offsprings_size = pop.size();
}
do {
eoPop<EOT> offsprings;
for(size_t i=0; i < _offsprings_size; ++i) {
// eo::log << eo::xdebug << "\tOffspring #" << i << std::endl;
if(eo::rng.flip(_rate_crossover)) {
// eo::log << eo::xdebug << "\t\tDo crossover" << std::endl;
// Manual setup of eoSelectOne
// (usually they are setup in a
// wrapping eoSelect).
_select_cross.setup(pop);
// Copy of const ref solutions,
// because one alter them hereafter.
EOT sol1 = _select_cross(pop);
EOT sol2 = _select_cross(pop);
// If the operator returns true,
// solutions have been altered.
if(_crossover(sol1, sol2)) {
sol1.invalidate();
sol2.invalidate();
}
// Select one of the two solutions
// which have been crossed.
eoPop<EOT> crossed;
crossed.push_back(sol1);
crossed.push_back(sol2);
_select_aftercross.setup(crossed);
EOT sol3 = _select_aftercross(crossed);
// Additional mutation (X)OR the crossed/cloned solution.
if(eo::rng.flip(_rate_mutation)) {
// eo::log << eo::xdebug << "\t\tDo mutation" << std::endl;
if(_mutation(sol3)) {
sol3.invalidate();
}
}
offsprings.push_back(sol3);
} else { // If not crossing, always mutate.
// eo::log << eo::xdebug << "\t\tNo crossover, do mutation" << std::endl;
_select_mut.setup(pop);
EOT sol3 = _select_mut(pop);
if(_mutation(sol3)) {
sol3.invalidate();
}
offsprings.push_back(sol3);
}
}
assert(offsprings.size() == _offsprings_size);
_pop_eval(pop, offsprings);
_replace(pop, offsprings);
// eo::log << eo::xdebug << "\tEnd of generation" << std::endl;
} while(_continuator(pop));
#ifndef NDEBUG
assert(pop.size() > 0);
for(auto sol : pop) {
assert(not sol.invalid());
}
#endif
}
};
#endif // _eoFastGA_H_

View file

@ -36,7 +36,7 @@
*
* @ingroup Representations
*/
template <class FitT> class eoInt: public eoVector<FitT, int>
template <class FitT, class T = size_t> class eoInt: public eoVector<FitT, T>
{
public:
@ -45,14 +45,14 @@ template <class FitT> class eoInt: public eoVector<FitT, int>
* @param size Size of the std::vector
* @param value fill the vector with this value
*/
eoInt(unsigned size = 0, int value = 0) :
eoVector<FitT, int>(size, value)
eoInt(unsigned size = 0, T value = 0) :
eoVector<FitT, T>(size, value)
{}
/** Constructor copying from a vector (or an initialization list).
*/
eoInt(std::vector<int> vec) :
eoVector<FitT, int>(vec)
eoInt(std::vector<T> vec) :
eoVector<FitT, T>(vec)
{}
/// My class name.

View file

@ -34,6 +34,7 @@
#include "utils/eoRNG.h"
#include "utils/selectors.h"
#include "utils/eoLogger.h"
#include "eoSelectOne.h"
#include "eoPop.h"
@ -92,9 +93,9 @@ public:
typename FitVec::iterator result
= std::upper_bound(cumulative.begin(), cumulative.end(), fortune);
assert(fortune <= cumulative.back());
// assert(fortune <= cumulative.back());
if(result - cumulative.begin() == _pop.size()) {
if(result - cumulative.begin() >= _pop.size()) {
return _pop.back();
} else {
return _pop[result - cumulative.begin()];

Some files were not shown because too many files have changed in this diff Show more