fix #10: removed the moo/ directory and eoMO* classes, deprecated by the Paradiseo-MOEO project

This commit is contained in:
Johann Dreo 2010-10-31 22:57:05 +01:00
commit 653bc392ed
15 changed files with 0 additions and 1846 deletions

View file

@ -1 +0,0 @@
Makefile.in

View file

@ -1,34 +0,0 @@
######################################################################################
### 1) Include the sources
######################################################################################
INCLUDE_DIRECTORIES(${EO_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
######################################################################################
### 2) Define the eomoo target
######################################################################################
SET(EOMOO_LIB_OUTPUT_PATH ${EO_BINARY_DIR}/lib)
SET(LIBRARY_OUTPUT_PATH ${EOMOO_LIB_OUTPUT_PATH})
SET (EOMOO_SOURCES eoFrontSorter.cpp
eoNSGA_IIa_Eval.cpp
eoNSGA_II_Eval.cpp)
ADD_LIBRARY(eomoo STATIC ${EOMOO_SOURCES})
INSTALL(TARGETS eomoo ARCHIVE DESTINATION lib COMPONENT libraries)
FILE(GLOB HDRS *.h)
INSTALL(FILES ${HDRS} DESTINATION include/eo/moo COMPONENT headers)
######################################################################################
### 3) Optionnal
######################################################################################
SET(EOMOO_VERSION ${GLOBAL_VERSION})
SET_TARGET_PROPERTIES(eomoo PROPERTIES VERSION "${EOMOO_VERSION}")
######################################################################################

View file

@ -1,136 +0,0 @@
#ifndef eoEpsMOEA_h
#define eoEpsMOEA_h
#include <eoAlgo.h>
#include <moo/eoEpsilonArchive.h>
#include <utils/eoStat.h>
template <class EOT>
class eoEpsMOEA : public eoAlgo<EOT> {
public:
eoEpsMOEA(
eoContinue<EOT>& _continuator,
eoEvalFunc<EOT>& _eval,
eoGenOp<EOT>& _op,
const std::vector<double>& eps,
unsigned max_archive_size = std::numeric_limits<unsigned>::max()
) : continuator(_continuator),
eval (_eval),
loopEval(_eval),
popEval(loopEval),
op(_op),
archive(eps, max_archive_size)
{
}
void operator()(eoPop<EOT>& pop) {
eoPop<EOT> offspring;
popEval(offspring, pop);
for (unsigned i = 0; i < pop.size(); ++i) pop[i].fitnessReference().setWorth(1.0);
do {
unsigned nProcessed = 0;
while (nProcessed < pop.size()) {
offspring.clear();
epsPopulator populator(archive, pop, offspring);
op(populator);
nProcessed += offspring.size();
popEval(pop, offspring);
for (unsigned i = 0; i < offspring.size(); ++i) {
offspring[i].fitnessReference().setWorth(1.0);
archive(offspring[i]);
update_pop(pop, offspring[i]);
}
}
// quite expensive to copy the entire archive time and time again, but this will make it work more seamlessly with the rest of EO
offspring.clear();
archive.appendTo(offspring);
} while (continuator(offspring)); // check archive
// return archive
pop.clear();
archive.appendTo(pop);
}
private :
void update_pop(eoPop<EOT>& pop, const EOT& offspring) {
std::vector<unsigned> dominated;
for (unsigned i = 0; i < pop.size(); ++i) {
int dom = offspring.fitness().check_dominance(pop[i].fitness());
switch (dom) {
case 1 : // indy dominates this
dominated.push_back(i);
break;
case -1 : // is dominated, do not insert
return;
case 0: // incomparable
break;
}
}
if (dominated.size()) {
pop[ dominated[ rng.random(dominated.size()) ] ] = offspring;
}
// non-dominated everywhere, overwrite random one
pop[ rng.random(pop.size()) ] = offspring;
}
class epsPopulator : public eoPopulator<EOT> {
using eoPopulator< EOT >::src;
eoEpsilonArchive<EOT>& archive;
bool fromArchive;
public:
epsPopulator(eoEpsilonArchive<EOT>& arch, const eoPop<EOT>& pop, eoPop<EOT>& res) : eoPopulator<EOT>(pop, res), archive(arch), fromArchive(true) {}
const EOT& select() {
fromArchive = !fromArchive;
using std::cout;
using std::endl;
if (fromArchive && !archive.empty()) {
return archive.selectRandom();
}
// tournament selection on population
const EOT& eo1 = rng.choice(src);
const EOT& eo2 = rng.choice(src);
if (eo1.fitness().dominates(eo2.fitness())) return eo1;
return eo2; // they are drawn at random, so no need to do an extra randomization step
}
};
eoContinue<EOT>& continuator;
eoEvalFunc <EOT> & eval ;
eoPopLoopEval<EOT> loopEval;
eoPopEvalFunc<EOT>& popEval;
eoGenOp<EOT>& op;
eoEpsilonArchive<EOT> archive;
};
#endif

View file

@ -1,140 +0,0 @@
#ifndef eoEpsilonArchive_h
#define eoEpsilonArchive_h
#include <moo/eoMOFitness.h>
#include <list>
template <class EOT>
class eoEpsilonArchive {
typedef typename EOT::Fitness::fitness_traits Traits;
struct Node {
EOT element;
std::vector<long> discretized;
Node(const EOT& eo) : element(eo), discretized(Traits::nObjectives()) {}
dominance::dominance_result check(const Node& other) const {
return dominance::check_discrete(discretized, other.discretized);
}
};
typedef std::vector<Node> archive_t;
archive_t archive;
std::vector<double> inv_eps;
unsigned max_size;
public:
static double direction(unsigned i) { return 1; }
static double tol() { return 1e-6; }
eoEpsilonArchive(const std::vector<double>& eps_, unsigned max_size_ = std::numeric_limits<unsigned>::max()) : max_size(max_size_) {
inv_eps.resize(eps_.size());
for (unsigned i = 0; i < inv_eps.size(); ++i) {
inv_eps[i] = 1.0 / eps_[i];
}
if (inv_eps.size() != Traits::nObjectives()) throw std::logic_error("eoEpsilonArchive: need one epsilon for each objective");
}
bool empty() { return archive.size() == 0; }
void operator()(const EOT& eo) {
using std::cout;
using std::endl;
// discretize
Node node(eo);
for (unsigned i = 0; i < eo.fitness().size(); ++i) {
double val = Traits::direction(i) * eo.fitness()[i];
node.discretized[i] = (long) floor(val*inv_eps[i]);
}
using namespace dominance;
unsigned box = archive.size();
// update archive
for (unsigned i = 0; i != archive.size(); ++i) {
dominance_result result = node.check(archive[i]); //check<eoEpsilonArchive<EOT> >(node.discretized, archive[i].discretized);
switch (result) {
case first : { // remove dominated archive member
std::swap( archive[i], archive.back());
archive.pop_back();
--i;
break;
}
case second : {
return; // new one does not belong in archive
}
case non_dominated : break; // both non-dominated, put in different boxes
case non_dominated_equal : { // in same box
box = i;
goto exitLoop; // break
}
}
}
exitLoop:
// insert
if (box >= archive.size()) { // non-dominated, new box
archive.push_back(node);
} else { // fight it out
int dom = node.element.fitness().check_dominance( archive[box].element.fitness() );
switch (dom) {
case 1: archive[box] = node; break;
case -1: break;
case 0: {
double d1 = 0.0;
double d2 = 0.0;
for (unsigned i = 0; i < node.element.fitness().size(); ++i) {
double a = Traits::direction(i) * node.element.fitness()[i] * inv_eps[i];
double b = Traits::direction(i) * archive[box].element.fitness()[i] * inv_eps[i];
d1 += pow( a - node.discretized[i], 2.0);
d2 += pow( b - node.discretized[i], 2.0);
}
if (d1 > d2) {
archive[box] = node;
}
break;
}
}
}
if (archive.size() > max_size) {
unsigned idx = rng.random(archive.size());
if (idx != archive.size()-1) std::swap(archive[idx], archive.back());
archive.pop_back();
}
}
void appendTo(eoPop<EOT>& pop) const {
for (typename archive_t::const_iterator it = archive.begin(); it != archive.end(); ++it) {
pop.push_back( it->element );
}
}
const EOT& selectRandom() const {
int i = rng.random(archive.size());
return archive[i].element;
}
};
#endif

View file

@ -1,146 +0,0 @@
#include <moo/eoFrontSorter.h>
using namespace std;
namespace detail {
void one_objective(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front, double tol)
{
std::sort(fitness.begin(), fitness.end(), CompareOn(0, tol));
front.clear();
front.resize(1);
front[0].push_back(fitness[0]);
for (unsigned i = 1; i < fitness.size(); ++i) {
if (fitness[i].fitness[0] < fitness[i-1].fitness[0]) { // keep clones in same front
front.push_back( std::vector<FitnessInfo>() );
}
front.back().push_back( fitness[i] );
}
}
/**
* Optimization for two objectives. Makes the algorithm run in
* complexity O(n log n) where n is the population size
*/
void two_objectives(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front, double tol)
{
std::sort(fitness.begin(), fitness.end(), CompareOn(0, tol));
front.clear();
std::vector<FitnessInfo> front_leader;
for (unsigned i = 0; i < fitness.size(); ++i) {
// find front through binary search
vector<FitnessInfo>::iterator it = upper_bound( front_leader.begin(), front_leader.end(), fitness[i], CompareOn(1, tol));
if (it == front_leader.end()) {
front_leader.push_back(fitness[i]);
front.push_back( vector<FitnessInfo>(1, fitness[i]) );
} else {
*it = fitness[i]; // new 'best of front in second dimension'
front[ it - front_leader.begin() ].push_back(fitness[i]); // add to front of nth dominated solutions
}
}
}
bool dominates(const FitnessInfo& a, const FitnessInfo& b, double tol) {
bool better_on_one = false;
for (unsigned i = 0; i < a.fitness.size(); ++i) {
if (fabs(a.fitness[i] - b.fitness[i]) < tol) continue;
if (a.fitness[i] < b.fitness[i]) return false; // worse on at least one other objective
if (a.fitness[i] > b.fitness[i]) better_on_one = true;
}
return better_on_one;
}
void m_objectives(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front, double tol) {
unsigned i;
std::vector<std::vector<unsigned> > S(fitness.size()); // which individuals does guy i dominate
std::vector<unsigned> n(fitness.size()); // how many individuals dominate guy i
unsigned j;
for (i = 0; i < fitness.size(); ++i)
{
for (j = 0; j < fitness.size(); ++j)
{
if ( dominates(fitness[i], fitness[j], tol) )
{ // i dominates j
S[i].push_back(j); // add j to i's domination list
}
else if (dominates(fitness[j], fitness[i], tol))
{ // j dominates i, increment count for i, add i to the domination list of j
n[i]++;
}
}
}
front.clear();
front.resize(1);
// get the first front out
for (i = 0; i < fitness.size(); ++i)
{
if (n[i] == 0)
{
front.back().push_back( fitness[i] );
}
}
while (!front.back().empty())
{
front.push_back(vector<FitnessInfo>());
vector<FitnessInfo>& last_front = front[front.size()-2];
// Calculate which individuals are in the next front;
for (i = 0; i < last_front.size(); ++i)
{
for (j = 0; j < S[ last_front[i].index ].size(); ++j)
{
unsigned dominated_individual = S[ last_front[i].index ][j];
n[dominated_individual]--; // As we remove individual i -- being part of the current front -- it no longer dominates j
if (n[dominated_individual] == 0) // it should be in the current front
{
front.back().push_back( fitness[dominated_individual] );
}
}
}
}
front.pop_back(); // last front is empty;
}
void front_sorter_impl(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& front_indices, double tol) {
switch (fitness[0].fitness.size())
{
case 1:
{
one_objective(fitness, front_indices, tol);
return;
}
case 2:
{
two_objectives(fitness, front_indices, tol);
return;
}
default :
{
m_objectives(fitness, front_indices, tol);
}
}
}
} // namespace detail

View file

@ -1,104 +0,0 @@
/** -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
-----------------------------------------------------------------------------
eoNDSorting.h
(c) Maarten Keijzer, Marc Schoenauer, 2001
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; either
version 2 of the License, or (at your option) any later version.
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
Contact: todos@geneura.ugr.es, http://geneura.ugr.es
Marc.Schoenauer@polytechnique.fr
mkeijzer@dhi.dk
*/
//-----------------------------------------------------------------------------
#ifndef eoFrontSorter_h
#define eoFrontSorter_h
#include <EO.h>
#include <algorithm>
#include <eoPop.h>
#include <cassert>
namespace detail {
// small helper structs to store the multi-objective information. To be used in the implementation
struct FitnessInfo {
std::vector<double> fitness; // preprocessed fitness -> all maximizing
unsigned index; // index into population
FitnessInfo() {}
FitnessInfo(const std::vector<double>& fitness_, unsigned index_) : fitness(fitness_), index(index_) {}
};
struct CompareOn {
unsigned dim;
double tol;
CompareOn(unsigned d, double t) : dim(d), tol(t) {}
bool operator()(const FitnessInfo& a, const FitnessInfo& b) {
return a.fitness[dim] > b.fitness[dim] && fabs(a.fitness[dim] - b.fitness[dim]) > tol;
}
};
extern void front_sorter_impl(std::vector<FitnessInfo>& fitness, std::vector< std::vector<FitnessInfo> >& fronts, double tol);
} // namespace detail
/**
* Reassembles population into a set of fronts;
*/
template <class EOT>
class eoFrontSorter : public eoUF< const eoPop<EOT>&, const std::vector< std::vector<detail::FitnessInfo> >& >
{
std::vector<detail::FitnessInfo > fitness;
std::vector< std::vector<detail::FitnessInfo> > fronts;
public :
typedef typename EOT::Fitness::fitness_traits Traits;
typedef std::vector< std::vector<detail::FitnessInfo> > front_t;
const std::vector<std::vector<detail::FitnessInfo> >& operator()(const eoPop<EOT>& _pop)
{
fitness.resize(_pop.size());
for (unsigned i = 0; i < _pop.size(); ++i) {
fitness[i] = detail::FitnessInfo(_pop[i].fitness().normalized(), i);
}
detail::front_sorter_impl(fitness, fronts, Traits::tol());
return fronts;
}
const std::vector<std::vector<detail::FitnessInfo> >& operator()(const std::vector<EOT*>& _pop)
{
fitness.resize(_pop.size());
for (unsigned i = 0; i < _pop.size(); ++i) {
fitness[i] = detail::FitnessInfo(_pop[i]->fitness().normalized(), i);
}
detail::front_sorter_impl(fitness, fronts, Traits::tol());
return fronts;
}
};
#endif

View file

@ -1,26 +0,0 @@
#ifndef eoMOEval_h
#define eoMOEval_h
#include <eoPopEvalFunc.h>
template <class EOT>
class eoMOEval : public eoPopEvalFunc<EOT> {
protected:
eoMOEval(eoEvalFunc<EOT>& eval) : default_loop(eval), pop_eval(default_loop) {}
eoMOEval(eoPopEvalFunc<EOT>& ev) : default_loop(dummy_eval), pop_eval(ev) {}
void eval(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
pop_eval(parents, offspring);
}
private :
class eoDummyEval : public eoEvalFunc<EOT> {public: void operator()(EOT &) {} } dummy_eval;
eoPopLoopEval<EOT> default_loop;
eoPopEvalFunc<EOT>& pop_eval;
};
#endif

View file

@ -1,298 +0,0 @@
// -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*-
//-----------------------------------------------------------------------------
// eoMOFitness.h
// (c) Maarten Keijzer and Marc Schoenauer, 2007
/*
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; either
version 2 of the License, or (at your option) any later version.
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
Contact: mak@dhi.dk
Marc.Schoenauer@inria.fr
*/
//-----------------------------------------------------------------------------
#ifndef _eoMOFitness_h
#define _eoMOFitness_h
#include <math.h>
#include <vector>
#include <stdexcept>
#include <iostream>
#include <limits>
/**
* eoMOFitnessTraits: a traits class to specify
* the number of objectives and which one are direction or not
* See test/t-eoParetoFitness for its use.
*
* If you define your own, make sure you make the functions static!
*/
class eoMOFitnessTraits
{
public :
/// Number of Objectives
static unsigned nObjectives() { return 2; }
/// by default: all are maximizing, zero will lead to ignored fitness, negative to minimization for that objective
static double direction(unsigned which) { return 1; }
/// tolerance for dominance check (if within this tolerance objective values are considered equal)
static double tol() { return 1e-6; }
};
namespace dominance {
template <class Traits>
inline double worst_possible_value(unsigned objective) {
double dir = Traits::direction(objective);
if (dir == 0.) return 0.0;
if (dir < 0.) return std::numeric_limits<double>::infinity();
return -std::numeric_limits<double>::infinity();
}
template <class Traits>
inline double best_possible_value(unsigned objective) {
return -worst_possible_value<Traits>(objective);
}
enum dominance_result { non_dominated_equal, first, second, non_dominated };
template <class FitnessDirectionTraits>
inline dominance_result check(const std::vector<double>& p1, const std::vector<double>& p2, double tolerance) {
bool all_equal = true;
bool a_better_in_one = false;
bool b_better_in_one = false;
for (unsigned i = 0; i < p1.size(); ++i) {
double maxim = FitnessDirectionTraits::direction(i);
double aval = maxim * p1[i];
double bval = maxim * p2[i];
if ( fabs(aval-bval) > tolerance ) {
all_equal = false;
if (aval > bval) {
a_better_in_one = true;
} else {
b_better_in_one = true;
}
// check if we need to go on
if (a_better_in_one && b_better_in_one) return non_dominated;
}
}
if (all_equal) return non_dominated_equal;
if (a_better_in_one) return first;
// else b dominates a (check for non-dominance done above
return second;
}
template <class IntType>
inline dominance_result check_discrete(const std::vector<IntType>& a, const std::vector<IntType>& b) {
bool all_equal = true;
bool a_better_in_one = false;
bool b_better_in_one = false;
for (unsigned i = 0; i < a.size(); ++i) {
if ( a[i] != b[i] ) {
all_equal = false;
if (a[i] > b[i]) {
a_better_in_one = true;
} else {
b_better_in_one = true;
}
// check if we need to go on
if (a_better_in_one && b_better_in_one) return non_dominated;
}
}
if (all_equal) return non_dominated_equal;
if (a_better_in_one) return first;
// else b dominates a (check for non-dominance done above
return second;
}
template <class FitnessTraits>
inline dominance_result check(const std::vector<double>& p1, const std::vector<double>& p2) {
return check<FitnessTraits>(p1, p2, FitnessTraits::tol());
}
} // namespace dominance
/**
eoMOFitness class: std::vector of doubles with overloaded comparison operators. Comparison is done
on 'worth'. This worth needs to be set elsewhere. The template argument FitnessTraits defaults to eMOFitnessTraits, which
can be replaces at will by any other class that implements the static functions defined therein.
Note that the comparison defines a partial order, so that
!(a < b) && !(b <a) does not neccessarily imply that (a==b)
The other way around does hold.
*/
template <class FitnessTraits = eoMOFitnessTraits>
class eoMOFitness : public std::vector<double>
{
double worth; // used for sorting and selection, by definition, bigger is better
bool worthValid;
public :
typedef FitnessTraits fitness_traits;
eoMOFitness() : std::vector<double>(FitnessTraits::nObjectives()), worthValid(false) { reset(); }
explicit eoMOFitness(double def) : std::vector<double>(FitnessTraits::nObjectives(),def), worthValid(false) {}
// Ctr from a std::vector<double>
explicit eoMOFitness(std::vector<double> & _v) : std::vector<double>(_v), worthValid(false) {}
virtual ~eoMOFitness() {} // in case someone wants to subclass
eoMOFitness(const eoMOFitness<FitnessTraits>& org) { operator=(org); }
eoMOFitness<FitnessTraits>& operator=(const eoMOFitness<FitnessTraits>& org) {
std::vector<double>::operator=(org);
worth = org.worth;
worthValid = org.worthValid;
return *this;
}
void reset() {
for (unsigned i = 0; i < size(); ++i) {
this->operator[](i) = dominance::worst_possible_value<FitnessTraits>(i);
}
}
// Make the objective 'feasible' by setting it to the best possible value
void setFeasible(unsigned objective) { this->operator[](objective) = dominance::best_possible_value<FitnessTraits>(objective); }
void setWorth(double worth_) {
worth = worth_;
worthValid = true;
}
double getWorth() const {
if (!worthValid) {
throw std::runtime_error("invalid worth");
}
return worth;
}
bool validWorth() const { return worthValid; }
void invalidateWorth() { worthValid = false; }
/// Check on dominance: returns 0 if non-dominated, 1 if this dominates other, -1 if other dominates this
int check_dominance(const eoMOFitness<FitnessTraits>& _other) const
{
dominance::dominance_result dom = dominance::check<FitnessTraits>(*this, _other);
return dom == dominance::first? 1 : (dom == dominance::second? -1 : 0);
}
/// normalized fitness: all maximizing, removed the irrelevant ones
std::vector<double> normalized() const {
std::vector<double> f;
for (unsigned j = 0; j < FitnessTraits::nObjectives(); ++j) {
if (FitnessTraits::direction(j) != 0) {
f.push_back( FitnessTraits::direction(j) * this->operator[](j));
}
}
return f;
}
/// returns true if this dominates other
bool dominates(const eoMOFitness<FitnessTraits>& _other) const
{
return check_dominance(_other) == 1;
}
/// compare *not* on dominance, but on worth
bool operator<(const eoMOFitness<FitnessTraits>& _other) const
{
return getWorth() < _other.getWorth();
}
bool operator>(const eoMOFitness<FitnessTraits>& _other) const
{
return _other > *this;
}
bool operator<=(const eoMOFitness<FitnessTraits>& _other) const
{
return getWorth() <= _other.getWorth();
}
bool operator>=(const eoMOFitness<FitnessTraits>& _other) const
{
return _other <= *this;
}
bool operator==(const eoMOFitness<FitnessTraits>& _other) const
{ // check if they're all within tolerance
return getWorth() == _other.getWorth();
}
bool operator!=(const eoMOFitness<FitnessTraits>& _other) const
{ return ! operator==(_other); }
friend std::ostream& operator<<(std::ostream& os, const eoMOFitness<FitnessTraits>& fitness)
{
for (unsigned i = 0; i < fitness.size(); ++i)
{
os << fitness[i] << ' ';
}
os << fitness.worthValid << ' ' << fitness.worth;
return os;
}
friend std::istream& operator>>(std::istream& is, eoMOFitness<FitnessTraits>& fitness)
{
fitness = eoMOFitness<FitnessTraits>();
for (unsigned i = 0; i < fitness.size(); ++i)
{
is >> fitness[i];
}
is >> fitness.worthValid >> fitness.worth;
return is;
}
};
namespace dominance {
template <class FitnessTraits>
inline dominance_result check(const eoMOFitness<FitnessTraits>& p1, const eoMOFitness<FitnessTraits>& p2) {
return check<FitnessTraits>(p1, p2, FitnessTraits::tol());
}
}
#endif

View file

@ -1,80 +0,0 @@
#include <limits>
#include <moo/eoNSGA_II_Eval.h>
namespace nsga2 {
using namespace std;
typedef std::pair<double, unsigned> double_index_pair;
class compare_nodes
{
public :
bool operator()(const double_index_pair& a, const double_index_pair& b) const
{
return a.first < b.first;
}
};
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, std::vector<double>& worths) {
unsigned nObjectives = front[0].fitness.size(); //traits::nObjectives(); //_pop[_cf[0]].fitness().size();
std::vector<double> niche_distance(front.size());
for (unsigned o = 0; o < nObjectives; ++o)
{
std::vector<std::pair<double, unsigned> > performance(front.size());
for (unsigned i =0; i < front.size(); ++i)
{
performance[i].first = front[i].fitness[o];
performance[i].second = i;
}
std::sort(performance.begin(), performance.end(), compare_nodes()); // a lambda operator would've been nice here
std::vector<double> nc(front.size(), 0.0);
for (unsigned i = 1; i < front.size()-1; ++i)
{ // and yet another level of indirection
nc[performance[i].second] = performance[i+1].first - performance[i-1].first;
}
// set boundary at max_dist + 1 (so it will get chosen over all the others
//nc[performance[0].second] += 0;
nc[performance.back().second] = std::numeric_limits<double>::infinity(); // best on objective
for (unsigned i = 0; i < nc.size(); ++i)
{
niche_distance[i] += nc[i];
}
}
// now we've got niche_distances, scale them between (0, 1), making sure that infinities get maximum rank
double max = 0;
for (unsigned i = 0; i < niche_distance.size(); ++i) {
if (niche_distance[i] != std::numeric_limits<double>::infinity()) {
max = std::max(max, niche_distance[i]);
}
}
for (unsigned i = 0; i < front.size(); ++i) {
double dist = niche_distance[i];
if (dist == std::numeric_limits<double>::infinity()) {
dist = 1.0;
} else {
dist /= (1+max);
}
unsigned idx = front[i].index;
worths[idx] = rank + dist;
}
}
}

View file

@ -1,57 +0,0 @@
#ifndef eoNSGA_II_Eval_h
#define eoNSGA_II_Eval_h
#include <moo/eoFrontSorter.h>
#include <moo/eoMOEval.h>
/** @brief Fast Elitist Non-Dominant Sorting Genetic Algorithm
Adapted from Deb, Agrawal, Pratab and Meyarivan: A Fast Elitist
Non-Dominant Sorting Genetic Algorithm for MultiObjective
Optimization: NSGA-II KanGAL Report No. 200001
*/
namespace nsga2 {
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, std::vector<double>& worths);
}
template <class EOT>
class eoNSGA_II_Eval : public eoMOEval<EOT>
{
public:
eoNSGA_II_Eval(eoEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
eoNSGA_II_Eval(eoPopEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
virtual void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
this->eval(parents, offspring);
std::vector<EOT*> pop;
pop.reserve(parents.size() + offspring.size());
for (unsigned i = 0; i < parents.size(); ++i) pop.push_back(&parents[i]);
for (unsigned i = 0; i < offspring.size(); ++i) pop.push_back(&offspring[i]);
typename eoFrontSorter<EOT>::front_t front = sorter(pop);
// calculate worths
std::vector<double> worths(pop.size());
for (unsigned i = 0; i < front.size(); ++i) {
nsga2::assign_worths(front[i], front.size() - i, worths);
}
// set worths
for (unsigned i = 0; i < pop.size(); ++i) {
pop[i]->fitnessReference().setWorth( worths[i]);
}
}
eoFrontSorter<EOT> sorter;
private:
};
#endif

View file

@ -1,228 +0,0 @@
#include <limits>
#include <moo/eoNSGA_IIa_Eval.h>
namespace nsga2a {
double calc_distance(const std::vector<double>& f1, const std::vector<double>& f2) {
double dist = 0;
for (unsigned i = 0; i < f1.size(); ++i) {
double d = (f1[i] - f2[i]);
dist += pow(fabs(d), 1./2);
//dist += pow(fabs(d), 2.0);
}
return dist;
}
unsigned assign_worths(std::vector<detail::FitnessInfo> front, unsigned rank, std::vector<double>& worths) {
unsigned nDim = front[0].fitness.size();
// find boundary points
std::vector<unsigned> processed(nDim);
for (unsigned i = 1; i < front.size(); ++i) {
for (unsigned dim = 0; dim < nDim; ++dim) {
if (front[i].fitness[dim] > front[processed[dim]].fitness[dim]) {
processed[dim] = i;
}
}
}
// assign fitness to processed and store in boundaries
std::vector<detail::FitnessInfo> boundaries;
for (unsigned i = 0; i < processed.size(); ++i) {
worths[ front[ processed[i] ].index] = rank;
//cout << "Boundary " << i << ' ' << front[processed[i]].index << ' ' << parents[ front[ processed[i] ].index]->fitness() << endl;
boundaries.push_back( front[ processed[i] ] );
}
rank--;
// clean up processed (make unique)
sort(processed.begin(), processed.end()); // swap out last first
for (unsigned i = 1; i < processed.size(); ++i) {
if (processed[i] == processed[i-1]) {
std::swap(processed[i], processed.back());
processed.pop_back();
--i;
}
}
// remove boundaries from front
while (processed.size()) {
unsigned idx = processed.back();
//std::cout << idx << ' ' ;
processed.pop_back();
std::swap(front.back(), front[idx]);
front.pop_back();
}
//std::cout << std::endl;
// calculate distances
std::vector<double> distances(front.size(), std::numeric_limits<double>::infinity());
unsigned selected = 0;
// select based on maximum distance to nearest processed point
for (unsigned i = 0; i < front.size(); ++i) {
for (unsigned k = 0; k < boundaries.size(); ++k) {
double d = calc_distance( front[i].fitness, boundaries[k].fitness);
if (d < distances[i]) {
distances[i] = d;
}
}
if (distances[i] > distances[selected]) {
selected = i;
}
}
while (!front.empty()) {
detail::FitnessInfo last = front[selected];
std::swap(front[selected], front.back());
front.pop_back();
std::swap(distances[selected], distances.back());
distances.pop_back();
// set worth
worths[last.index] = rank--;
if (front.empty()) break;
selected = 0;
for (unsigned i = 0; i < front.size(); ++i) {
double d = calc_distance(front[i].fitness, last.fitness);
if (d < distances[i]) {
distances[i] = d;
}
if (distances[i] >= distances[selected]) {
selected = i;
}
}
}
return rank;
}
unsigned assign_worths2(std::vector<detail::FitnessInfo> front, unsigned rank, std::vector<double>& worths) {
unsigned nDim = front[0].fitness.size();
// find boundary points
std::vector<unsigned> processed(nDim);
for (unsigned i = 1; i < front.size(); ++i) {
for (unsigned dim = 0; dim < nDim; ++dim) {
if (front[i].fitness[dim] > front[processed[dim]].fitness[dim]) {
processed[dim] = i;
}
}
}
// assign fitness to processed and store in boundaries
std::vector<detail::FitnessInfo> boundaries;
for (unsigned i = 0; i < processed.size(); ++i) {
worths[ front[ processed[i] ].index] = rank;
//cout << "Boundary " << i << ' ' << front[processed[i]].index << ' ' << parents[ front[ processed[i] ].index]->fitness() << endl;
boundaries.push_back( front[ processed[i] ] );
}
rank--;
// clean up processed (make unique)
sort(processed.begin(), processed.end()); // swap out last first
for (unsigned i = 1; i < processed.size(); ++i) {
if (processed[i] == processed[i-1]) {
std::swap(processed[i], processed.back());
processed.pop_back();
--i;
}
}
// remove boundaries from front
while (processed.size()) {
unsigned idx = processed.back();
//std::cout << idx << ' ' ;
processed.pop_back();
std::swap(front.back(), front[idx]);
front.pop_back();
}
//std::cout << std::endl;
// calculate distances
std::vector< std::vector<double> > distances(front.size(), std::vector<double>(nDim, std::numeric_limits<double>::infinity()));
double bestsum = 0;
unsigned selected = 0;
// select based on maximum distance to nearest processed point
for (unsigned i = 0; i < front.size(); ++i) {
for (unsigned k = 0; k < boundaries.size(); ++k) {
for (unsigned dim = 0; dim < nDim; ++dim) {
double d = front[i].fitness[dim] - boundaries[k].fitness[dim];
if (d > 0 && d < distances[i][dim]) {
distances[i][dim] = d;
}
}
}
double sum = 0;
for (unsigned dim = 0; dim < nDim; ++dim) sum += distances[i][dim];
if (sum > bestsum) {
selected = i;
bestsum = sum;
}
}
while (!front.empty()) {
detail::FitnessInfo last = front[selected];
std::swap(front[selected], front.back());
front.pop_back();
std::swap(distances[selected], distances.back());
distances.pop_back();
// set worth
worths[last.index] = rank--;
if (front.empty()) break;
selected = 0;
bestsum = 0;
for (unsigned i = 0; i < front.size(); ++i) {
double sum = 0;
for (unsigned dim = 0; dim < nDim; ++dim) {
double d = front[i].fitness[dim] - last.fitness[dim];
if (d > 0 && d < distances[i][dim]) {
distances[i][dim] = d;
}
sum += distances[i][dim];
}
if (sum > bestsum) {
selected = i;
bestsum = sum;
}
}
}
return rank;
}
}

View file

@ -1,59 +0,0 @@
#ifndef eoNSGA_IIa_Eval_h
#define eoNSGA_IIa_Eval_h
#include <moo/eoFrontSorter.h>
#include <moo/eoMOEval.h>
#include <cassert>
/** @brief Fast Elitist Non-Dominant Sorting Genetic Algorithm
Variant of the NSGA-II, where the ranking is based on a top-down distance based mechanism ( O(n^2)! )
*/
namespace nsga2a {
extern unsigned assign_worths(std::vector<detail::FitnessInfo> front, unsigned rank, std::vector<double>& worths);
}
template <class EOT>
class eoNSGA_IIa_Eval : public eoMOEval<EOT>
{
public:
eoNSGA_IIa_Eval(eoEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
eoNSGA_IIa_Eval(eoPopEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval) {}
virtual void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
eval(parents, offspring);
std::vector<EOT*> pop;
pop.reserve(parents.size() + offspring.size());
for (unsigned i = 0; i < parents.size(); ++i) pop.push_back(&parents[i]);
for (unsigned i = 0; i < offspring.size(); ++i) {
pop.push_back(&offspring[i]);
}
typename eoFrontSorter<EOT>::front_t front = sorter(pop);
std::vector<double> worths(pop.size());
unsigned rank = pop.size();
for (unsigned i = 0; i < front.size(); ++i) {
rank = nsga2a::assign_worths(front[i], rank, worths);
}
for (unsigned i = 0; i < worths.size(); ++i) {
typename EOT::Fitness f = pop[i]->fitness();
f.setWorth(worths[i]);
pop[i]->fitness(f);
}
}
private:
eoFrontSorter<EOT> sorter;
// implementation
};
#endif

View file

@ -1,73 +0,0 @@
#ifndef __eoNSGA_I_Eval_h_
#define __eoNSGA_I_Eval_h_
#include <moo/eoFrontSorter.h>
#include <moo/eoMOEval.h>
/**
The original Non Dominated Sorting algorithm from Srinivas and Deb
*/
template <class EOT>
class eoNSGA_I_Eval : public eoMOEval<EOT>
{
public :
eoNSGA_I_Eval(double nicheWidth, eoEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval), nicheSize(nicheWidth) {}
eoNSGA_I_Eval(double nicheWidth, eoPopEvalFunc<EOT>& eval) : eoMOEval<EOT>(eval), nicheSize(nicheWidth) {}
virtual void operator()(eoPop<EOT>& parents, eoPop<EOT>& offspring) {
eval(parents, offspring);
std::vector<EOT*> pop;
pop.reserve(parents.size() + offspring.size());
for (unsigned i = 0; i < parents.size(); ++i) pop.push_back(&parents[i]);
for (unsigned i = 0; i < offspring.size(); ++i) pop.push_back(&offspring[i]);
typename eoFrontSorter<EOT>::front_t front = sorter(pop);
for (unsigned i = 0; i < front.size(); ++i) {
assign_worths(front[i], front.size() - i, pop);
}
}
private:
void assign_worths(const std::vector<detail::FitnessInfo>& front, unsigned rank, std::vector<EOT*>& parents) {
for (unsigned i = 0; i < front.size(); ++i)
{ // calculate whether the other points lie within the nice
double niche_count = 0;
for (unsigned j = 0; j < front.size(); ++j)
{
if (i == j)
continue;
double dist = 0.0;
for (unsigned k = 0; k < front[j].fitness.size(); ++k)
{
double d = front[i].fitness[k] - front[j].fitness[k];
dist += d*d;
}
if (dist < nicheSize)
{
niche_count += 1.0 - pow(dist / nicheSize,2.);
}
}
unsigned idx = front[i].index;
typename EOT::Fitness f = parents[idx]->fitness();
f.setWorth(rank + niche_count);
parents[ idx ]->fitness(f);
}
}
private :
double nicheSize;
eoFrontSorter<EOT> sorter;
};
#endif

View file

@ -1,236 +0,0 @@
#include <eo>
#include <moo/eoEpsMOEA.h>
#include <utils/eoFuncPtrStat.h>
using namespace std;
class MinimizingFitnessTraits
{
public :
static unsigned nObjectives() { return 2; }
static double direction(unsigned) { return -1; }
static double tol() { return 1e-9; }
static vector<double> eps;
};
vector<double> MinimizingFitnessTraits::eps(2, 0.1);
typedef eoMOFitness<MinimizingFitnessTraits> fitness_type;
const unsigned chromsize=5;
const double minval = -15;
const double maxval = 15;
struct eoDouble : public EO<fitness_type>
{
double value[chromsize];
};
class Mutate : public eoMonOp<eoDouble>
{
bool operator()(eoDouble& _eo)
{
for (unsigned i = 0; i < chromsize; ++i)
{
if (rng.flip(1./chromsize)) {
_eo.value[i] += rng.normal() * 0.1 * _eo.value[i];
if (_eo.value[i] < minval)
_eo.value[i] = minval;
else if (_eo.value[i] > maxval)
_eo.value[i] = maxval;
}
}
return true;
}
};
class Cross : public eoBinOp<eoDouble> {
bool operator()(eoDouble& _eo, const eoDouble& eo2)
{
for (unsigned i = 0; i < chromsize; ++i)
{
if (rng.flip(0.5)) {
_eo.value[i] = eo2.value[i];
}
}
return true;
}
};
class Eval : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
vector<double> x(_eo.value, _eo.value + chromsize);
fitness_type f(0.0);
for (unsigned i = 0; i < chromsize; ++i)
{
if (i < chromsize-1)
{
f[0] += -10.0 * exp(-0.2 * sqrt(x[i]*x[i] + x[i+1]*x[i+1]));
}
f[1] += pow(fabs(x[i]), 0.8) + 5 * pow(sin(x[i]),3.);
}
_eo.fitness(f);
}
};
class Eval2 : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
vector<double> x(_eo.value, _eo.value + chromsize);
fitness_type f;
for (unsigned i = 0; i < chromsize; ++i)
{
f[0] += x[i] * x[i];
}
f[1] =
3 * x[0] + 2 * x[1]
- x[2]/3 + 0.01*pow(x[3] - x[4], 3);
_eo.fitness(f);
}
};
class Eval3 : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
double x = _eo.value[0];
fitness_type f;
f[0] = x * x;
double y = x-10;
f[1] = y * y;
_eo.fitness(f);
}
};
class Init : public eoInit<eoDouble>
{
void operator()(eoDouble& _eo)
{
_eo.value[0] = rng.uniform();
double range = maxval - minval;
for (unsigned i = 1; i < chromsize; ++i)
_eo.value[i] = rng.uniform() * range + minval;
_eo.invalidate();
}
};
template <class EOT>
unsigned get_size(const eoPop<EOT>& pop) {
return pop.size();
}
template <class EOT>
unsigned counter(const eoPop<EOT>& pop) {
static unsigned c = 0;
return c++;
}
// Test pareto dominance and perf2worth, and while you're at it, test the eoGnuPlot monitor as well
void the_main(int argc, char* argv[])
{
Init init;
Eval eval;
Mutate mutate;
Cross cross;
eoParser parser(argc, argv);
eoState state;
unsigned num_gen = parser.createParam(unsigned(50), "num_gen", "number of generations to run", 'g').value();
unsigned pop_size = parser.createParam(unsigned(100), "pop_size", "population size", 'p').value();
eoPop<eoDouble> pop(pop_size, init);
// binary tournament selection
eoDetTournamentSelect<eoDouble> select;
// One general operator
eoProportionalOp<eoDouble> opsel;
opsel.add(mutate, 1.0);
opsel.add(cross, 1.0);
unsigned long generation = 0;
eoGenContinue<eoDouble> gen(num_gen, generation);
eoCheckPoint<eoDouble> cp(gen);
eoMOFitnessStat<eoDouble> fitness0(0, "FirstObjective");
eoMOFitnessStat<eoDouble> fitness1(1, "SecondObjective");
cp.add(fitness0);
cp.add(fitness1);
eoGnuplot1DSnapshot snapshot("pareto");
//snapshot.with(eoGnuplot::Points(3));
cp.add(snapshot);
snapshot.add(fitness0);
snapshot.add(fitness1);
eoGnuplot1DMonitor monitor("sizemon");
cp.add(monitor);
eoFuncPtrStat<eoDouble, unsigned> size(get_size<eoDouble>);
eoFuncPtrStat<eoDouble, unsigned> counterStat(counter<eoDouble>);
monitor.add(counterStat);
monitor.add(size);
cp.add(size);
cp.add(counterStat);
// the algo
eoEpsMOEA<eoDouble> ea(cp, eval, opsel, MinimizingFitnessTraits::eps );
if (parser.userNeedsHelp())
{
parser.printHelp(std::cout);
return;
}
ea(pop);
}
int main(int argc, char* argv[])
{
the_main(argc, argv);
return 0;
try
{
the_main(argc, argv);
}
catch (std::exception& e)
{
std::cout << "Exception thrown: " << e.what() << std::endl;
throw e; // make sure it does not pass the test
}
}
// Local Variables:
// mode: C++
// c-file-style: "Stroustrup"
// End:

View file

@ -1,228 +0,0 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <eo>
#include <moo/eoMOFitness.h>
#include <moo/eoNSGA_I_Eval.h>
#include <moo/eoNSGA_II_Eval.h>
#include <moo/eoNSGA_IIa_Eval.h>
using namespace std;
class MinimizingFitnessTraits
{
public :
static unsigned nObjectives() { return 2; }
static double direction(unsigned) { return -1; }
static double tol() { return 1e-9; }
};
typedef eoMOFitness<MinimizingFitnessTraits> fitness_type;
const unsigned chromsize=5;
const double minval = -15;
const double maxval = 15;
struct eoDouble : public EO<fitness_type>
{
double value[chromsize];
};
class Mutate : public eoMonOp<eoDouble>
{
bool operator()(eoDouble& _eo)
{
for (unsigned i = 0; i < chromsize; ++i)
{
if (rng.flip(1./chromsize))
_eo.value[i] += rng.normal() * 0.1 * _eo.value[i];
if (_eo.value[i] < minval)
_eo.value[i] = minval;
else if (_eo.value[i] > maxval)
_eo.value[i] = maxval;
}
return true;
}
};
class Cross : public eoBinOp<eoDouble> {
bool operator()(eoDouble& _eo, const eoDouble& eo2)
{
for (unsigned i = 0; i < chromsize; ++i)
{
if (rng.flip(0.5)) {
_eo.value[i] = eo2.value[i];
}
}
return true;
}
};
class Eval : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
vector<double> x(_eo.value, _eo.value + chromsize);
fitness_type f(0.0);
for (unsigned i = 0; i < chromsize; ++i)
{
if (i < chromsize-1)
{
f[0] += -10.0 * exp(-0.2 * sqrt(x[i]*x[i] + x[i+1]*x[i+1]));
}
f[1] += pow(fabs(x[i]), 0.8) + 5 * pow(sin(x[i]),3.);
}
_eo.fitness(f);
}
};
class Eval2 : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
vector<double> x(_eo.value, _eo.value + chromsize);
fitness_type f;
for (unsigned i = 0; i < chromsize; ++i)
{
f[0] += x[i] * x[i];
}
f[1] =
3 * x[0] + 2 * x[1]
- x[2]/3 + 0.01*pow(x[3] - x[4], 3);
_eo.fitness(f);
}
};
class Eval3 : public eoEvalFunc<eoDouble>
{
void operator()(eoDouble& _eo)
{
double x = _eo.value[0];
fitness_type f;
f[0] = x * x;
double y = x-10;
f[1] = y * y;
_eo.fitness(f);
}
};
class Init : public eoInit<eoDouble>
{
void operator()(eoDouble& _eo)
{
_eo.value[0] = rng.uniform();
double range = maxval - minval;
for (unsigned i = 1; i < chromsize; ++i)
_eo.value[i] = rng.uniform() * range + minval;
_eo.invalidate();
}
};
// Test pareto dominance and perf2worth, and while you're at it, test the eoGnuPlot monitor as well
void the_main(int argc, char* argv[])
{
Init init;
Eval simple_eval;
Mutate mutate;
Cross cross;
eoParser parser(argc, argv);
eoState state;
unsigned num_gen = parser.createParam(unsigned(50), "num_gen", "number of generations to run", 'g').value();
unsigned pop_size = parser.createParam(unsigned(100), "pop_size", "population size", 'p').value();
bool use_nsga1 = parser.createParam(false, "nsga1", "Use nsga 1").value();
bool use_nsga2a = parser.createParam(false, "nsga2a", "Use nsga 2a").value();
eoPop<eoDouble> pop(pop_size, init);
// binary tournament selection
eoDetTournamentSelect<eoDouble> select;
// One general operator
eoProportionalOp<eoDouble> opsel;
opsel.add(mutate, 1.0);
opsel.add(cross, 1.0);
// the breeder
eoGeneralBreeder<eoDouble> breeder(select, opsel);
// replacement
eoNSGA_IIa_Eval<eoDouble> nsga2a(simple_eval);
eoNSGA_II_Eval<eoDouble> nsga2(simple_eval);
eoNSGA_I_Eval<eoDouble> nsga1(0.1, simple_eval);
eoMOEval<eoDouble>& eval = use_nsga1 ? static_cast<eoMOEval<eoDouble>&>(nsga1) : (use_nsga2a? static_cast<eoMOEval<eoDouble>&>(nsga2a) : static_cast<eoMOEval<eoDouble>&>(nsga2));
eoPlusReplacement<eoDouble> replace;
unsigned long generation = 0;
eoGenContinue<eoDouble> gen(num_gen, generation);
eoCheckPoint<eoDouble> cp(gen);
eoMOFitnessStat<eoDouble> fitness0(0, "FirstObjective");
eoMOFitnessStat<eoDouble> fitness1(1, "SecondObjective");
cp.add(fitness0);
cp.add(fitness1);
#ifdef HAVE_GNUPLOT
eoGnuplot1DSnapshot snapshot("pareto");
//snapshot.with(eoGnuplot::Points(3));
cp.add(snapshot);
snapshot.add(fitness0);
snapshot.add(fitness1);
#endif
// the algo
eoEasyEA<eoDouble> ea(cp, eval, breeder, replace);
if (parser.userNeedsHelp())
{
parser.printHelp(std::cout);
return;
}
ea(pop);
}
int main(int argc, char* argv[])
{
the_main(argc, argv);
return 0;
try
{
the_main(argc, argv);
}
catch (std::exception& e)
{
std::cout << "Exception thrown: " << e.what() << std::endl;
throw e; // make sure it does not pass the test
}
}
// Local Variables:
// mode: C++
// c-file-style: "Stroustrup"
// End: