document everything and remove dead code

This commit is contained in:
Johann Dreo 2022-09-13 15:25:33 +02:00 committed by nojhan
commit 2accb17599
3 changed files with 150 additions and 10 deletions

View file

@ -4,30 +4,76 @@
#include <eo> #include <eo>
/** A partition of a binary space.
*
* This data structure defines a grouping of the elements of a multi-dimensional
* set in a space of boolean numbers.
* \f[
* \mathrm{1}^n = \bigcup_{i=1}^n \{0,1\}_i
* \f]
* Elements of the set may be either "selected" (in the set S) or "rejected" (in the set R).
* \f[
* (S \in \mathrm{1}^m) \cup (R \in \mathrm{1}^k) \in \mathrm{1}^n,\; n=m+k
* \f]
* Elements are referred to by their index in the set (hereby named "atoms").
*
* This representation is useful if your problem can be defined has selecting
* a subset of elements that optimize some objective function.
*
* The core data structures are two ordered sets of unique atoms,
* the union of which is guaranteed to have the correct dimension.
*/
template<class FitT> template<class FitT>
class moBinaryPartition : public EO<FitT> class moBinaryPartition : public EO<FitT>
{ {
public: public:
/** The type for indices. */
using AtomType = size_t; using AtomType = size_t;
/** The data structures holding the indices. */
using ContainerType = std::set<AtomType>; using ContainerType = std::set<AtomType>;
/** The set of selected atoms. */
ContainerType selected; ContainerType selected;
/** The set of not-selected atoms. */
ContainerType rejected; ContainerType rejected;
/** Constructor /** Consistent constructor
* *
* @param total_nb_genes Total number of possible genes from whith to select. * Put all `total_nb_atoms` indices in the @ref rejected set.
* Indices starts at zero and fill the set in increasing order.
*
* @param total_nb_atoms Total number of possible atoms from whith to select.
*/ */
moBinaryPartition( const size_t total_nb_genes ) moBinaryPartition( const size_t total_nb_atoms )
{ {
// Fill the rejected list with all possible gene indices, // Fill the rejected list with all possible gene indices,
// starting from zero. // starting from zero.
for(size_t i = 0; i < total_nb_genes; ++i) { for(size_t i = 0; i < total_nb_atoms; ++i) {
rejected.insert(i); rejected.insert(i);
} }
// No selected. // None selected.
} }
/** Empty constructor
*
* Do not fill the @ref rejected set.
* You are responsible for making it consistent after instantiation.
*
* @warning If you do not fill at least the @ref rejected set,
* errors will be raised whe trying to @ref select or @ref reject.
*/
moBinaryPartition()
{ }
/** Move one atom in the @ref selected set.
*
* That is: erase the atom from @ref rejected,
* insert it in @ref selected.
*
* @note In debug mode, double check that elements were actually moved.
*/
void select(const size_t atom) { void select(const size_t atom) {
assert(not selected.contains(atom)); assert(not selected.contains(atom));
@ -44,6 +90,13 @@ class moBinaryPartition : public EO<FitT>
assert(has_inserted); assert(has_inserted);
} }
/** Move one atom in the @ref rejected set.
*
* That is: insert the atom in @ref rejected,
* erase it from @ref selected.
*
* @note In debug mode, double check that elements were actually moved.
*/
void reject(const size_t atom) { void reject(const size_t atom) {
assert(not rejected.contains(atom)); assert(not rejected.contains(atom));
@ -95,6 +148,7 @@ class moBinaryPartition : public EO<FitT>
assert(rejected.size() == size); assert(rejected.size() == size);
} }
/** Returns true if all sets are equals. */
bool operator==(const moBinaryPartition& other) { bool operator==(const moBinaryPartition& other) {
return this->selected == other.selected return this->selected == other.selected
and this->rejected == other.rejected; and this->rejected == other.rejected;

View file

@ -6,25 +6,53 @@
#include "moBinaryPartition.h" #include "moBinaryPartition.h"
/** Stable neighbor for a binary partition.
*
* Models how to move from a solution to a neighbor,
* by swaping one selected atom for one rejected atom.
* The number of selected atoms is thus guaranteed to be stable.
*
* The core data structure is two atoms:
* - the selected one,
* - the rejected one.
*/
template<class EOT, class Fitness=typename EOT::Fitness> template<class EOT, class Fitness=typename EOT::Fitness>
class moBinaryPartitionSwapNeighbor : class moBinaryPartitionSwapNeighbor :
public moBackableNeighbor<EOT,double>//, public moBackableNeighbor<EOT,double>//,
// public moIndexNeighbor<EOT,double> // public moIndexNeighbor<EOT,double> // FIXME see if we can model that.
{ {
public: public:
/** Shortcut for Atoms type. */
using AtomType = typename EOT::AtomType; using AtomType = typename EOT::AtomType;
/** Shortcut for containers type. */
using ContainerType = typename EOT::ContainerType; using ContainerType = typename EOT::ContainerType;
/** Shortcut for fitness. */
using moBackableNeighbor<EOT, Fitness>::fitness; using moBackableNeighbor<EOT, Fitness>::fitness;
// using moIndexNeighbor<EOT, Fitness>::key; // using moIndexNeighbor<EOT, Fitness>::key;
// using moIndexNeighbor<EOT, Fitness>::index; // using moIndexNeighbor<EOT, Fitness>::index;
/** Consistent constructor.
*
* Will ensure that the dimension of the partition does not change.
*
* @param _selected_nb Number of selected atoms to maintain.
*/
moBinaryPartitionSwapNeighbor( const size_t _selected_nb ) : moBinaryPartitionSwapNeighbor( const size_t _selected_nb ) :
selected_nb(_selected_nb), selected_nb(_selected_nb)
is_set(false) #ifndef NDEBUG
, is_set(false)
#endif
{ {
assert(selected_nb > 0); assert(selected_nb > 0);
} }
/** Apply the currently stored move.
*
* That is: reject one atom and select one other.
*/
virtual void move(EOT& solution) override { virtual void move(EOT& solution) override {
assert(is_set); assert(is_set);
// Swap the two atoms. // Swap the two atoms.
@ -35,6 +63,10 @@ class moBinaryPartitionSwapNeighbor :
solution.invalidate(); solution.invalidate();
} }
/** Apply the opposite of the currently stored move.
*
* That is: reject the selected atom, and select the rejected one.
*/
virtual void moveBack(EOT& solution) override { virtual void moveBack(EOT& solution) override {
assert(is_set); assert(is_set);
solution.reject(this->select); solution.reject(this->select);
@ -44,6 +76,11 @@ class moBinaryPartitionSwapNeighbor :
solution.invalidate(); solution.invalidate();
} }
/** Set the considered atoms.
*
* @param in The selected atom.
* @param out The rejected atom.
*/
void set(AtomType in, AtomType out) { void set(AtomType in, AtomType out) {
this->select = in; this->select = in;
this->reject = out; this->reject = out;
@ -52,11 +89,16 @@ class moBinaryPartitionSwapNeighbor :
#endif #endif
} }
/** Get the considered atom.
*
* @returns A pair of atoms, the first being the selected atom, the second being the rejected one.
*/
std::pair<AtomType,AtomType> get() { std::pair<AtomType,AtomType> get() {
assert(is_set); assert(is_set);
return std::make_pair(select, reject); return std::make_pair(select, reject);
} }
/** Returns true if this neighbor has the same selected & rejected atoms than the given neighbor. */
virtual bool equals(moBinaryPartitionSwapNeighbor<EOT,Fitness>& neighbor) { virtual bool equals(moBinaryPartitionSwapNeighbor<EOT,Fitness>& neighbor) {
auto [in, out] = neighbor.get(); auto [in, out] = neighbor.get();
return this->select == in and this->reject == out; return this->select == in and this->reject == out;
@ -66,6 +108,7 @@ class moBinaryPartitionSwapNeighbor :
return "moBinaryPartitionSwapNeighbor"; return "moBinaryPartitionSwapNeighbor";
} }
/** Fancy print. */
virtual void printOn(std::ostream& out) const override { virtual void printOn(std::ostream& out) const override {
assert(is_set); assert(is_set);
out << selected_nb out << selected_nb
@ -78,10 +121,21 @@ class moBinaryPartitionSwapNeighbor :
#else #else
protected: protected:
#endif #endif
/** Fixed dimension of the handled solutions. */
const size_t selected_nb; const size_t selected_nb;
/** Selected atom. */
AtomType select; AtomType select;
/** Rejected atom. */
AtomType reject; AtomType reject;
#ifndef NDEBUG #ifndef NDEBUG
/** Sanity flag.
*
* Used in debug builds to ensure that the neighbor
* have been set before being used.
*/
bool is_set; bool is_set;
#endif #endif
}; };

View file

@ -5,13 +5,32 @@
#include <mo> #include <mo>
#include "moBinaryPartition.h" #include "moBinaryPartition.h"
/** Stable neighborhood for binary partitions.
*
* This generates all neighbors of a binary partition
* that have the same dimension than the considered solution.
* I.e. it enumerates all the swaps of two atoms
* between the selected and rejected sets.
*
* The core data structure is two indices:
* - one for the position within the selected set of a binary partition,
* - the other for the position within the rejected set.
*
* The neighborhood is defined as enumerating the neighbors,
* first by going over the rejected atoms (outer loop),
* then by iterating over the selected atoms (inner loop).
*/
template <class EOT, class Fitness=typename EOT::Fitness> template <class EOT, class Fitness=typename EOT::Fitness>
class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitionSwapNeighbor<EOT, Fitness> > class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitionSwapNeighbor<EOT, Fitness> >
{ {
public: public:
/** Shortcut for neighbor's type. */
using Neighbor = moBinaryPartitionSwapNeighbor<EOT, Fitness>; using Neighbor = moBinaryPartitionSwapNeighbor<EOT, Fitness>;
/** Shortcut for Atoms type. */
using AtomType = typename EOT::AtomType; using AtomType = typename EOT::AtomType;
/** Get the currently pointed selected atom. */
AtomType selected(EOT& from, const size_t i_select) { AtomType selected(EOT& from, const size_t i_select) {
typename EOT::ContainerType::iterator typename EOT::ContainerType::iterator
it = std::begin(from.rejected); it = std::begin(from.rejected);
@ -19,6 +38,7 @@ class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitio
return *it; return *it;
} }
/** Get the currently pointed rejected atom. */
AtomType rejected(EOT& from, const size_t j_reject) { AtomType rejected(EOT& from, const size_t j_reject) {
typename EOT::ContainerType::iterator typename EOT::ContainerType::iterator
it = std::begin(from.selected); it = std::begin(from.selected);
@ -26,6 +46,11 @@ class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitio
return *it; return *it;
} }
/** Initialize the neighborhood.
*
* This actually make the neighborhood point to the first possible swap:
* between the first selected atom and the first rejected atom.
*/
virtual void init(EOT& from, Neighbor& to) override { virtual void init(EOT& from, Neighbor& to) override {
i_select = 0; i_select = 0;
j_reject = 0; j_reject = 0;
@ -41,6 +66,7 @@ class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitio
to.set(in, out); to.set(in, out);
} }
/** Point to the next neighbor. */
virtual void next(EOT& from, Neighbor& to) override { virtual void next(EOT& from, Neighbor& to) override {
// If last item of the inner loop. // If last item of the inner loop.
if( i_select == from.rejected.size()-1 ) { if( i_select == from.rejected.size()-1 ) {
@ -66,9 +92,8 @@ class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitio
); );
} }
/** Returns true if there is more neighbors to be enumerated. */
virtual bool cont(EOT& from) override { virtual bool cont(EOT& from) override {
// Outer loop on selected,
// inner loop on rejected.
// std::clog << "cont neighborhood?" // std::clog << "cont neighborhood?"
// << " " << j_reject << "(-" << rejected(from, j_reject) << ")/" << from.selected.size() // << " " << j_reject << "(-" << rejected(from, j_reject) << ")/" << from.selected.size()
// << " " << i_select << "(-" << selected(from, i_select) << ")/" << from.rejected.size() // << " " << i_select << "(-" << selected(from, i_select) << ")/" << from.rejected.size()
@ -90,6 +115,10 @@ class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitio
} }
} }
/** Returns true if there is actual neighbors in the neighborhood.
*
* Essentially just tells if the rejected set is not empty.
*/
virtual bool hasNeighbor(EOT& solution) override { virtual bool hasNeighbor(EOT& solution) override {
return solution.rejected.size() > 0; return solution.rejected.size() > 0;
} }
@ -103,6 +132,9 @@ class moBinaryPartitionSwapNeighborhood : public moNeighborhood<moBinaryPartitio
#else #else
protected: protected:
#endif #endif
/** Index of the currently pointed selected atom. */
size_t i_select; size_t i_select;
/** Index of the currently pointed rejected atom. */
size_t j_reject; size_t j_reject;
}; };