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,12 +76,12 @@ 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};
* // ^ ^ ^
* // | | |
* // | | + 3d operator
* // | + 2d operator
* // + 1st operator
* foundry.select({0, 1, 2});
* // ^ ^ ^
* // | | |
* // | | + 3d operator
* // | + 2d operator
* // + 1st operator
* @endcode
*
* If you don't (want to) recall the order of the operators in the encoding,

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( crossovers.size() > 0); assert(this->at( crossovers.index()) < crossovers.size());
assert( mutation_rates.size() > 0); assert(this->at( mutation_rates.index()) < mutation_rates.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( 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( replacements.size() > 0); assert(this->at( replacements.index()) < replacements.size());
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()];

View file

@ -48,6 +48,9 @@ template <class EOT> class eoRandomSelect: public eoSelectOne<EOT>
{
return _pop[eo::rng.random(_pop.size())] ;
}
virtual std::string className() const {return "eoRandomSelect";}
};
/** eoBestSelect: a selection method that always return the best
@ -64,6 +67,8 @@ template <class EOT> class eoBestSelect: public eoSelectOne<EOT>
{
return _pop.best_element() ;
}
virtual std::string className() const {return "eoBestSelect";}
};
/** eoNoSelect: returns all individual in order WITHOUT USING FITNESS!!!
@ -86,6 +91,9 @@ template <class EOT> class eoNoSelect: public eoSelectOne<EOT>
current++;
return _pop[current-1] ;
}
virtual std::string className() const {return "eoNoSelect";}
private:
unsigned current;
};

View file

@ -112,9 +112,14 @@ comparing with less is the default behaviour.
// typedef eoScalarFitness<double, std::greater<double> > eoMinimizingFitness;
// #endif
using eoMaximizingFitness = eoScalarFitness<double, std::less<double> >;
using eoMinimizingFitness = eoScalarFitness<double, std::greater<double> >;
template<class T=double>
using eoMaximizingFitnessT = eoScalarFitness<T, std::less<T> >;
template<class T=double>
using eoMinimizingFitnessT = eoScalarFitness<T, std::greater<T> >;
using eoMaximizingFitness = eoMaximizingFitnessT<double>;
using eoMinimizingFitness = eoMinimizingFitnessT<double>;
template <class F, class Cmp>
std::ostream& operator<<(std::ostream& os, const eoScalarFitness<F, Cmp>& f)

View file

@ -110,10 +110,8 @@ class eoDetSingleBitFlip: public eoMonOp<Chrom>
* (Default) Constructor.
* @param _num_bit The number of bits to change
* default is one - equivalent to eoOneBitFlip then
*
* @note: use a reference for num_bit, thus you may change and recall without having to re-instantiate.
*/
eoDetSingleBitFlip(const unsigned& _num_bit = 1): num_bit(_num_bit) {}
eoDetSingleBitFlip(const unsigned _num_bit = 1): num_bit(_num_bit) {}
/// The class name.
virtual std::string className() const { return "eoDetSingleBitFlip"; }
@ -138,6 +136,7 @@ class eoDetSingleBitFlip: public eoMonOp<Chrom>
}
// Flip at first indices
assert(num_bit <= chrom.size());
for(unsigned i=0; i<num_bit; ++i) {
chrom[indices[i]] = !chrom[indices[i]];
}
@ -149,8 +148,13 @@ class eoDetSingleBitFlip: public eoMonOp<Chrom>
}
}
void number_bits(const unsigned _num_bit)
{
num_bit = _num_bit;
}
protected:
const unsigned& num_bit;
unsigned num_bit;
};

View file

@ -28,6 +28,8 @@ class eoStandardBitMutation : public eoMonOp<EOT>
return _bitflip(chrom);
}
virtual std::string className() const {return "eoStandardBitMutation";}
protected:
double _rate;
unsigned _nb;
@ -58,6 +60,8 @@ class eoUniformBitMutation : public eoMonOp<EOT>
return _bitflip(chrom);
}
virtual std::string className() const {return "eoUniformBitMutation";}
protected:
double _rate;
unsigned _nb;
@ -93,6 +97,8 @@ class eoConditionalBitMutation : public eoStandardBitMutation<EOT>
// thus one don't need to re-instantiate.
return this->_bitflip(chrom);
}
virtual std::string className() const {return "eoConditionalBitMutation";}
};
/** Shifted standard bit mutation with mutation rate p:
@ -125,6 +131,8 @@ class eoShiftedBitMutation : public eoStandardBitMutation<EOT>
// thus one don't need to re-instantiate.
return this->_bitflip(chrom);
}
virtual std::string className() const {return "eoShiftedBitMutation";}
};
/** Mutation which size is sample in a gaussian.
@ -163,6 +171,8 @@ class eoNormalBitMutation : public eoStandardBitMutation<EOT>
return this->_bitflip(chrom);
}
virtual std::string className() const {return "eoNormalBitMutation";}
protected:
double _variance;
};
@ -196,6 +206,8 @@ class eoFastBitMutation : public eoStandardBitMutation<EOT>
return this->_bitflip(chrom);
}
virtual std::string className() const {return "eoFastBitMutation";}
protected:
double powerlaw(unsigned n, double beta)

View file

@ -68,7 +68,7 @@ eoInit<EOT> & do_make_genotype(eoParser& _parser, eoState& _state, EOT, float _b
// Then we can built a bitstring random initializer
// based on boolean_generator class (see utils/rnd_generator.h)
eoBooleanGenerator * gen = new eoBooleanGenerator(_bias);
eoBooleanGenerator<bool> * gen = new eoBooleanGenerator<bool>(_bias);
_state.storeFunctor(gen);
eoInitFixedLength<EOT>* init = new eoInitFixedLength<EOT>(theSize, *gen);
// store in state

View file

@ -50,7 +50,7 @@
#include "eoGenCounter.h"
// and make_help - any better suggestion to include it?
void make_help(eoParser & _parser, bool exit_after = true);
void make_help(eoParser & _parser, bool exit_after = true, std::ostream& out = std::cout);
#endif // !_CHECKPOINTING_

View file

@ -115,15 +115,16 @@ inline bool eoUniformGenerator<bool>::operator()(void)
to easily generate random booleans with a specified bias
\ingroup bitstring
*/
class eoBooleanGenerator : public eoRndGenerator<bool>
template<class T=bool>
class eoBooleanGenerator : public eoRndGenerator<T>
{
public :
eoBooleanGenerator(float _bias = 0.5, eoRng& _rng = rng) : bias(_bias), gen(_rng) {}
public :
eoBooleanGenerator(float _bias = 0.5, eoRng& _rng = rng) : bias(_bias), gen(_rng) {}
bool operator()(void) { return gen.flip(bias); }
private :
float bias;
eoRng& gen;
T operator()(void) { return gen.flip(bias); }
private :
float bias;
eoRng& gen;
};
/**

View file

@ -44,7 +44,7 @@
* It is declared in all make_xxx.h files in representation-dependent dirs
* but it is NOT representation-dependent itself - that's why it's in utils
*/
void make_help(eoParser & _parser, bool exit_after)
void make_help(eoParser & _parser, bool exit_after, std::ostream& out)
{
// name of the "status" file where all actual parameter values will be saved
std::string str_status = _parser.ProgramName() + ".status"; // default value
@ -62,8 +62,8 @@ void make_help(eoParser & _parser, bool exit_after)
// i.e. in case you need parameters somewhere else, postpone these
if (_parser.userNeedsHelp())
{
_parser.printHelp(std::cout);
std::cout << "You can use an edited copy of file " << statusParam.value()
_parser.printHelp(out);
out << "You can use an edited copy of file " << statusParam.value()
<< " as parameter file" << std::endl;
if(exit_after) {
exit(0);

View file

@ -76,7 +76,10 @@ set (TEST_LIST
t-algo-forged
t-algo-forged-search
t-FastGA
t-eoFastGA
t-forge-FastGA
t-eoFoundryFastGA
t-eoAlgoFoundryFastGA
)

79
eo/test/t-FastGA.cpp Normal file
View file

@ -0,0 +1,79 @@
/*
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
*/
#include <iostream>
#include <string>
#include <eo>
#include <ga.h>
#include "../../problems/eval/oneMaxEval.h"
using EOT = eoBit<double>;
int main(int /*argc*/, char** /*argv*/)
{
size_t dim = 5;
size_t pop_size = 3;
oneMaxEval<EOT> evalfunc;
eoPopLoopEval<EOT> eval(evalfunc);
eoBooleanGenerator gen(0.5);
eoInitFixedLength<EOT> init(dim, gen);
double cross_rate = 0.5;
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).
eo1PtBitXover<EOT> crossover;
eoQuad2BinOp<EOT> mono_cross(crossover);
cross.add(mono_cross, cross_rate);
eoBinCloneOp<EOT> bin_clone;
cross.add(bin_clone, 1 - cross_rate); // Clone
double mut_rate = 0.5;
eoProportionalOp<EOT> mut;
eoShiftedBitMutation<EOT> mutation(0.5);
mut.add(mutation, mut_rate);
eoMonCloneOp<EOT> mon_clone;
mut.add(mon_clone, 1 - mut_rate); // FIXME TBC
eoSequentialOp<EOT> variator;
variator.add(cross,1.0);
variator.add(mut,1.0);
double lambda = 1.0; // i.e. 100%
eoStochTournamentSelect<EOT> selector(0.5);
eoGeneralBreeder<EOT> breeder(selector, variator, lambda);
eoGenContinue<EOT> common_cont(3);
eoCombinedContinue<EOT> gen_cont(common_cont);
//gen_cont.add(continuator);
eoPlusReplacement<EOT> replacement;
eoEasyEA<EOT> algo = eoEasyEA<EOT>(gen_cont, eval, breeder, replacement);
eoPop<EOT> pop;
pop.append(pop_size, init);
eval(pop,pop);
algo(pop);
std::cout << pop.best_element() << std::endl;
}

View file

@ -0,0 +1,147 @@
#include <iostream>
#include <string>
#include <eo>
#include <ga.h>
#include "../../problems/eval/oneMaxEval.h"
int main(int /*argc*/, char** /*argv*/)
{
size_t dim = 500;
size_t pop_size = 10;
eo::log << eo::setlevel(eo::warnings);
using EOT = eoBit<double>;
oneMaxEval<EOT> eval;
eoBooleanGenerator gen(0.5);
eoInitFixedLength<EOT> init(dim, gen);
eoAlgoFoundryFastGA<EOT> foundry(init, eval, pop_size*10);
/***** Variation rates *****/
for(double r = 0.0; r < 1.0; r+=0.1) {
foundry.crossover_rates.add<double>(r);
foundry. mutation_rates.add<double>(r);
}
/***** Crossovers ****/
foundry.crossovers.add< eo1PtBitXover<EOT> >();
foundry.crossovers.add< eoUBitXover<EOT> >(0.5); // preference over 1
for(size_t i=1; i < 11; i+=4) {
foundry.crossovers.add< eoNPtsBitXover<EOT> >(i); // nb of points
}
/***** Mutations ****/
foundry.mutations.add< eoBitMutation<EOT> >(0.01); // proba of flipping one bit
for(size_t i=1; i < 11; i+=4) {
foundry.mutations.add< eoDetBitFlip<EOT> >(i); // mutate k bits
}
/***** Selectors *****/
for(eoOperatorFoundry<eoSelectOne<EOT>>& ops :
{std::ref(foundry.crossover_selectors),
std::ref(foundry.aftercross_selectors),
std::ref(foundry.mutation_selectors) }) {
ops.add< eoRandomSelect<EOT> >();
ops.add< eoStochTournamentSelect<EOT> >(0.5);
ops.add< eoSequentialSelect<EOT> >();
ops.add< eoProportionalSelect<EOT> >();
for(size_t i=2; i < 10; i+=4) {
ops.add< eoDetTournamentSelect<EOT> >(i);
}
}
/***** Replacements ****/
foundry.replacements.add< eoCommaReplacement<EOT> >();
foundry.replacements.add< eoPlusReplacement<EOT> >();
foundry.replacements.add< eoSSGAWorseReplacement<EOT> >();
foundry.replacements.add< eoSSGAStochTournamentReplacement<EOT> >(0.51);
for(size_t i=2; i < 10; i+=4) {
foundry.replacements.add< eoSSGADetTournamentReplacement<EOT> >(i);
}
/***** Continuators ****/
for(size_t i=10; i < 30; i+=10 ) {
foundry.continuators.add< eoSteadyFitContinue<EOT> >(10,i);
}
/***** Offspring population size *****/
foundry.offspring_sizes.add<size_t>(0); // 0 = same as parent pop
// for(size_t s = pop_size; s < 2*pop_size; s+=pop_size/10) {
// foundry.offspring_sizes.add<size_t>(s);
// }
size_t n =
foundry.crossover_rates.size()
* foundry.crossover_selectors.size()
* foundry.crossovers.size()
* foundry.aftercross_selectors.size()
* foundry.mutation_rates.size()
* foundry.mutation_selectors.size()
* foundry.mutations.size()
* foundry.replacements.size()
* foundry.continuators.size()
* foundry.offspring_sizes.size();
std::clog << n << " possible algorithms instances." << std::endl;
EOT best_sol;
std::string best_algo = "";
size_t i=0;
for(size_t i_crossrate = 0; i_crossrate < foundry.crossover_rates.size(); ++i_crossrate ) {
for(size_t i_crossselect = 0; i_crossselect < foundry.crossover_selectors.size(); ++i_crossselect ) {
for(size_t i_cross = 0; i_cross < foundry.crossovers.size(); ++i_cross ) {
for(size_t i_aftercrosel = 0; i_aftercrosel < foundry.aftercross_selectors.size(); ++i_aftercrosel ) {
for(size_t i_mutrate = 0; i_mutrate < foundry.mutation_rates.size(); ++i_mutrate ) {
for(size_t i_mutselect = 0; i_mutselect < foundry.mutation_selectors.size(); ++i_mutselect ) {
for(size_t i_mut = 0; i_mut < foundry.mutations.size(); ++i_mut ) {
for(size_t i_rep = 0; i_rep < foundry.replacements.size(); ++i_rep ) {
for(size_t i_cont = 0; i_cont < foundry.continuators.size(); ++i_cont ) {
for(size_t i_pop = 0; i_pop < foundry.offspring_sizes.size(); ++i_pop ) {
std::clog << "\r" << i++ << "/" << n-1; std::clog.flush();
eoPop<EOT> pop;
pop.append(pop_size, init);
foundry.select({
i_crossrate,
i_crossselect,
i_cross,
i_aftercrosel,
i_mutrate,
i_mutselect,
i_mut,
i_rep,
i_cont,
i_pop
});
// Actually perform a search
foundry(pop);
if(best_sol.invalid()) {
best_sol = pop.best_element();
best_algo = foundry.name();
} else if(pop.best_element().fitness() > best_sol.fitness()) {
best_sol = pop.best_element();
best_algo = foundry.name();
}
}
}
}
}
}
}
}
}
}
}
std::cout << std::endl << "Best algo: " << best_algo << ", with " << best_sol << std::endl;
}

72
eo/test/t-eoFastGA.cpp Normal file
View file

@ -0,0 +1,72 @@
/*
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
*/
#include <iostream>
#include <string>
#include <eo>
#include <ga.h>
#include "../../problems/eval/oneMaxEval.h"
using EOT = eoBit<double>;
int main(int /*argc*/, char** /*argv*/)
{
size_t dim = 100;
size_t pop_size = 10;
oneMaxEval<EOT> evalfunc;
eoPopLoopEval<EOT> eval(evalfunc);
eoBooleanGenerator gen(0.5);
eoInitFixedLength<EOT> init(dim, gen);
double cross_rate = 0.5;
eoSequentialSelect<EOT> select_cross;
eoUBitXover<EOT> crossover;
eoRandomSelect<EOT> select_aftercross;
double mut_rate = 0.5;
eoSequentialSelect<EOT> select_mut;
eoStandardBitMutation<EOT> mutation(0.5);
eoPlusReplacement<EOT> replacement;
eoGenContinue<EOT> common_cont(dim*2);
eoCombinedContinue<EOT> gen_cont(common_cont);
eoFastGA<EOT> algo(
cross_rate,
select_cross,
crossover,
select_aftercross,
mut_rate,
select_mut,
mutation,
eval,
replacement,
common_cont
);
eoPop<EOT> pop;
pop.append(pop_size, init);
eval(pop,pop);
algo(pop);
std::cout << pop.best_element() << std::endl;
}

View file

@ -26,7 +26,7 @@ eoAlgoFoundryFastGA<Bits>& make_foundry(eoFunctorStore& store, eoInit<Bits>& ini
}
for(size_t i=5; i<100; i+=10) {
foundry.pop_sizes.add<size_t>(i);
foundry.offspring_sizes.add<size_t>(i);
}
/***** Crossovers ****/
@ -51,14 +51,24 @@ eoAlgoFoundryFastGA<Bits>& make_foundry(eoFunctorStore& store, eoInit<Bits>& ini
}
/***** Selectors *****/
foundry.selectors.add< eoRandomSelect<Bits> >();
foundry.selectors.add< eoSequentialSelect<Bits> >();
foundry.selectors.add< eoProportionalSelect<Bits> >();
for(size_t i=2; i < 10; i+=1) { // Tournament size.
foundry.selectors.add< eoDetTournamentSelect<Bits> >(i);
for(eoOperatorFoundry<eoSelectOne<Bits>>& ops :
{std::ref(foundry.crossover_selectors),
std::ref(foundry.aftercross_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 < 10; i+=4) {
ops.add< eoDetTournamentSelect<Bits> >(i);
}
}
for(double i=0.51; i<0.91; i+=0.1) { // Tournament size as perc of pop.
foundry.selectors.add< eoStochTournamentSelect<Bits> >(i);
/***** Variation rates *****/
for(double r = 0.0; r < 1.0; r+=0.1) {
foundry.crossover_rates.add<double>(r);
foundry. mutation_rates.add<double>(r);
}
/***** Replacements ****/
@ -88,8 +98,20 @@ int main(int /*argc*/, char** /*argv*/)
auto& foundry = make_foundry(store, init, onemax_eval);
size_t n = foundry.continuators.size() * foundry.crossovers.size() * foundry.mutations.size() * foundry.selectors.size() * foundry.replacements.size()* foundry.crossover_rates.size() * foundry.mutation_rates.size() * foundry.pop_sizes.size();
std::clog << n << " possible algorithms instances." << std::endl;
size_t n =
foundry.crossover_rates.size()
* foundry.crossover_selectors.size()
* foundry.crossovers.size()
* foundry.aftercross_selectors.size()
* foundry.mutation_rates.size()
* foundry.mutation_selectors.size()
* foundry.mutations.size()
* foundry.replacements.size()
* foundry.continuators.size()
* foundry.offspring_sizes.size();
std::clog << n << " possible algorithms instances." << std::endl;
eoPop<Bits> pop;
pop.append(5,init);

115
eo/test/t-forge-FastGA.cpp Normal file
View file

@ -0,0 +1,115 @@
#include <iostream>
#include <string>
#include <eo>
#include <ga.h>
#include "../../problems/eval/oneMaxEval.h"
int main(int /*argc*/, char** /*argv*/)
{
size_t dim = 500;
size_t pop_size = 10;
eo::log << eo::setlevel(eo::warnings);
using EOT = eoBit<double>;
oneMaxEval<EOT> eval;
eoBooleanGenerator gen(0.5);
eoInitFixedLength<EOT> init(dim, gen);
eoGenContinue<EOT> common_cont(100);
eoForgeVector< eoContinue<EOT> > continuators;
continuators.add< eoSteadyFitContinue<EOT> >(10,10);
continuators.add< eoGenContinue<EOT> >(100);
eoForgeVector< eoQuadOp<EOT> > crossovers;
crossovers.add< eo1PtBitXover<EOT> >();
crossovers.add< eoUBitXover<EOT> >(0.5); // preference over 1
crossovers.add< eoNPtsBitXover<EOT> >(2); // nb of points
eoForgeVector< eoMonOp<EOT> > mutations;
mutations.add< eoBitMutation<EOT> >(0.01); // proba of flipping one bit
mutations.add< eoDetBitFlip<EOT> >(1); // mutate k bits
eoForgeVector< eoSelectOne<EOT> > selectors;
selectors.add< eoDetTournamentSelect<EOT> >(pop_size/2);
selectors.add< eoStochTournamentSelect<EOT> >(0.5);
selectors.add< eoSequentialSelect<EOT> >();
selectors.add< eoProportionalSelect<EOT> >();
eoForgeVector< eoReplacement<EOT> > replacors;
replacors.add< eoCommaReplacement<EOT> >();
replacors.add< eoPlusReplacement<EOT> >();
replacors.add< eoSSGAWorseReplacement<EOT> >();
replacors.add< eoSSGADetTournamentReplacement<EOT> >(pop_size/2);
replacors.add< eoSSGAStochTournamentReplacement<EOT> >(0.51);
std::clog << continuators.size() * crossovers.size() * mutations.size() * selectors.size() * replacors.size()
<< " possible algorithms instances." << std::endl;
EOT best_sol;
std::string best_algo = "";
for(auto& forge_cont : continuators) {
auto& continuator = forge_cont->instantiate();
for(auto& forge_cross : crossovers) {
auto& crossover = forge_cross->instantiate();
for(auto& forge_mut : mutations ) {
auto& mutation = forge_mut->instantiate();
for(auto& forge_sel : selectors) {
auto& selector = forge_sel->instantiate();
for(auto& forge_rep : replacors) {
auto& replacor = forge_rep->instantiate();
std::ostringstream algo_name;
algo_name << continuator.className() << " + "
<< crossover.className() << " + "
<< mutation.className() << " + "
<< selector.className() << " + "
<< replacor.className();
std::clog << "ALGO: " << algo_name.str();
std::clog.flush();
eoSequentialOp<EOT> variator;
variator.add(crossover, 1.0);
variator.add(mutation, 1.0);
eoGeneralBreeder<EOT> breeder(selector, variator, 1.0);
eoCombinedContinue<EOT> gen_cont(common_cont);
gen_cont.add(continuator);
eoEasyEA<EOT> algo(gen_cont, eval, breeder, replacor);
eoPop<EOT> pop;
pop.append(pop_size, init);
::apply(eval,pop);
algo(pop);
std::clog << " = " << pop.best_element().fitness() << std::endl;
if(best_sol.invalid()) {
best_sol = pop.best_element();
best_algo = algo_name.str();
} else if(pop.best_element().fitness() > best_sol.fitness()) {
best_sol = pop.best_element();
best_algo = algo_name.str();
}
}
}
}
}
}
std::cout << "Best algo: " << best_algo << ", with " << best_sol << std::endl;
}

View file

@ -200,7 +200,7 @@ class eoEvalIOHsuiteSingleDim : public eoEvalFunc<EOT>
// Evaluate the performance of the encoded algo instance
// on a whole IOH suite benchmark.
typename IOHprofiler_suite<ScalarType>::Problem_ptr pb;
while(pb = _ioh_suite->get_next_problem()) {
while( (pb = _ioh_suite->get_next_problem()) ) {
// Consider a new problem.
_eval.problem(*pb); // Will call logger's target_problem.