Add tutorial READMEs and fix tutorial return codes
Add README.md files for moeo/tutorial/Lesson{1-4}, smp/tutorial/Lesson{1-4},
and mo/tutorial/Lesson9 — these tutorials had no documentation.
Fix return 1 → return 0 in 28 tutorial main() functions across mo/ and
smp/ that unconditionally returned failure status.
This commit is contained in:
parent
54a44a177f
commit
c1a44fd2a6
37 changed files with 371 additions and 30 deletions
|
|
@ -218,5 +218,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,5 +247,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,5 +214,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,5 +192,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,5 +209,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,5 +214,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,5 +211,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,5 +196,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,5 +192,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,5 +193,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,5 +237,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,5 +228,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,5 +262,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,5 +226,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,5 +207,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,5 +222,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,5 +190,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,5 +188,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,5 +213,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,5 +211,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,5 +247,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,5 +252,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,5 +197,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,5 +274,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,5 +239,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,5 +218,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
48
mo/tutorial/Lesson9/README.md
Normal file
48
mo/tutorial/Lesson9/README.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Variable Neighborhood Search (VNS)
|
||||
|
||||
VNS on the N-Queens problem, using multiple neighborhood structures to
|
||||
escape local optima.
|
||||
|
||||
The N-Queens problem places N queens on an N x N chessboard so that no two
|
||||
queens attack each other. The representation is a permutation (one queen
|
||||
per column) and the fitness counts conflicts (minimized).
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/mo/tutorial/Lesson9` directory:
|
||||
|
||||
```shell
|
||||
./VNS -V=12
|
||||
```
|
||||
|
||||
This runs VNS on a 12-queens instance with a 3-second time limit.
|
||||
|
||||
## How it works
|
||||
|
||||
VNS alternates between perturbation (shaking) and local search using
|
||||
different neighborhood structures. Here, two neighborhoods are used:
|
||||
|
||||
```c++
|
||||
shiftNeighborhood shiftNH((vecSize-1) * (vecSize-1));
|
||||
swapNeighborhood swapNH(vecSize * (vecSize-1) / 2);
|
||||
```
|
||||
|
||||
Each has its own hill-climber and mutation operator:
|
||||
|
||||
```c++
|
||||
moSimpleHC<shiftNeighbor> ls1(shiftNH, fullEval, shiftEval);
|
||||
moSimpleHC<swapNeighbor> ls2(swapNH, fullEval, swapEval);
|
||||
|
||||
moRndVectorVNSelection<Queen> selectNH(ls1, shiftMut, true);
|
||||
selectNH.add(ls2, swapMut);
|
||||
```
|
||||
|
||||
`moRndVectorVNSelection` randomly picks which neighborhood/local search
|
||||
to apply at each iteration. Forward (`moForwardVectorVNSelection`) and
|
||||
backward (`moBackwardVectorVNSelection`) selection strategies are also
|
||||
available. The search runs until the `moTimeContinuator` time limit:
|
||||
|
||||
```c++
|
||||
moTimeContinuator<shiftNeighbor> cont(3); // 3 seconds
|
||||
moVNS<shiftNeighbor> vns(selectNH, acceptCrit, fullEval, cont);
|
||||
```
|
||||
|
|
@ -284,5 +284,5 @@ int main(int argc, char **argv)
|
|||
catch (exception& e) {
|
||||
cout << "Exception: " << e.what() << '\n';
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
84
moeo/tutorial/Lesson1/README.md
Normal file
84
moeo/tutorial/Lesson1/README.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# How to run your first multi-objective EA?
|
||||
|
||||
In this lesson you will solve the Schaffer SCH1 bi-objective problem with
|
||||
NSGA-II using the ParadisEO-MOEO framework.
|
||||
|
||||
The SCH1 problem minimizes two objectives over a single real-valued
|
||||
variable x in [0, 2]:
|
||||
|
||||
- f1(x) = x^2
|
||||
- f2(x) = (x - 2)^2
|
||||
|
||||
## 1. Running
|
||||
|
||||
From the `build/moeo/tutorial/Lesson1` directory:
|
||||
|
||||
```shell
|
||||
./Sch1 --help
|
||||
./Sch1 --popSize=100 --maxGen=100
|
||||
```
|
||||
|
||||
Parameters can also be read from a file:
|
||||
|
||||
```shell
|
||||
./Sch1 @Sch1.param
|
||||
```
|
||||
|
||||
## 2. Browsing the code
|
||||
|
||||
Open `Sch1.cpp` and follow along.
|
||||
|
||||
First, define the objective vector traits. This tells MOEO how many
|
||||
objectives the problem has and whether each is minimizing or maximizing:
|
||||
|
||||
```c++
|
||||
class Sch1ObjectiveVectorTraits : public moeoObjectiveVectorTraits
|
||||
{
|
||||
public:
|
||||
static bool minimizing (int) { return true; }
|
||||
static bool maximizing (int) { return false; }
|
||||
static unsigned int nObjectives () { return 2; }
|
||||
};
|
||||
```
|
||||
|
||||
The solution class `Sch1` inherits from `moeoRealVector` — a real-valued
|
||||
decision vector that also carries an objective vector:
|
||||
|
||||
```c++
|
||||
class Sch1 : public moeoRealVector < Sch1ObjectiveVector >
|
||||
{
|
||||
public:
|
||||
Sch1() : moeoRealVector < Sch1ObjectiveVector > (1) {}
|
||||
};
|
||||
```
|
||||
|
||||
The evaluator computes both objectives and stores them via
|
||||
`objectiveVector()`:
|
||||
|
||||
```c++
|
||||
void operator () (Sch1 & _sch1)
|
||||
{
|
||||
if (_sch1.invalidObjectiveVector()) {
|
||||
Sch1ObjectiveVector objVec;
|
||||
double x = _sch1[0];
|
||||
objVec[0] = x * x;
|
||||
objVec[1] = (x - 2.0) * (x - 2.0);
|
||||
_sch1.objectiveVector(objVec);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The algorithm itself is a single line — `moeoNSGAII` takes the generation
|
||||
limit, evaluator, crossover, and mutation as constructor arguments:
|
||||
|
||||
```c++
|
||||
moeoNSGAII < Sch1 > nsgaII (MAX_GEN, eval, xover, P_CROSS, mutation, P_MUT);
|
||||
```
|
||||
|
||||
After the run, extract the Pareto front with `moeoUnboundedArchive`:
|
||||
|
||||
```c++
|
||||
moeoUnboundedArchive < Sch1 > arch;
|
||||
arch(pop);
|
||||
arch.sortedPrintOn(cout);
|
||||
```
|
||||
31
moeo/tutorial/Lesson2/README.md
Normal file
31
moeo/tutorial/Lesson2/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Multi-objective EA on the flow-shop scheduling problem
|
||||
|
||||
This lesson solves a more realistic combinatorial problem: the bi-objective
|
||||
permutation flow-shop, which minimizes both makespan and total flow time.
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/moeo/tutorial/Lesson2` directory:
|
||||
|
||||
```shell
|
||||
./FlowShopEA @FlowShopEA.param
|
||||
```
|
||||
|
||||
The parameter file specifies the problem instance, population size, operator
|
||||
rates, and fitness assignment strategy.
|
||||
|
||||
## How it works
|
||||
|
||||
The code uses ParadisEO's `do_make_*` factory functions to build all
|
||||
components from command-line parameters:
|
||||
|
||||
```c++
|
||||
eoEvalFuncCounter<FlowShop>& eval = do_make_eval(parser, state);
|
||||
eoInit<FlowShop>& init = do_make_genotype(parser, state);
|
||||
eoGenOp<FlowShop>& op = do_make_op(parser, state);
|
||||
```
|
||||
|
||||
The flow-shop representation is defined in `FlowShop.h` — a
|
||||
permutation-based `moeoVector` with a bi-objective vector. Different
|
||||
Pareto-based fitness assignment strategies (NSGA-II, SPEA2, IBEA, etc.)
|
||||
can be selected via parameters.
|
||||
32
moeo/tutorial/Lesson3/README.md
Normal file
32
moeo/tutorial/Lesson3/README.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# User-friendly multi-objective EA
|
||||
|
||||
Same flow-shop problem as Lesson 2, but with a complete algorithmic pipeline
|
||||
built from reusable `do_make_*` helpers: stopping criteria, checkpointing,
|
||||
statistics, and the full evolution engine.
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/moeo/tutorial/Lesson3` directory:
|
||||
|
||||
```shell
|
||||
./FlowShopEA2 @FlowShopEA2.param
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
The main program is essentially a sequence of factory calls:
|
||||
|
||||
```c++
|
||||
eoEvalFuncCounter<FlowShop>& eval = do_make_eval(parser, state);
|
||||
eoInit<FlowShop>& init = do_make_genotype(parser, state);
|
||||
eoPop<FlowShop>& pop = do_make_pop(parser, state, init);
|
||||
eoContinue<FlowShop>& term = do_make_continue_moeo(parser, state, eval);
|
||||
eoCheckPoint<FlowShop>& checkpoint = do_make_checkpoint_moeo(parser, state, ...);
|
||||
eoAlgo<FlowShop>& algo = do_make_ea_moeo(parser, state, ...);
|
||||
do_make_run(parser, state, algo, pop);
|
||||
```
|
||||
|
||||
`do_make_continue_moeo` builds continuators (generation limit, fitness
|
||||
target, etc.) from parameters. `do_make_checkpoint_moeo` adds statistics,
|
||||
population snapshots, and archive tracking. `do_make_ea_moeo` constructs
|
||||
the selection and replacement strategy.
|
||||
35
moeo/tutorial/Lesson4/README.md
Normal file
35
moeo/tutorial/Lesson4/README.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Dominance-based multi-objective local search (DMLS)
|
||||
|
||||
Same flow-shop problem as Lessons 2-3, but solved with local search instead
|
||||
of an evolutionary algorithm. This combines ParadisEO-MO local search
|
||||
components with the MOEO multi-objective framework.
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/moeo/tutorial/Lesson4` directory:
|
||||
|
||||
```shell
|
||||
./FlowShopDMLS @FlowShopDMLS.param
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
The program uses `moShiftNeighbor` and `moOrderNeighborhood` from
|
||||
ParadisEO-MO, with `moeoFullEvalByCopy` to adapt the full solution
|
||||
evaluator for neighbor evaluation:
|
||||
|
||||
```c++
|
||||
typedef moShiftNeighbor<FlowShop, FlowShopObjectiveVector> Neighbor;
|
||||
|
||||
moOrderNeighborhood<Neighbor> neighborhood((nhSize-1) * (nhSize-1));
|
||||
moeoFullEvalByCopy<Neighbor> moEval(eval);
|
||||
```
|
||||
|
||||
At each iteration, DMLS explores all non-dominated solutions in the
|
||||
archive via local search moves and updates the archive with any improving
|
||||
neighbors:
|
||||
|
||||
```c++
|
||||
moeoFirstImprovingNeighborhoodExplorer<Neighbor> explor(neighborhood, moEval);
|
||||
moeoUnifiedDominanceBasedLS<Neighbor> algo(checkpoint, eval, arch, explor, select);
|
||||
```
|
||||
23
smp/tutorial/Lesson1/README.md
Normal file
23
smp/tutorial/Lesson1/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Master/Workers wrapping with eoEasyEA
|
||||
|
||||
Wraps a standard eoEasyEA with the ParadisEO-SMP parallel evaluation model,
|
||||
applied to the Quadratic Assignment Problem (QAP).
|
||||
|
||||
The QAP assigns facilities to locations to minimize cost (flow x distance).
|
||||
The representation is a permutation.
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/smp/tutorial/Lesson1` directory:
|
||||
|
||||
```shell
|
||||
./lesson1_eoEasyEA lesson1_eoEasyEA.param
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
The key idea: ParadisEO-SMP parallelizes evaluation by wrapping an existing
|
||||
sequential algorithm. The algorithm code itself stays the same. `QAP.h`
|
||||
defines the problem representation and evaluation, `QAPGA.h` defines the GA
|
||||
operators, and `parserStruct.h` + `utils.h` handle parameter parsing and
|
||||
instance loading. See also `lesson1_data.dat` for the problem instance.
|
||||
|
|
@ -23,8 +23,8 @@ same conditions as regards security.
|
|||
The fact that you are presently reading this means that you have had
|
||||
knowledge of the CeCILL license and that you accept its terms.
|
||||
|
||||
ParadisEO WebSite : http://paradiseo.gforge.inria.fr
|
||||
Contact: paradiseo-help@lists.gforge.inria.fr
|
||||
ParadisEO WebSite : https://nojhan.github.io/paradiseo/
|
||||
Contact: https://github.com/nojhan/paradiseo/issues
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -125,5 +125,5 @@ int main(int argc, char **argv)
|
|||
delete[] b;
|
||||
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
30
smp/tutorial/Lesson2/README.md
Normal file
30
smp/tutorial/Lesson2/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Homogeneous island model
|
||||
|
||||
Three islands running the same algorithm (`eoEasyEA`) with a complete
|
||||
topology — all islands exchange individuals with all others.
|
||||
|
||||
Same QAP problem as Lesson 1.
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/smp/tutorial/Lesson2` directory:
|
||||
|
||||
```shell
|
||||
./lesson2_homogeneous
|
||||
```
|
||||
|
||||
The problem instance is loaded from `../lessonData.dat`.
|
||||
|
||||
## How it works
|
||||
|
||||
All islands share the same operators (evaluation, selection, crossover,
|
||||
mutation, replacement) but can have different parameters. The topology
|
||||
and island model are set up with:
|
||||
|
||||
```c++
|
||||
Topology<Complete> topo;
|
||||
IslandModel<Indi> model(topo);
|
||||
```
|
||||
|
||||
Each island gets its own population and generation limit, then the model
|
||||
runs them in parallel and handles migration.
|
||||
27
smp/tutorial/Lesson3/README.md
Normal file
27
smp/tutorial/Lesson3/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Heterogeneous island model
|
||||
|
||||
Two islands running different algorithms: an `eoEasyEA` on the QAP problem
|
||||
and a PSO on a bitstring problem, connected via conversion functions.
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/smp/tutorial/Lesson3` directory:
|
||||
|
||||
```shell
|
||||
./lesson3_heterogeneous
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
When islands use different representations, you need conversion functions
|
||||
to translate individuals during migration. In this example, `fromBase()`
|
||||
and `toBase()` convert between the QAP permutation and the PSO bitstring:
|
||||
|
||||
```c++
|
||||
Indi2 fromBase(Indi& i, unsigned size) { ... }
|
||||
Indi toBase(Indi2& i) { ... }
|
||||
```
|
||||
|
||||
The conversions here are dummy placeholders (they just create random
|
||||
individuals), but in a real application you would implement meaningful
|
||||
mappings between representations.
|
||||
31
smp/tutorial/Lesson4/README.md
Normal file
31
smp/tutorial/Lesson4/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Dynamic island topology
|
||||
|
||||
Three islands start with a ring topology and switch to a complete topology
|
||||
after 10 seconds of computation.
|
||||
|
||||
Same QAP problem as Lessons 1-2.
|
||||
|
||||
## Running
|
||||
|
||||
From the `build/smp/tutorial/Lesson4` directory:
|
||||
|
||||
```shell
|
||||
./lesson4_topology
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
A callback function registered with the islands triggers the topology
|
||||
change:
|
||||
|
||||
```c++
|
||||
void changeTopo(IslandModel<Indi>* _model, AbstractTopology& _topo)
|
||||
{
|
||||
// ... after 10 seconds:
|
||||
_model->setTopology(_topo);
|
||||
}
|
||||
```
|
||||
|
||||
The topology can be changed at runtime via `model.setTopology()`, so you
|
||||
can implement adaptive communication patterns based on time, convergence,
|
||||
or any other criterion.
|
||||
Loading…
Add table
Add a link
Reference in a new issue