The new feature onlymutga with new mutation and experiments

This commit is contained in:
Potalas 2022-01-05 10:37:21 +01:00
commit e5b5e8807d
7 changed files with 1339 additions and 0 deletions

View file

@ -73,3 +73,7 @@ add_executable(fastga fastga.cpp)
# target_link_libraries(fastga ${PARADISEO_LIBRARIES} ${IOH_LIBRARY} stdc++fs)
target_link_libraries(fastga ${PARADISEO_LIBRARIES} fmt)
add_executable(onlymutga onlymutga.cpp)
# target_link_libraries(onlymutga ${PARADISEO_LIBRARIES} ${IOH_LIBRARY} stdc++fs)
target_link_libraries(onlymutga ${PARADISEO_LIBRARIES} fmt)

View file

@ -0,0 +1,119 @@
#!/usr/bin/python
###############################################################################
# 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:
# argv[1] is the candidate configuration ID
# argv[2] is the instance ID
# argv[3] is the seed
# argv[4] is the instance name
# The rest (argv[5:]) 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
###############################################################################
import datetime
import os.path
import re
import subprocess
import sys
exe = "../../../../release/onlymutga"
problem = 19
pop_size = 1
offspring_size = 100
fixed_parameters = ["--problem", str(problem), "--crossover-rate", "0", "--mutation-rate", "1", "--pop-size", str(pop_size), " --offspring-size", str(offspring_size)]
if __name__=='__main__':
if len(sys.argv) < 5:
print("\nUsage: ./target-runner.py <configuration_id> <instance_id> <seed> <instance_path_name> <list of parameters>\n")
sys.exit(1)
# Get the parameters as command line arguments.
configuration_id = sys.argv[1]
instance_id = sys.argv[2]
seed = sys.argv[3]
instance = sys.argv[4]
slices_prop = sys.argv[5:]
#print(sys.argv)
exe = os.path.expanduser(exe)
cmd = [exe] + fixed_parameters + ["--instance", instance, "--seed", seed]
residual_prob = 1
cl_probs = []
residual_size = 1
cl_sizes = []
values = ""
sizes = ""
for i in range(len(slices_prop)):
cl_probs.append(residual_prob * float(slices_prop[i]))
cl_sizes.append(residual_size * (1-float(slices_prop[i])))
residual_prob -= cl_probs[-1]
residual_size -= cl_sizes[-1]
values += "%.2f,"%cl_probs[-1]
sizes += "%.2f,"%cl_sizes[-1]
cl_probs.append(residual_prob)
values += "%.2f"%cl_probs[-1]
sizes += "%.2f"%cl_sizes[-1]
cmd += ["--cl-probs", values, "--cl-sizes", sizes]
# Define the stdout and stderr files.
out_file = "c" + str(configuration_id) + "-" + str(instance_id) + str(seed) + ".stdout"
err_file = "c" + str(configuration_id) + "-" + str(instance_id) + str(seed) + ".stderr"
def target_runner_error(msg):
now = datetime.datetime.now()
print(str(now) + " error: " + msg)
sys.exit(1)
def check_executable(fpath):
fpath = os.path.expanduser(fpath)
if not os.path.isfile(fpath):
target_runner_error(str(fpath) + " not found")
if not os.access(fpath, os.X_OK):
target_runner_error(str(fpath) + " is not executable")
# This is an example of reading a number from the output.
def parse_output(out):
match = re.search(r'Best ([-+0-9.eE]+)', out.strip())
if match:
return match.group(1);
else:
return "No match"
check_executable (exe)
outf = open(out_file, "w")
errf = open(err_file, "w")
return_code = subprocess.call(cmd, stdout = outf, stderr = errf)
outf.close()
errf.close()
if return_code != 0:
target_runner_error("command returned code " + str(return_code))
if not os.path.isfile(out_file):
target_runner_error("output file " + out_file + " not found.")
cost = parse_output (open(out_file).read())
#print(cost)
print(open(out_file).read().strip())
os.remove(out_file)
os.remove(err_file)
sys.exit(0)

View file

@ -0,0 +1,267 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "04867792",
"metadata": {},
"source": [
"# Imports"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "435212a6",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import seaborn as sb\n",
"import matplotlib.pyplot as plt\n",
"from matplotlib.ticker import MaxNLocator\n",
"import matplotlib.animation\n",
"from math import sqrt, log, cos, sin, pi\n",
"import numpy as np\n",
"import os\n",
"import shutil\n",
"import re\n",
"from subprocess import call\n",
"sb.set_style(\"whitegrid\")\n",
"#sb.set_palette(\"cubehelix\")\n",
"sb.set_palette(\"husl\")\n",
"sb.set(font_scale=1) # crazy big\n",
"sb.set_style('whitegrid', {'legend.frameon':True})\n",
"myfontsize = 12\n",
"titlesize = 15\n",
"%matplotlib notebook"
]
},
{
"cell_type": "markdown",
"id": "d76bdf6b",
"metadata": {},
"source": [
"# Function to generate the scenario file for irace"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "d86a9ca8",
"metadata": {},
"outputs": [],
"source": [
"def scenario(filename=\"scenario.txt\", \n",
" parameterFile=\"parameters.txt\", \n",
" execDir=\".\", \n",
" logFile=\"./irace.Rdata\", \n",
" targetRunner = \"target-runner.py\", \n",
" maxExperiments = 100000,\n",
" digits = 2):\n",
" f = open(filename, \"w\")\n",
" f.write(\"parameterFile=\" + parameterFile +\"\\n\")\n",
" f.write(\"execDir=\" + execDir + \"\\n\")\n",
" f.write(\"logFile=\" + logFile + \"\\n\")\n",
" f.write(\"targetRunner=\" + targetRunner + \"\\n\")\n",
" f.write(\"maxExperiments=\" + maxExperiments + \"\\n\")\n",
" f.write(\"digits=\" + digits + \"\\n\")\n",
" f.close()"
]
},
{
"cell_type": "markdown",
"id": "1213321a",
"metadata": {},
"source": [
"# Function to generate the parameter file for irace"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "70d221c9",
"metadata": {},
"outputs": [],
"source": [
"# Generate the param file for irace with all configuarable parameters\n",
"def parameters(filename=\"parameters.txt\"):\n",
" f = open(\"parameters.txt\", \"w\")\n",
" f.write(\"# name\\tswitch\\ttype\\tvalues\\n\") # head of the param file\n",
" cl_nb_part = 10 # number of category for the custom categorial probabilistic law\n",
" for i in range(cl_nb_part-1): # minus 1 slice than the number of categories\n",
" f.write(\"slice_prob_%s\\t\\\"\\\"\\tr\\t(0,1)\\n\"%i) # percentage of the residual probability for the slice\n",
"\n",
" ######################################### NOT USED YET ##########################################\n",
" #for i in range(cl_nb_part-1): # minus 1 slice than the number of categories\n",
" # f.write(\"slice_size_%s\\t\\\"\\\"\\tr\\t(0,1)\\n\"%i) # percentage of the residual size for the slice\n",
" #################################################################################################\n",
" f.close()"
]
},
{
"cell_type": "markdown",
"id": "65fcb69d",
"metadata": {},
"source": [
"# Fonction to generate problem dedicated target-runner.py"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "a18ba251",
"metadata": {},
"outputs": [],
"source": [
"def target_runner(origin=\"irace-config/target-runner.py\", path=\"target-runner.py\", problem=1):\n",
" \n",
" generalTR = open(origin, \"r\")\n",
" dedicatedTR = open(path, \"w\")\n",
" for line in generalTR:\n",
" if re.search(\"problem = \", line, flags=0):\n",
" dedicatedTR.write(\"problem = \" + str(problem) + \"\\n\")\n",
" else:\n",
" dedicatedTR.write(line)\n",
" generalTR.close()\n",
" dedicatedTR.close()"
]
},
{
"cell_type": "markdown",
"id": "59421dee",
"metadata": {},
"source": [
"# Run script"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "38dfec96",
"metadata": {},
"outputs": [],
"source": [
"results_directory = \"results\"\n",
"irace_path = \"/Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library/irace/bin/irace\"\n",
"instances_file = \"instances.txt\"\n",
"scenario_file = \"scenario.txt\"\n",
"parameters_file = \"parameters.txt\"\n",
"target_runner_file = \"target-runner.py\"\n",
"\n",
"# create or clear the results directory\n",
"if not os.path.isdir(results_directory):\n",
" os.mkdir(results_directory)\n",
" \n",
"for pb in range(1,3): # for each problem\n",
" # create or clear a subdirectory for the problem\n",
" problem_directory = results_directory + \"/problem_%s\"%pb\n",
" if os.path.isdir(problem_directory):\n",
" shutil.rmtree(problem_directory)\n",
" os.mkdir(problem_directory)\n",
" \n",
" # generate a custom target runner file for the problem\n",
" target_runner(path = problem_directory + \"/\" + target_runner_file, problem = pb)\n",
"\n",
" # copy the config files for iraces\n",
" for filename in [instances_file, scenario_file, parameters_file, target_runner_file]:\n",
" src = r'irace-config/' + filename\n",
" dst = problem_directory + \"/\" + filename\n",
" shutil.copyfile(src, dst)\n",
" \n",
" # run irace for\n",
" cmd = [irace_path, \"--scenario\", problem_directory + \"/\" + scenario_file] #, \"&> irace.log\"\n",
" call(cmd)\n",
"#call(cmd)\n"
]
},
{
"cell_type": "code",
"execution_count": 59,
"id": "b707ff3b",
"metadata": {},
"outputs": [],
"source": [
"shutil.rmtree(\"results\")"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "460c588e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"-10"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"call([\"../../release/onlymutga\"])"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "eb234425",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'problem_1/default.instances'"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import shutil\n",
"import os\n",
"src = r'irace-config/default.instances'\n",
"dst = r'problem_1/default.instances'\n",
"shutil.copyfile(src, dst)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a62c411",
"metadata": {},
"outputs": [],
"source": [
"chmod u+x script.py\n",
"cp -a a b"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View file

@ -0,0 +1,12 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 14 12:16:17 2021
@author: labeiros
"""
import sys
print('Number of arguments:', len(sys.argv), 'arguments.')
print('Argument List:', str(sys.argv))

View file

@ -0,0 +1,119 @@
#!/usr/bin/python
###############################################################################
# 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:
# argv[1] is the candidate configuration ID
# argv[2] is the instance ID
# argv[3] is the seed
# argv[4] is the instance name
# The rest (argv[5:]) 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
###############################################################################
import datetime
import os.path
import re
import subprocess
import sys
exe = "../../../../release/onlymutga"
problem = blabla
pop_size = 1
offspring_size = 100
fixed_parameters = ["--problem", str(problem), "--crossover-rate", "0", "--mutation-rate", "1", "--pop-size", str(pop_size), " --offspring-size", str(offspring_size)]
if __name__=='__main__':
if len(sys.argv) < 5:
print("\nUsage: ./target-runner.py <configuration_id> <instance_id> <seed> <instance_path_name> <list of parameters>\n")
sys.exit(1)
# Get the parameters as command line arguments.
configuration_id = sys.argv[1]
instance_id = sys.argv[2]
seed = sys.argv[3]
instance = sys.argv[4]
slices_prop = sys.argv[5:]
#print(sys.argv)
exe = os.path.expanduser(exe)
cmd = [exe] + fixed_parameters + ["--instance", instance, "--seed", seed]
residual_prob = 1
cl_probs = []
residual_size = 1
cl_sizes = []
values = ""
sizes = ""
for i in range(len(slices_prop)):
cl_probs.append(residual_prob * float(slices_prop[i]))
cl_sizes.append(residual_size * (1-float(slices_prop[i])))
residual_prob -= cl_probs[-1]
residual_size -= cl_sizes[-1]
values += "%.2f,"%cl_probs[-1]
sizes += "%.2f,"%cl_sizes[-1]
cl_probs.append(residual_prob)
values += "%.2f"%cl_probs[-1]
sizes += "%.2f"%cl_sizes[-1]
cmd += ["--cl-probs", values, "--cl-sizes", sizes]
# Define the stdout and stderr files.
out_file = "c" + str(configuration_id) + "-" + str(instance_id) + str(seed) + ".stdout"
err_file = "c" + str(configuration_id) + "-" + str(instance_id) + str(seed) + ".stderr"
def target_runner_error(msg):
now = datetime.datetime.now()
print(str(now) + " error: " + msg)
sys.exit(1)
def check_executable(fpath):
fpath = os.path.expanduser(fpath)
if not os.path.isfile(fpath):
target_runner_error(str(fpath) + " not found")
if not os.access(fpath, os.X_OK):
target_runner_error(str(fpath) + " is not executable")
# This is an example of reading a number from the output.
def parse_output(out):
match = re.search(r'Best ([-+0-9.eE]+)', out.strip())
if match:
return match.group(1);
else:
return "No match"
check_executable (exe)
outf = open(out_file, "w")
errf = open(err_file, "w")
return_code = subprocess.call(cmd, stdout = outf, stderr = errf)
outf.close()
errf.close()
if return_code != 0:
target_runner_error("command returned code " + str(return_code))
if not os.path.isfile(out_file):
target_runner_error("output file " + out_file + " not found.")
cost = parse_output (open(out_file).read())
#print(cost)
print(open(out_file).read().strip())
os.remove(out_file)
os.remove(err_file)
sys.exit(0)

View file

@ -0,0 +1,770 @@
#include <filesystem>
#include <iostream>
#include <cstdlib>
#include <string>
#include <memory>
#include <eo>
#include <ga.h>
#include <utils/checkpointing>
#include <eoInt.h>
#include <problems/eval/eoEvalIOH.h>
#include <ioh.hpp>
/*****************************************************************************
* ParadisEO algorithmic grammar definition.
*****************************************************************************/
// 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,
const size_t max_evals,
const size_t generations,
const double optimum,
const size_t pop_size,
const size_t offspring_size,
std::vector<double> cl_sizes,
std::vector<double> cl_values
)
{
// FIXME using max_restarts>1 does not allow to honor max evals.
auto& foundry = store.pack< eoAlgoFoundryFastGA<Bits> >(init, eval, max_evals, /*max_restarts=*/1);
/***** Continuators ****/
auto& fitcont = store.pack< eoFitContinue<Bits> >(optimum);
auto& gencont = store.pack< eoGenContinue<Bits> >(generations);
auto combconts = std::make_shared< std::vector<eoContinue<Bits>*> >();
combconts->push_back( &fitcont );
combconts->push_back( &gencont );
foundry.continuators.add< eoCombinedContinue<Bits> >( *combconts );
// 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.setup(0,offspring_size); // 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> >(); // Same as NPts=1
/***** Mutations ****/
/* ######################## Removed by Alexis ######################## */
/*
double p = 1.0; // Probability of flipping each bit.
// proba of flipping k bits, k drawn in uniform distrib
foundry.mutations.add< eoUniformBitMutation<Bits> >(p);
// proba of flipping k bits, k drawn in binomial distrib
foundry.mutations.add< eoStandardBitMutation<Bits> >(p);
// proba of flipping k bits, k drawn in binomial distrib, minus zero
foundry.mutations.add< eoConditionalBitMutation<Bits> >(p);
// proba of flipping k bits, k drawn in binomial distrib, changing zeros to one
foundry.mutations.add< eoShiftedBitMutation<Bits> >(p);
// proba of flipping k bits, k drawn in normal distrib
foundry.mutations.add< eoNormalBitMutation<Bits> >(p);
// proba of flipping k bits, k drawn in powerlaw distrib
foundry.mutations.add< eoFastBitMutation<Bits> >(p);
for(size_t i=1; i < 11; i+=2) {
// mutate k bits without duplicates
foundry.mutations.add< eoDetSingleBitFlip<Bits> >(i);
}
*/
/* ######################## RbA END ######################## */
/* ######################## Add by Alexis ######################## */
foundry.mutations.add< eoBucketBitMutation<Bits> >(cl_sizes, cl_values);
/* ######################## AbA END ######################## */
/***** 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 ****/
/* ######################## Removed by Alexis ######################## */
/*
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);
}
*/
/* ######################## RbA END ######################## */
/* ######################## Add by Alexis ######################## */
//foundry.replacements.add< eoSSGADetTournamentReplacement<Bits> >(1);
foundry.replacements.add< eoCommaReplacement<Bits> >();
/* ######################## AbA END ######################## */
return foundry;
}
/*****************************************************************************
* irace helper functions.
*****************************************************************************/
Bits::Fitness fake_func(const Bits&) { return 0; }
void print_irace_categorical(const eoParam& param, const size_t slot_size, std::string type="c", 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() << "=\""
<< "\t" << type;
out << "\t(0";
for(size_t i=1; i<slot_size; ++i) {
out << "," << i;
}
out << ")" << std::endl;
}
template<class T>
void print_irace_ranged(const eoParam& param, const T min, const T max, std::string type="r", std::ostream& out = std::cout)
{
// If there is no choice to be made on this operator, comment it out.
if(max - min <= 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() << "=\""
<< "\t" << type;
if(max-min <= 0) {
out << "\t(?)";
} else {
out << "\t(" << min << "," << max << ")";
}
out << std::endl;
}
template<class ITF>
void print_irace_oper(const eoParam& param, const eoOperatorFoundry<ITF>& op_foundry, std::ostream& out = std::cout)
{
print_irace_categorical(param, op_foundry.size(), "c", out);
}
// FIXME generalize to any scalar type with enable_if
// template<class ITF>
void print_irace_param(
const eoParam& param,
// const eoParameterFoundry<typename std::enable_if< std::is_floating_point<ITF>::value >::type>& op_foundry,
const eoParameterFoundry<double>& op_foundry,
std::ostream& out)
{
print_irace_ranged(param, op_foundry.min(), op_foundry.max(), "r", out);
}
// template<class ITF>
void print_irace_param(
const eoParam& param,
// const eoParameterFoundry<typename std::enable_if< std::is_integral<ITF>::value >::type>& op_foundry,
const eoParameterFoundry<size_t>& op_foundry,
std::ostream& out)
{
print_irace_ranged(param, op_foundry.min(), op_foundry.max(), "i", out);
}
template<class ITF>
void print_irace(const eoParam& param, const eoOperatorFoundry<ITF>& op_foundry, std::ostream& out = std::cout)
{
print_irace_oper<ITF>(param, op_foundry, out);
}
template<class ITF>
void print_irace(const eoParam& param, const eoParameterFoundry<ITF>& op_foundry, std::ostream& out = std::cout)
{
print_irace_param/*<ITF>*/(param, op_foundry, out);
}
void print_irace(const eoParam& param, const size_t min, const size_t max, std::ostream& out = std::cout)
{
print_irace_ranged(param, min, max, "i", out);
}
void print_operator_typed(const eoFunctorBase& op, std::ostream& out)
{
out << op.className();
}
void print_operator_typed(const double& op, std::ostream& out)
{
out << op;
}
template<class ITF>
void print_operators(const eoParam& param, eoOperatorFoundry<ITF>& op_foundry, std::ostream& out = std::cout, std::string indent=" ")
{
out << indent << op_foundry.size() << " " << param.longName() << ":" << std::endl;
for(size_t i=0; i < op_foundry.size(); ++i) {
out << indent << indent << i << ": ";
auto& op = op_foundry.instantiate(i);
print_operator_typed(op, out);
out << std::endl;
}
}
template<class T>
void print_operators(const eoParam& param, T min, T max, std::ostream& out = std::cout, std::string indent=" ")
{
out << indent << "[" << min << "," << max << "] " << param.longName() << "." << std::endl;
}
template<class ITF>
void print_operators(const eoParam& param, eoParameterFoundry<ITF>& op_foundry, std::ostream& out = std::cout, std::string indent=" ")
{
print_operators(param, op_foundry.min(), op_foundry.max(), out, indent);
}
// Problem configuration.
struct Problem {
double dummy;
size_t epistasis;
size_t neutrality;
size_t ruggedness;
size_t max_target;
size_t dimension;
friend std::ostream& operator<<(std::ostream& os, const Problem& pb);
};
std::ostream& operator<<(std::ostream& os, const Problem& pb)
{
os << "u=" << pb.dummy << "_"
<< "e=" << pb.epistasis << "_"
<< "n=" << pb.neutrality << "_"
<< "r=" << pb.ruggedness << "_"
<< "t=" << pb.max_target << "_"
<< "d=" << pb.dimension;
return os;
}
/*****************************************************************************
* IOH problem adaptation.
*****************************************************************************/
class WModelFlat : public ioh::problem::wmodel::WModelOneMax
{
public:
WModelFlat(const int instance, const int n_variables,
const double dummy_para, const int epistasis_para, const int neutrality_para,
const int ruggedness_para)
: WModelOneMax(instance, n_variables, dummy_para, epistasis_para, neutrality_para, ruggedness_para)
{ }
protected:
double transform_objectives(const double y) override
{ // Disable objective function shift & scaling.
return y;
}
};
/*****************************************************************************
* Command line interface.
*****************************************************************************/
int main(int argc, char* argv[])
{
/***** Global parameters. *****/
enum { NO_ERROR = 0, ERROR_USAGE = 100 };
std::map<size_t, Problem> benchmark {
/* ┌ problem index in the map
* problem ID in IOH experimenter
* dummy
* epistasis
* neutrality
* ruggedness
* max target
* dimension (bitstring length) */
{ 0 /* 1*/, {0, 6, 2, 10, 10, 20 }},
{ 1 /* 2*/, {0, 6, 2, 18, 10, 20 }},
{ 2 /* 3*/, {0, 5, 1, 72, 16, 16 }},
{ 3 /* 4*/, {0, 9, 3, 72, 16, 48 }},
{ 4 /* 5*/, {0, 23, 1, 90, 25, 25 }},
{ 5 /* 6*/, {0, 2, 1, 397, 32, 32 }},
{ 6 /* 7*/, {0, 11, 4, 0, 32, 128 }},
{ 7 /* 8*/, {0, 14, 4, 0, 32, 128 }},
{ 8 /* 9*/, {0, 8, 4, 128, 32, 128 }},
{ 9 /*10*/, {0, 36, 1, 245, 50, 50 }},
{10 /*11*/, {0, 21, 2, 256, 50, 100 }},
{11 /*12*/, {0, 16, 3, 613, 50, 150 }},
{12 /*13*/, {0, 32, 2, 256, 64, 128 }},
{13 /*14*/, {0, 21, 3, 16, 64, 192 }},
{14 /*15*/, {0, 21, 3, 256, 64, 192 }},
{15 /*16*/, {0, 21, 3, 403, 64, 192 }},
{16 /*17*/, {0, 52, 4, 2, 64, 256 }},
{17 /*18*/, {0, 60, 1, 16, 75, 75 }},
{18 /*19*/, {0, 32, 2, 4, 75, 150 }},
{19 /*20?*/, {0, 0, 0, 0, 0, 64 }} // Add by Alexis
};
eoFunctorStore store;
eoParser parser(argc, argv, "OnlymutGA interface for iRace");
/***** Problem parameters *****/
auto problem_p = parser.getORcreateParam<size_t>(0,
"problem", "Problem ID",
'p', "Problem", /*required=*/true);
const size_t problem = problem_p.value();
assert(0 <= problem and problem < benchmark.size());
// const size_t dimension = parser.getORcreateParam<size_t>(1000,
// "dimension", "Dimension size",
// 'd', "Problem").value();
const size_t dimension = benchmark[problem].dimension;
auto instance_p = parser.getORcreateParam<size_t>(0,
"instance", "Instance ID",
'i', "Instance", /*required=*/false);
const size_t instance = instance_p.value();
const size_t max_evals = parser.getORcreateParam<size_t>(5 * dimension,
"max-evals", "Maximum number of evaluations (default: 5*dim, else the given value)",
'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();
/***** Generic options *****/
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);
bool full_log =
parser.getORcreateParam<bool>(0,
"full-log", "Log the full search in CSV files"/* (using the IOH profiler format)"*/,
'F').value();
bool output_mat =
parser.getORcreateParam<bool>(0,
"output-mat", "Output the aggregated attainment matrix instead of its scalar sum (fancy colormap on stderr, parsable CSV on stdout).",
'A').value();
/***** populations sizes *****/
auto pop_size_p = parser.getORcreateParam<size_t>(1,
"pop-size", "Population size",
'P', "Operator Choice", /*required=*/false); // Changed by Alexis: 5 -> 1
const size_t pop_size = pop_size_p.value();
const size_t pop_size_max = 10;
auto offspring_size_p = parser.getORcreateParam<size_t>(10,
"offspring-size", "Offsprings size (0 = same size than the parents pop, see --pop-size)",
'O', "Operator Choice", /*required=*/false); // Single alternative, not required. // Changed by Alexis: 0 -> 10
const size_t offspring_size = offspring_size_p.value();
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();
if(generations < 1) {
generations = 1;
}
/***** metric parameters *****/
auto crossover_rate_p = parser.getORcreateParam<double>(0,
"crossover-rate", "",
'C', "Operator Choice", /*required=*/false); // Changed by Alexis: 0.5 -> 0 | true -> false
const double crossover_rate = crossover_rate_p.value();
auto mutation_rate_p = parser.getORcreateParam<double>(1,
"mutation-rate", "",
'M', "Operator Choice", /*required=*/false); // Changed by Alexis: 0 -> 1 | true -> false
const double mutation_rate = mutation_rate_p.value();
/***** operators *****/
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_selector_p = parser.getORcreateParam<size_t>(0,
"cross-selector", "How to selects candidates for cross-over",
's', "Operator Choice", /*required=*/false); // Changed by Alexis: true -> false
const size_t crossover_selector = crossover_selector_p.value();
auto crossover_p = parser.getORcreateParam<size_t>(0,
"crossover", "",
'c', "Operator Choice", /*required=*/false); // Changed by Alexis: true -> false
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_selector_p = parser.getORcreateParam<size_t>(0,
"mut-selector", "How to selects candidate for mutation",
'u', "Operator Choice", /*required=*/false); // Changed by Alexis: true -> false
const size_t mutation_selector = mutation_selector_p.value();
auto mutation_p = parser.getORcreateParam<size_t>(0,
"mutation", "",
'm', "Operator Choice", /*required=*/false); // Changed by Alexis: true -> false
const size_t mutation = mutation_p.value();
auto replacement_p = parser.getORcreateParam<size_t>(0,
"replacement", "",
'r', "Operator Choice", /*required=*/false); // Changed by Alexis: true -> false
const size_t replacement = replacement_p.value();
/* ######################## Add by Alexis ######################## */
auto cl_values_p = parser.getORcreateParam<std::string>("0.8,0.2",
"cl-probs", "Probabilities of each part for the custom law (sum = 1)",
'y', "Operator Choice", false);
std::string cl_v = cl_values_p.value();
std::vector<double> cl_probs = std::vector<double>();
std::string sep = ",";
size_t pos = 0;
std::string token;
while ((pos = cl_v.find(sep)) != std::string::npos) {
token = cl_v.substr(0, pos);
cl_probs.push_back(std::stod(token));
cl_v.erase(0, pos + sep.length());
}
cl_probs.push_back(std::stod(cl_v));
auto cl_sizes_p = parser.getORcreateParam<std::string>("0.5,0.5",
"cl-sizes", "Proportion sizes of each part for the custom law (sum = 1)",
'x', "Operator Choice", false);
std::string cl_s = cl_sizes_p.value();
std::vector<double> cl_sizes = std::vector<double>();
pos = 0;
while ((pos = cl_s.find(sep)) != std::string::npos) {
token = cl_s.substr(0, pos);
cl_sizes.push_back(std::stod(token));
cl_s.erase(0, pos + sep.length());
}
cl_sizes.push_back(std::stod(cl_s));
/* ######################## AbA END ######################## */
// 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, 0, pop_size_max, offspring_size, cl_sizes, cl_probs);
std::clog << std::endl << "Available operators:" << std::endl;
print_operators( continuator_p, fake_foundry.continuators , std::clog);
print_operators( crossover_rate_p, fake_foundry.crossover_rates , std::clog);
print_operators( crossover_selector_p, fake_foundry.crossover_selectors , std::clog);
print_operators(aftercross_selector_p, fake_foundry.aftercross_selectors, std::clog);
print_operators( crossover_p, fake_foundry.crossovers , std::clog);
print_operators( mutation_rate_p, fake_foundry.mutation_rates , std::clog);
print_operators( mutation_selector_p, fake_foundry.mutation_selectors , std::clog);
print_operators( mutation_p, fake_foundry.mutations , std::clog);
print_operators( replacement_p, fake_foundry.replacements , std::clog);
print_operators( offspring_size_p, fake_foundry.offspring_sizes , std::clog);
print_operators( pop_size_p, (size_t)1, pop_size_max , std::clog);
/* ######################## Add by Alexis ######################## */
print_operators( cl_values_p, "(1)", "(0.01,...,0.99)" , std::clog);
print_operators( cl_sizes_p, "(1)", "(0.01,...,0.99)" , std::clog);
/* ######################## AbA END ######################## */
std::clog << std::endl;
// If we were to make a DoE sampling numeric parameters,
// we would use that many samples:
size_t fake_sample_size = 10;
std::clog << "With " << fake_sample_size << " samples for numeric parameters..." << std::endl;
size_t n =
fake_sample_size //crossover_rates
* fake_foundry.crossover_selectors.size()
* fake_foundry.crossovers.size()
* fake_foundry.aftercross_selectors.size()
* fake_sample_size //mutation_rates
* fake_foundry.mutation_selectors.size()
* fake_foundry.mutations.size()
* fake_foundry.replacements.size()
* fake_foundry.continuators.size()
* fake_sample_size //offspring_sizes
* fake_sample_size //pop_size
;
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;
/* ######################## Removed by Alexis ######################## */
/*
print_irace( continuator_p, fake_foundry.continuators , std::cout);
print_irace( crossover_rate_p, fake_foundry.crossover_rates , std::cout);
print_irace( crossover_selector_p, fake_foundry.crossover_selectors , std::cout);
print_irace(aftercross_selector_p, fake_foundry.aftercross_selectors, std::cout);
print_irace( crossover_p, fake_foundry.crossovers , std::cout);
print_irace( mutation_rate_p, fake_foundry.mutation_rates , std::cout);
print_irace( mutation_selector_p, fake_foundry.mutation_selectors , std::cout);
print_irace( mutation_p, fake_foundry.mutations , std::cout);
print_irace( replacement_p, fake_foundry.replacements , std::cout);
print_irace( offspring_size_p, fake_foundry.offspring_sizes , std::cout);
print_irace( pop_size_p, 1, pop_size_max , std::cout);
*/
/* ######################## RbA END ######################## */
//std::ofstream irace_param("fastga.params");
//irace_param << "# name\tswitch\ttype\tvalues" << std::endl;
exit(NO_ERROR);
}
eo::log << eo::debug << "Maximum number of evaluations: " << max_evals << std::endl;
eo::log << eo::debug << "Number of generations: " << generations << std::endl;
/*****************************************************************************
* IOH stuff.
*****************************************************************************/
/***** IOH logger *****/
auto max_target = benchmark[problem].max_target;
ioh::logger::eah::Log10Scale<double> target_range(0, max_target, buckets);
ioh::logger::eah::Log10Scale<size_t> budget_range(0, max_evals, buckets);
ioh::logger::EAH eah_logger(target_range, budget_range);
ioh::logger::Combine loggers(eah_logger);
std::shared_ptr<ioh::logger::FlatFile> csv_logger = nullptr;
if(full_log) {
// Build up an algorithm name from main parameters.
std::ostringstream name;
name << "OnlymutGA";
for(auto& p : {
crossover_selector_p,
crossover_p,
aftercross_selector_p,
mutation_selector_p,
mutation_p,
replacement_p }) {
name << "_" << p.shortName() << "=" << p.getValue();
}
for(auto& p : {
crossover_rate_p,
mutation_rate_p }) {
name << "_" << p.shortName() << "=" << p.getValue();
}
for(auto& p : {pop_size_p,
offspring_size_p }) {
name << "_" << p.shortName() << "=" << p.getValue();
}
std::clog << name.str() << std::endl;
// Build up a problem description.
std::ostringstream desc;
desc << "pb=" << problem << "_";
desc << benchmark[problem]; // Use the `operator<<` above.
std::clog << desc.str() << std::endl;
std::filesystem::path folder = desc.str();
std::filesystem::create_directories(folder);
ioh::trigger::OnImprovement on_improvement;
ioh::watch::Evaluations evaluations;
ioh::watch::TransformedYBest transformed_y_best;
std::vector<std::reference_wrapper<ioh::logger::Trigger >> t = {on_improvement};
std::vector<std::reference_wrapper<ioh::logger::Property>> w = {evaluations,transformed_y_best};
csv_logger = std::make_shared<ioh::logger::FlatFile>(
// {std::ref(on_improvement)},
// {std::ref(evaluations),std::ref(transformed_y_best)},
t, w,
name.str(),
folder
);
loggers.append(*csv_logger);
}
/***** IOH problem *****/
double w_dummy = benchmark[problem].dummy;
int w_epitasis = benchmark[problem].epistasis;
int w_neutrality = benchmark[problem].neutrality;
int w_ruggedness = benchmark[problem].ruggedness;
// std::string problem_name = "OneMax";
// problem_name = problem_name
// + "_D" + std::to_string((int)(w_dummy * dimension))
// + "_E" + std::to_string(w_epitasis)
// + "_N" + std::to_string(w_neutrality)
// + "_R" + std::to_string(w_ruggedness);
// ioh::problem::wmodel::WModelOneMax w_model_om(
WModelFlat w_model_om(
instance,
dimension,
w_dummy,
w_epitasis,
w_neutrality,
w_ruggedness);
/***** Bindings *****/
w_model_om.attach_logger(loggers);
/*****************************************************************************
* Binding everything together.
*****************************************************************************/
eoEvalIOHproblem<Bits> onemax_pb(w_model_om, loggers);
// eoEvalPrint<Bits> eval_print(onemax_pb, std::clog, "\n");
// eoEvalFuncCounter<Bits> eval_count(onemax_pb);
eoEvalCounterThrowException<Bits> eval_count(onemax_pb, max_evals);
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, generations, max_target, pop_size_max, offspring_size, cl_sizes, cl_probs);
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);
/*****************************************************************************
* Run and output results.
*****************************************************************************/
eoPop<Bits> pop;
pop.append(pop_size, onemax_init);
try {
onemax_eval(pop,pop);
foundry(pop); // Actually run the selected algorithm.
} catch(eoMaxEvalException e) {
eo::log << eo::debug << "Reached maximum evaluations: " << eval_count.getValue() << " / " << max_evals << std::endl;
}
/***** IOH perf stats *****/
double perf = ioh::logger::eah::stat::under_curve::volume(eah_logger);
if(perf == 0 or perf > max_target * max_evals * 1.0) {
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;
if(output_mat) {
std::vector<std::vector<double>> mat = ioh::logger::eah::stat::distribution(eah_logger);
// Fancy color map on clog.
std::clog << ioh::logger::eah::colormap(mat) << std::endl;
// Parsable CSV on cout.
std::clog << "Attainment matrix distribution: " << std::endl;
assert(mat.size() > 0);
assert(mat[0].size() > 1);
for(size_t i = mat.size()-1; i > 0; --i) {
assert(mat[i].size() >= 1);
std::cout << mat[i][0];
for(size_t j = 1; j < mat[i].size(); ++j) {
std::cout << "," << mat[i][j];
}
std::cout << std::endl;
}
} else {
// iRace expects minimization
std::cout << -1 * perf << std::endl;
}
}

View file

@ -222,4 +222,52 @@ class eoFastBitMutation : public eoStandardBitMutation<EOT>
double _beta;
};
/** Bucket mutation which assign probability for each bucket
*
* From:
* Carola Doerr, Johann Dréo, Alexis Robbes
*/
template<class EOT>
class eoBucketBitMutation : public eoStandardBitMutation<EOT>
{
public:
eoBucketBitMutation(std::vector<double> bucketsSizes, std::vector<double> bucketValues) :
_bucketsSizes(bucketsSizes),
_bucketValues(bucketValues)
{
assert(bucketsSizes.size() != bucketValues.size());
}
virtual bool operator()(EOT& chrom)
{
this->_nb = customlaw(chrom.size(), _bucketsSizes, _bucketValues);
// BitFlip operator is bound to the _nb reference,
// thus one don't need to re-instantiate.
return this->_bitflip(chrom);
}
virtual std::string className() const {return "eoBucketBitMutation";}
protected:
double customlaw(unsigned n, std::vector<double> bucketsSizes, std::vector<double> bucketValues)
{
int targetBucketIndex = eo::rng.roulette_wheel(bucketValues);
int nb = 0;
int bucketIndex = 0;
while (nb < n && bucketIndex <= targetBucketIndex)
{
if (bucketIndex < targetBucketIndex) nb += int(n*bucketsSizes[bucketIndex]);
else nb += int(eo::rng.uniform(1, n*bucketsSizes[targetBucketIndex]));
}
if (nb > n) nb = n;
return nb;
}
std::vector<double> _bucketsSizes;
std::vector<double> _bucketValues;
};
#endif // _eoStandardBitMutation_h_