massive documentation update

This commit is contained in:
Johann Dreo 2012-07-19 17:23:41 +02:00
commit 7fed1ebf51
33 changed files with 399 additions and 181 deletions

View file

@ -771,7 +771,7 @@ COLS_IN_ALPHA_INDEX = 3
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
IGNORE_PREFIX = moeo
IGNORE_PREFIX = edo
#---------------------------------------------------------------------------
# configuration options related to the HTML output
@ -1273,13 +1273,13 @@ ENABLE_PREPROCESSING = YES
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
EXPAND_ONLY_PREDEF = NO
EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
@ -1307,14 +1307,14 @@ INCLUDE_FILE_PATTERNS =
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
PREDEFINED =
PREDEFINED = WITH_EIGEN
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED =
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all function-like macros that are alone

View file

@ -31,10 +31,23 @@ Authors:
#include <eoAlgo.h>
/** An EDO algorithm difffers from a canonical EO algorithm because it is
/**
@defgroup Algorithms Algorithms
In EDO, as in EO, an algorithm is a functor that takes one or several
solutions to an optimization problem as arguments, and iteratively modify
them with the help of operators.It differs from a canonical EO algorithm
because it is templatized on a edoDistrib rather than just an EOT.
@see eoAlgo
*/
/** An EDO algorithm differs from a canonical EO algorithm because it is
* templatized on a Distribution rather than just an EOT.
*
* Derivating from an eoAlgo, it should define an operator()( EOT sol )
*
* @ingroup Algorithms
*/
template < typename D >
class edoAlgo : public eoAlgo< typename D::EOType >

View file

@ -38,16 +38,25 @@ Authors:
#include "edoSampler.h"
#include "edoContinue.h"
//! edoEDA< D >
/** A generic stochastic search template for algorithms that need a distribution parameter.
*
* An adaptive algorithm will directly updates a distribution, it must thus be instanciated
* with an edoDistrib at hand. Thus, this distribution object should be instanciated appart.
* The reference to this distribution is generally also needed by at least one of the
* algorithm's operator, generally for algorithms that shares the same algorithms across
* operators and/or iterations.
*
* If you no operator needs to update the distribution, then it is simpler to use an
* edoAlgoStateless .
*
* @ingroup Algorithms
*/
template < typename EOD >
class edoAlgoAdaptive : public edoAlgo< EOD >
template < typename D >
class edoAlgoAdaptive : public edoAlgo< D >
{
public:
//! Alias for the type EOT
typedef typename EOD::EOType EOType;
typedef typename D::EOType EOType;
//! Alias for the atom type
typedef typename EOType::AtomType AtomType;
@ -61,7 +70,7 @@ public:
Takes algo operators, all are mandatory
\param distrib A distribution to use, if you want to update this parameter (e.gMA-ES) instead of replacing it (e.g. an EDA)
\param evaluation Evaluate a population
\param evaluator Evaluate a population
\param selector Selection of the best candidate solutions in the population
\param estimator Estimation of the distribution parameters
\param sampler Generate feasible solutions using the distribution
@ -70,14 +79,14 @@ public:
\param distribution_continuator Stopping criterion based on the distribution features
*/
edoAlgoAdaptive(
EOD & distrib,
D & distrib,
eoPopEvalFunc < EOType > & evaluator,
eoSelect< EOType > & selector,
edoEstimator< EOD > & estimator,
edoSampler< EOD > & sampler,
edoEstimator< D > & estimator,
edoSampler< D > & sampler,
eoReplacement< EOType > & replacor,
eoContinue< EOType > & pop_continuator,
edoContinue< EOD > & distribution_continuator
edoContinue< D > & distribution_continuator
) :
_distrib(distrib),
_evaluator(evaluator),
@ -96,7 +105,7 @@ public:
Takes algo operators, all are mandatory
\param distrib A distribution to use, if you want to update this parameter (e.gMA-ES) instead of replacing it (e.g. an EDA)
\param evaluation Evaluate a population
\param evaluator Evaluate a population
\param selector Selection of the best candidate solutions in the population
\param estimator Estimation of the distribution parameters
\param sampler Generate feasible solutions using the distribution
@ -104,11 +113,11 @@ public:
\param pop_continuator Stopping criterion based on the population features
*/
edoAlgoAdaptive (
EOD & distrib,
D & distrib,
eoPopEvalFunc < EOType > & evaluator,
eoSelect< EOType > & selector,
edoEstimator< EOD > & estimator,
edoSampler< EOD > & sampler,
edoEstimator< D > & estimator,
edoSampler< D > & sampler,
eoReplacement< EOType > & replacor,
eoContinue< EOType > & pop_continuator
) :
@ -172,7 +181,7 @@ public:
protected:
//! The distribution that you want to update
EOD & _distrib;
D & _distrib;
//! A full evaluation function.
eoPopEvalFunc<EOType> & _evaluator;
@ -181,10 +190,10 @@ protected:
eoSelect<EOType> & _selector;
//! A EOType estimator. It is going to estimate distribution parameters.
edoEstimator<EOD> & _estimator;
edoEstimator<D> & _estimator;
//! A D sampler
edoSampler<EOD> & _sampler;
edoSampler<D> & _sampler;
//! A EOType replacor
eoReplacement<EOType> & _replacor;
@ -193,10 +202,10 @@ protected:
eoContinue<EOType> & _pop_continuator;
//! A D continuator that always return true
edoDummyContinue<EOD> _dummy_continue;
edoDummyContinue<D> _dummy_continue;
//! A D continuator
edoContinue<EOD> & _distribution_continuator;
edoContinue<D> & _distribution_continuator;
};

View file

@ -35,13 +35,15 @@ Authors:
* This use a default dummy distribution, for algorithms willing to replace it instead of updating
* Thus we can instanciate _distrib on this and replace it at the first iteration with an estimator.
* This is why an edoDistrib must have an empty constructor.
*
* @ingroup Algorithms
*/
template < typename EOD >
class edoAlgoStateless : public edoAlgoAdaptive< EOD >
template < typename D >
class edoAlgoStateless : public edoAlgoAdaptive< D >
{
public:
//! Alias for the type EOT
typedef typename EOD::EOType EOType;
typedef typename D::EOType EOType;
//! Alias for the atom type
typedef typename EOType::AtomType AtomType;
@ -52,7 +54,7 @@ public:
public:
/** Full constructor
\param evaluation Evaluate a population
\param evaluator Evaluate a population
\param selector Selection of the best candidate solutions in the population
\param estimator Estimation of the distribution parameters
\param sampler Generate feasible solutions using the distribution
@ -63,18 +65,18 @@ public:
edoAlgoStateless(
eoPopEvalFunc < EOType > & evaluator,
eoSelect< EOType > & selector,
edoEstimator< EOD > & estimator,
edoSampler< EOD > & sampler,
edoEstimator< D > & estimator,
edoSampler< D > & sampler,
eoReplacement< EOType > & replacor,
eoContinue< EOType > & pop_continuator,
edoContinue< EOD > & distribution_continuator
edoContinue< D > & distribution_continuator
) :
edoAlgoAdaptive<EOD>( *(new EOD), evaluator, selector, estimator, sampler, replacor, pop_continuator, distribution_continuator)
edoAlgoAdaptive<D>( *(new D), evaluator, selector, estimator, sampler, replacor, pop_continuator, distribution_continuator)
{}
/** Constructor without an edoContinue
\param evaluation Evaluate a population
\param evaluator Evaluate a population
\param selector Selection of the best candidate solutions in the population
\param estimator Estimation of the distribution parameters
\param sampler Generate feasible solutions using the distribution
@ -84,12 +86,12 @@ public:
edoAlgoStateless (
eoPopEvalFunc < EOType > & evaluator,
eoSelect< EOType > & selector,
edoEstimator< EOD > & estimator,
edoSampler< EOD > & sampler,
edoEstimator< D > & estimator,
edoSampler< D > & sampler,
eoReplacement< EOType > & replacor,
eoContinue< EOType > & pop_continuator
) :
edoAlgoAdaptive<EOD>( *(new EOD), evaluator, selector, estimator, sampler, replacor, pop_continuator)
edoAlgoAdaptive<D>( *(new D), evaluator, selector, estimator, sampler, replacor, pop_continuator)
{}
~edoAlgoStateless()

View file

@ -34,6 +34,7 @@ Authors:
* a given set of bounds (typically an hypercube).
*
* @ingroup Repairers
* @ingroup Core
*/
template < typename EOT >
class edoBounder : public edoRepairer< EOT >

View file

@ -31,8 +31,13 @@ Authors:
#include <eoFunctor.h>
#include <eoPersistent.h>
//! edoContinue< D > class fitted to Distribution Object library
/** A continuator that check the state of an edoDistrib
*
* @see eoContinue
*
* @ingroup Continuators
* @ingroup Core
*/
template < typename D >
class edoContinue : public eoUF< const D&, bool >, public eoPersistent
{

View file

@ -30,8 +30,24 @@ Authors:
#include <eoFunctor.h>
//! edoDistrib< EOT >
/** @defgroup Core
*
* Core functors that made the basis of EDO.
*/
/** @defgroup Distributions Distributions
*
* A distribution is a data structure that holds sufficient informations to
* describe a probability density function by a set of parameters.
*
* It is passed across EDO operators and can be updated or manipulated by them.
*/
/** Base class for distributions. This is really just an empty shell.
*
* @ingroup Distributions
* @ingroup Core
*/
template < typename EOT >
class edoDistrib : public eoFunctorBase
{

View file

@ -31,8 +31,20 @@ Authors:
#include <eoPop.h>
#include <eoFunctor.h>
//! edoEstimator< D >
/** @defgroup Estimators Estimators
*
* Estimators takes an eoPop and estimates the parameters of a distributions
* (defined as an hypothesis) from it.
*/
/** Base class for estimators.
*
* Estimators takes an eoPop and estimates the parameters of a distributions
* (defined as an hypothesis) from it.
*
* @ingroup Estimators
* @ingroup Core
*/
template < typename D >
class edoEstimator : public eoUF< eoPop< typename D::EOType >&, D >
{

View file

@ -33,23 +33,26 @@ Authors:
#include "edoEstimator.h"
/** An interface that explicits the needs for a permanent distribution
/** An interface that explicits the needs for a permanent distribution
* that will be updated by operators.
*
* @ingroup Estimators
* @ingroup Core
*/
template < typename EOD >
class edoEstimatorAdaptive : public edoEstimator<EOD>
template < typename D >
class edoEstimatorAdaptive : public edoEstimator<D>
{
public:
typedef typename EOD::EOType EOType;
typedef typename D::EOType EOType;
edoEstimatorAdaptive<EOD>( EOD& distrib ) : _distrib(distrib) {}
edoEstimatorAdaptive<D>( D& distrib ) : _distrib(distrib) {}
// virtual D operator() ( eoPop< EOT >& )=0 (provided by eoUF< A1, R >)
EOD & distribution() const { return _distrib; }
D & distribution() const { return _distrib; }
protected:
EOD & _distrib;
D & _distrib;
};
#endif // !_edoEstimatorAdaptive_h

View file

@ -40,17 +40,20 @@ Authors:
/** An estimator that works on adaptive normal distributions, basically the heart of the CMA-ES algorithm.
*
* @ingroup Estimators
* @ingroup CMAES
* @ingroup Adaptivenormal
*/
template< typename EOT, typename EOD = edoNormalAdaptive<EOT> >
class edoEstimatorNormalAdaptive : public edoEstimatorAdaptive< EOD >
template< typename EOT, typename D = edoNormalAdaptive<EOT> >
class edoEstimatorNormalAdaptive : public edoEstimatorAdaptive< D >
{
public:
typedef typename EOT::AtomType AtomType;
typedef typename EOD::Vector Vector; // column vectors @see edoNormalAdaptive
typedef typename EOD::Matrix Matrix;
typedef typename D::Vector Vector; // column vectors @see edoNormalAdaptive
typedef typename D::Matrix Matrix;
edoEstimatorNormalAdaptive( EOD& distrib ) :
edoEstimatorAdaptive<EOD>( distrib ),
edoEstimatorNormalAdaptive( D& distrib ) :
edoEstimatorAdaptive<D>( distrib ),
_calls(0),
_eigeneval(0)
{}
@ -133,7 +136,7 @@ public:
// shortcut to the referenced distribution
EOD& d = this->distribution();
D& d = this->distribution();
// C^-1/2
Matrix invsqrtC =
@ -226,12 +229,12 @@ public:
Eigen::SelfAdjointEigenSolver<Matrix> eigensolver( d.covar() ); // FIXME use JacobiSVD?
d.coord_sys( eigensolver.eigenvectors() );
Matrix D = eigensolver.eigenvalues().asDiagonal();
assert( D.innerSize() == N && D.outerSize() == N );
Matrix mD = eigensolver.eigenvalues().asDiagonal();
assert( mD.innerSize() == N && mD.outerSize() == N );
// from variance to standard deviations
D.cwiseSqrt();
d.scaling( D.diagonal() );
mD.cwiseSqrt();
d.scaling( mD.diagonal() );
}
return d;
@ -243,7 +246,7 @@ protected:
unsigned int _eigeneval;
// EOD & distribution() inherited from edoEstimatorAdaptive
// D & distribution() inherited from edoEstimatorAdaptive
};
#endif // WITH_EIGEN

View file

@ -31,8 +31,11 @@ Authors:
#include "edoEstimator.h"
#include "edoNormalMono.h"
//! edoEstimatorNormalMono< EOT >
/** An estimator for edoNormalMono
*
* @ingroup Estimators
* @ingroup Mononormal
*/
template < typename EOT >
class edoEstimatorNormalMono : public edoEstimator< edoNormalMono< EOT > >
{

View file

@ -34,11 +34,31 @@ Authors:
#include "edoNormalMulti.h"
#ifdef WITH_BOOST
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/lu.hpp>
namespace ublas = boost::numeric::ublas;
#else
#ifdef WITH_EIGEN
#include <Eigen/Dense>
#endif // WITH_EIGEN
#endif // WITH_BOOST
//! edoEstimatorNormalMulti< EOT >
/** An estimator for edoNormalMulti
*
* Exists in two implementations, using either
* <a href="http://www.boost.org/doc/libs/1_50_0/libs/numeric/ublas/doc/index.htm">Boost::uBLAS</a> (if compiled WITH_BOOST)
* or <a href="http://eigen.tuxfamily.org">Eigen3</a> (WITH_EIGEN).
*
* @ingroup Estimators
* @ingroup EMNA
* @ingroup Multinormal
*/
template < typename EOT >
class edoEstimatorNormalMulti : public edoEstimator< edoNormalMulti< EOT > >
{
#ifdef WITH_BOOST
public:
class CovMatrix
{
@ -154,17 +174,13 @@ public:
#else
#ifdef WITH_EIGEN
//! edoEstimatorNormalMulti< EOT >
template < typename EOT, typename EOD = edoNormalMulti<EOT> >
class edoEstimatorNormalMulti : public edoEstimator< EOD >
{
public:
class CovMatrix
{
public:
typedef typename EOT::AtomType AtomType;
typedef typename EOD::Vector Vector;
typedef typename EOD::Matrix Matrix;
typedef typename D::Vector Vector;
typedef typename D::Matrix Matrix;
CovMatrix( const eoPop< EOT >& pop )
{
@ -233,8 +249,8 @@ public:
return edoNormalMulti< EOT >( cov.get_mean(), cov.get_varcovar() );
}
};
#endif // WITH_EIGEN
#endif // WITH_BOOST
}; // class edoNormalMulti
#endif // !_edoEstimatorNormalMulti_h

View file

@ -31,42 +31,42 @@ Authors:
#include "edoEstimator.h"
#include "edoUniform.h"
// TODO: calcule de la moyenne + covariance dans une classe derivee
//! edoEstimatorUniform
/** An estimator for edoUniform
*
* @ingroup Estimators
*/
template < typename EOT >
class edoEstimatorUniform : public edoEstimator< edoUniform< EOT > >
{
public:
edoUniform< EOT > operator()(eoPop<EOT>& pop)
{
unsigned int size = pop.size();
unsigned int size = pop.size();
assert(size > 0);
assert(size > 0);
EOT min = pop[0];
EOT max = pop[0];
EOT min = pop[0];
EOT max = pop[0];
for (unsigned int i = 1; i < size; ++i)
{
unsigned int size = pop[i].size();
for (unsigned int i = 1; i < size; ++i)
{
unsigned int size = pop[i].size();
assert(size > 0);
assert(size > 0);
// possibilité d'utiliser std::min_element et std::max_element mais exige 2 pass au lieu d'1.
// possibilité d'utiliser std::min_element et std::max_element mais exige 2 pass au lieu d'1.
for (unsigned int d = 0; d < size; ++d)
{
if (pop[i][d] < min[d])
min[d] = pop[i][d];
for (unsigned int d = 0; d < size; ++d)
{
if (pop[i][d] < min[d])
min[d] = pop[i][d];
if (pop[i][d] > max[d])
max[d] = pop[i][d];
}
}
if (pop[i][d] > max[d])
max[d] = pop[i][d];
}
}
return edoUniform< EOT >(min, max);
return edoUniform< EOT >(min, max);
}
};

View file

@ -28,8 +28,16 @@ Authors:
#ifndef _edoModifier_h
#define _edoModifier_h
//! edoModifier< D >
/** @defgroup Modifiers
*
* A set of classes that arbitrarly modify a given distribution.
*/
/** A functor to arbitrarly modify a distribution
*
* @ingroup Core
* @ingroup Modifiers
*/
template < typename D >
class edoModifier
{

View file

@ -33,8 +33,10 @@ Authors:
#include "edoModifier.h"
//! edoModifierDispersion< D >
/** An semantic pseudo-interface for modifiers that updates dispersion parameters (like variance).
*
* @ingroup Modifiers
*/
template < typename D >
class edoModifierDispersion : public edoModifier< D >, public eoBF< D&, eoPop< typename D::EOType >&, void >
{

View file

@ -32,8 +32,11 @@ Authors:
#include "edoModifier.h"
//! edoModifierMass< D >
/** An semantic pseudo-interface for modifiers that updates mass parameters (like mean).
*
* @ingroup Modifiers
*/
template < typename D >
class edoModifierMass : public edoModifier< D >, public eoBF< D&, typename D::EOType&, void >
{

View file

@ -35,6 +35,23 @@ Authors:
#include <Eigen/Dense>
/** @defgroup CMAES CMAES
*
* CMA-ES (Covariance Matrix Adaptation Evolution Strategy) is a stochastic,
* derivative-free methods for numerical optimization of non-linear or
* non-convex continuous optimization problems.
*
* @ingroup Algorithms
*/
/** @defgroup Adaptivenormal Adaptive normal
*
* A multi-variate normal distribution that can be updated via several components.
* This is the data structure on which works the CMA-ES algorithm.
*
* @ingroup Distributions
*/
/** A normal distribution that can be updated via several components. This is the data structure on which works the CMA-ES
* algorithm.
*
@ -44,6 +61,12 @@ Authors:
* The distribution is defined by its mean, its covariance matrix (which can be decomposed in its eigen vectors and
* values), a scaling factor (sigma) and the so-called evolution paths for the covariance and sigma.
* evolution paths.
*
* NOTE: this is only available as an Eigen3 implementation (built WITH_EIGEN).
*
* @ingroup Distributions
* @ingroup CMAES
* @ingroup Adaptivenormal
*/
template < typename EOT >
class edoNormalAdaptive : public edoDistrib< EOT >
@ -126,6 +149,8 @@ private:
Vector _p_s; // evolution path for sigma
};
#else
#pragma message "WARNING: there is no Boost::uBLAS implementation of edoNormalAdaptive, build WITH_EIGEN if you need it."
#endif // WITH_EIGEN
#endif // !_edoNormalAdaptive_h

View file

@ -30,23 +30,34 @@ Authors:
#include "edoDistrib.h"
//! edoNormalMono< EOT >
/** @defgroup Mononormal Normal
* A normal (Gaussian) distribution that only model variances of variables.
*
* @ingroup Distributions
*/
/** A normal (Gaussian) distribution that only model variances of variables.
*
* This is basically a mean vector and a variances vector. Do not model co-variances.
*
* @ingroup Distributions
* @ingroup Mononormal
*/
template < typename EOT >
class edoNormalMono : public edoDistrib< EOT >
{
public:
edoNormalMono( const EOT& mean, const EOT& variance )
: _mean(mean), _variance(variance)
: _mean(mean), _variance(variance)
{
assert(_mean.size() > 0);
assert(_mean.size() == _variance.size());
assert(_mean.size() > 0);
assert(_mean.size() == _variance.size());
}
unsigned int size()
{
assert(_mean.size() == _variance.size());
return _mean.size();
assert(_mean.size() == _variance.size());
return _mean.size();
}
EOT mean(){return _mean;}

View file

@ -31,8 +31,11 @@ Authors:
#include "edoModifierMass.h"
#include "edoNormalMono.h"
//! edoNormalMonoCenter< EOT >
/** Change a distribution's mean for a given EOT
*
* @ingroup Modifiers
* @ingroup Mononormal
*/
template < typename EOT >
class edoNormalMonoCenter : public edoModifierMass< edoNormalMono< EOT > >
{
@ -41,7 +44,7 @@ public:
void operator() ( edoNormalMono< EOT >& distrib, EOT& mass )
{
distrib.mean() = mass;
distrib.mean() = mass;
}
};

View file

@ -31,17 +31,49 @@ Copyright (C) 2010 Thales group
#include "edoDistrib.h"
#ifdef WITH_BOOST
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/lu.hpp>
namespace ublas = boost::numeric::ublas;
#else
#ifdef WITH_EIGEN
#include <Eigen/Dense>
#endif // WITH_EIGEN
#endif // WITH_BOOST
//! edoNormalMulti< EOT >
/** @defgroup EMNA
*
* Estimation of Multivariate Normal Algorithm (EMNA) is a stochastic,
* derivative-free methods for numerical optimization of non-linear or
* non-convex continuous optimization problems.
*
* @ingroup Algorithms
*/
/** @defgroup Multinormal Multivariate normal
*
* Distribution that model co-variances between variables.
*
* @ingroup Distributions
*/
/** A multi-normal distribution, that models co-variances.
*
* Defines a mean vector and a co-variances matrix.
*
* Exists in two implementations, using either
* <a href="http://www.boost.org/doc/libs/1_50_0/libs/numeric/ublas/doc/index.htm">Boost::uBLAS</a> (if compiled WITH_BOOST)
* or <a href="http://eigen.tuxfamily.org">Eigen3</a> (WITH_EIGEN).
*
* @ingroup Distributions
* @ingroup EMNA
* @ingroup Multinormal
*/
template < typename EOT >
class edoNormalMulti : public edoDistrib< EOT >
{
#ifdef WITH_BOOST
public:
typedef typename EOT::AtomType AtomType;
@ -79,17 +111,11 @@ public:
private:
ublas::vector< AtomType > _mean;
ublas::symmetric_matrix< AtomType, ublas::lower > _varcovar;
};
#else
#ifdef WITH_EIGEN
#include <Eigen/Dense>
template < typename EOT >
class edoNormalMulti : public edoDistrib< EOT >
{
public:
typedef typename EOT::AtomType AtomType;
typedef Eigen::Matrix< AtomType, Eigen::Dynamic, 1> Vector;
@ -128,11 +154,10 @@ public:
private:
Vector _mean;
Matrix _varcovar;
};
#endif // WITH_EIGEN
#endif // WITH_BOOST
}; // class edoNormalMulti
#endif // !_edoNormalMulti_h

Some files were not shown because too many files have changed in this diff Show more