Unverified Commit 70e1b4dd authored by Alexander Alekhin's avatar Alexander Alekhin Committed by GitHub

Merge pull request #10319 from catree:move_SimulatedAnnealingSolver_Impl_cpp

Move SimulatedAnnealingSolver::Impl in cpp file
parents bab86d65 aef30191
...@@ -1528,6 +1528,9 @@ public: ...@@ -1528,6 +1528,9 @@ public:
/** @copybrief getAnnealItePerStep @see getAnnealItePerStep */ /** @copybrief getAnnealItePerStep @see getAnnealItePerStep */
CV_WRAP void setAnnealItePerStep(int val); CV_WRAP void setAnnealItePerStep(int val);
/** @brief Set/initialize anneal RNG */
void setAnnealEnergyRNG(const RNG& rng);
/** possible activation functions */ /** possible activation functions */
enum ActivationFunctions { enum ActivationFunctions {
/** Identity function: \f$f(x)=x\f$ */ /** Identity function: \f$f(x)=x\f$ */
...@@ -1875,101 +1878,102 @@ class CV_EXPORTS_W ANN_MLP_ANNEAL : public ANN_MLP ...@@ -1875,101 +1878,102 @@ class CV_EXPORTS_W ANN_MLP_ANNEAL : public ANN_MLP
{ {
public: public:
/** @see setAnnealInitialT */ /** @see setAnnealInitialT */
CV_WRAP virtual double getAnnealInitialT() const; CV_WRAP virtual double getAnnealInitialT() const = 0;
/** @copybrief getAnnealInitialT @see getAnnealInitialT */ /** @copybrief getAnnealInitialT @see getAnnealInitialT */
CV_WRAP virtual void setAnnealInitialT(double val); CV_WRAP virtual void setAnnealInitialT(double val) = 0;
/** ANNEAL: Update final temperature. /** ANNEAL: Update final temperature.
It must be \>=0 and less than initialT. Default value is 0.1.*/ It must be \>=0 and less than initialT. Default value is 0.1.*/
/** @see setAnnealFinalT */ /** @see setAnnealFinalT */
CV_WRAP virtual double getAnnealFinalT() const; CV_WRAP virtual double getAnnealFinalT() const = 0;
/** @copybrief getAnnealFinalT @see getAnnealFinalT */ /** @copybrief getAnnealFinalT @see getAnnealFinalT */
CV_WRAP virtual void setAnnealFinalT(double val); CV_WRAP virtual void setAnnealFinalT(double val) = 0;
/** ANNEAL: Update cooling ratio. /** ANNEAL: Update cooling ratio.
It must be \>0 and less than 1. Default value is 0.95.*/ It must be \>0 and less than 1. Default value is 0.95.*/
/** @see setAnnealCoolingRatio */ /** @see setAnnealCoolingRatio */
CV_WRAP virtual double getAnnealCoolingRatio() const; CV_WRAP virtual double getAnnealCoolingRatio() const = 0;
/** @copybrief getAnnealCoolingRatio @see getAnnealCoolingRatio */ /** @copybrief getAnnealCoolingRatio @see getAnnealCoolingRatio */
CV_WRAP virtual void setAnnealCoolingRatio(double val); CV_WRAP virtual void setAnnealCoolingRatio(double val) = 0;
/** ANNEAL: Update iteration per step. /** ANNEAL: Update iteration per step.
It must be \>0 . Default value is 10.*/ It must be \>0 . Default value is 10.*/
/** @see setAnnealItePerStep */ /** @see setAnnealItePerStep */
CV_WRAP virtual int getAnnealItePerStep() const; CV_WRAP virtual int getAnnealItePerStep() const = 0;
/** @copybrief getAnnealItePerStep @see getAnnealItePerStep */ /** @copybrief getAnnealItePerStep @see getAnnealItePerStep */
CV_WRAP virtual void setAnnealItePerStep(int val); CV_WRAP virtual void setAnnealItePerStep(int val) = 0;
/** @brief Creates empty model
Use StatModel::train to train the model, Algorithm::load\<ANN_MLP\>(filename) to load the pre-trained model.
Note that the train method has optional flags: ANN_MLP::TrainFlags.
*/
// CV_WRAP static Ptr<ANN_MLP> create();
/** @brief Set/initialize anneal RNG */
virtual void setAnnealEnergyRNG(const RNG& rng) = 0;
}; };
/****************************************************************************************\ /****************************************************************************************\
* Simulated annealing solver * * Simulated annealing solver *
\****************************************************************************************/ \****************************************************************************************/
/** @brief The class defines interface for system state used in simulated annealing optimization algorithm.
@cite Kirkpatrick83 for details
*/
class CV_EXPORTS SimulatedAnnealingSolverSystem
{
protected:
inline SimulatedAnnealingSolverSystem() {}
public:
virtual ~SimulatedAnnealingSolverSystem() {}
/** Give energy value for a state of system.*/
virtual double energy() const = 0;
/** Function which change the state of system (random pertubation).*/
virtual void changeState() = 0;
/** Function to reverse to the previous state. Can be called once only after changeState(). */
virtual void reverseState() = 0;
};
/** @brief The class implements simulated annealing for optimization. /** @brief The class implements simulated annealing for optimization.
*
@cite Kirkpatrick83 for details @cite Kirkpatrick83 for details
*/ */
class CV_EXPORTS SimulatedAnnealingSolver : public Algorithm class CV_EXPORTS SimulatedAnnealingSolver : public Algorithm
{ {
public: public:
SimulatedAnnealingSolver() { init(); }; SimulatedAnnealingSolver(const Ptr<SimulatedAnnealingSolverSystem>& system);
~SimulatedAnnealingSolver(); inline ~SimulatedAnnealingSolver() { release(); }
/** Give energy value for a state of system.*/
virtual double energy() =0; /** Simulated annealing procedure. */
/** Function which change the state of system (random pertubation).*/
virtual void changedState() = 0;
/** Function to reverse to the previous state.*/
virtual void reverseChangedState() = 0;
/** Simulated annealing procedure. */
int run(); int run();
/** Set intial temperature of simulated annealing procedure. /** Set/initialize RNG (energy).
*@param x new initial temperature. x\>0 @param rng new RNG
*/
void setEnergyRNG(const RNG& rng);
/** Set initial temperature of simulated annealing procedure.
@param x new initial temperature. x\>0
*/ */
void setInitialTemperature(double x); void setInitialTemperature(double x);
/** Set final temperature of simulated annealing procedure. /** Set final temperature of simulated annealing procedure.
*@param x new final temperature value. 0\<x\<initial temperature @param x new final temperature value. 0\<x\<initial temperature
*/ */
void setFinalTemperature(double x); void setFinalTemperature(double x);
/** Get final temperature of simulated annealing procedure. */
double getFinalTemperature(); double getFinalTemperature();
/** Set setCoolingRatio of simulated annealing procedure : T(t) = coolingRatio * T(t-1). /** Set setCoolingRatio of simulated annealing procedure : T(t) = coolingRatio * T(t-1).
* @param x new cooling ratio value. 0\<x\<1 @param x new cooling ratio value. 0\<x\<1
*/ */
void setCoolingRatio(double x); void setCoolingRatio(double x);
/** Set number iteration per temperature step. /** Set number iteration per temperature step.
* @param ite number of iteration per temperature step ite \> 0 @param ite number of iteration per temperature step ite \> 0
*/ */
void setIterPerStep(int ite); void setIterPerStep(int ite);
struct Impl;
protected : void release();
void init(); SimulatedAnnealingSolver(const SimulatedAnnealingSolver&);
SimulatedAnnealingSolver& operator=(const SimulatedAnnealingSolver&);
struct Impl; friend struct Impl;
protected:
Impl* impl; Impl* impl;
}; };
struct SimulatedAnnealingSolver::Impl
{
RNG rEnergy;
double coolingRatio;
double initialT;
double finalT;
int iterPerStep;
Impl()
{
initialT = 2;
finalT = 0.1;
coolingRatio = 0.95;
iterPerStep = 100;
refcount = 1;
}
int refcount;
~Impl() { refcount--;CV_Assert(refcount==0); }
};
//! @} ml //! @} ml
......
...@@ -42,6 +42,40 @@ ...@@ -42,6 +42,40 @@
namespace cv { namespace ml { namespace cv { namespace ml {
struct SimulatedAnnealingSolver::Impl
{
int refcount;
const Ptr<SimulatedAnnealingSolverSystem> systemPtr;
SimulatedAnnealingSolverSystem& system;
RNG rEnergy;
double coolingRatio;
double initialT;
double finalT;
int iterPerStep;
Impl(const Ptr<SimulatedAnnealingSolverSystem>& s) :
refcount(1),
systemPtr(s),
system(*(s.get())),
rEnergy(12345)
{
CV_Assert(!systemPtr.empty());
initialT = 2;
finalT = 0.1;
coolingRatio = 0.95;
iterPerStep = 100;
}
inline double energy() { return system.energy(); }
inline void changeState() { system.changeState(); }
inline void reverseState() { system.reverseState(); }
void addref() { CV_XADD(&refcount, 1); }
void release() { if (CV_XADD(&refcount, -1) == 1) delete this; }
protected:
virtual ~Impl() { CV_Assert(refcount==0); }
};
struct AnnParams struct AnnParams
{ {
...@@ -53,7 +87,7 @@ struct AnnParams ...@@ -53,7 +87,7 @@ struct AnnParams
rpDW0 = 0.1; rpDWPlus = 1.2; rpDWMinus = 0.5; rpDW0 = 0.1; rpDWPlus = 1.2; rpDWMinus = 0.5;
rpDWMin = FLT_EPSILON; rpDWMax = 50.; rpDWMin = FLT_EPSILON; rpDWMax = 50.;
initialT=10;finalT=0.1,coolingRatio=0.95;itePerStep=10; initialT=10;finalT=0.1,coolingRatio=0.95;itePerStep=10;
rEnergy = cv::RNG(12345);
} }
TermCriteria termCrit; TermCriteria termCrit;
...@@ -72,6 +106,7 @@ struct AnnParams ...@@ -72,6 +106,7 @@ struct AnnParams
double finalT; double finalT;
double coolingRatio; double coolingRatio;
int itePerStep; int itePerStep;
RNG rEnergy;
}; };
template <typename T> template <typename T>
...@@ -80,48 +115,60 @@ inline T inBounds(T val, T min_val, T max_val) ...@@ -80,48 +115,60 @@ inline T inBounds(T val, T min_val, T max_val)
return std::min(std::max(val, min_val), max_val); return std::min(std::max(val, min_val), max_val);
} }
SimulatedAnnealingSolver::~SimulatedAnnealingSolver() SimulatedAnnealingSolver::SimulatedAnnealingSolver(const Ptr<SimulatedAnnealingSolverSystem>& system)
{ {
if (impl) delete impl; impl = new Impl(system);
} }
void SimulatedAnnealingSolver::init() SimulatedAnnealingSolver::SimulatedAnnealingSolver(const SimulatedAnnealingSolver& b)
{ {
impl = new SimulatedAnnealingSolver::Impl(); if (b.impl) b.impl->addref();
release();
impl = b.impl;
}
void SimulatedAnnealingSolver::release()
{
if (impl) { impl->release(); impl = NULL; }
} }
void SimulatedAnnealingSolver::setIterPerStep(int ite) void SimulatedAnnealingSolver::setIterPerStep(int ite)
{ {
CV_Assert(impl);
CV_Assert(ite>0); CV_Assert(ite>0);
impl->iterPerStep = ite; impl->iterPerStep = ite;
} }
int SimulatedAnnealingSolver::run() int SimulatedAnnealingSolver::run()
{ {
CV_Assert(impl);
CV_Assert(impl->initialT>impl->finalT); CV_Assert(impl->initialT>impl->finalT);
double Ti = impl->initialT; double Ti = impl->initialT;
double previousEnergy = energy(); double previousEnergy = impl->energy();
int exchange = 0; int exchange = 0;
while (Ti > impl->finalT) while (Ti > impl->finalT)
{ {
for (int i = 0; i < impl->iterPerStep; i++) for (int i = 0; i < impl->iterPerStep; i++)
{ {
changedState(); impl->changeState();
double newEnergy = energy(); double newEnergy = impl->energy();
if (newEnergy < previousEnergy) if (newEnergy < previousEnergy)
{ {
previousEnergy = newEnergy; previousEnergy = newEnergy;
//??? exchange++;
} }
else else
{ {
double r = impl->rEnergy.uniform(double(0.0), double(1.0)); double r = impl->rEnergy.uniform(0.0, 1.0);
if (r < exp(-(newEnergy - previousEnergy) / Ti)) if (r < std::exp(-(newEnergy - previousEnergy) / Ti))
{ {
previousEnergy = newEnergy; previousEnergy = newEnergy;
exchange++; exchange++;
} }
else else
reverseChangedState(); {
impl->reverseState();
}
} }
} }
...@@ -131,33 +178,43 @@ int SimulatedAnnealingSolver::run() ...@@ -131,33 +178,43 @@ int SimulatedAnnealingSolver::run()
return exchange; return exchange;
} }
void SimulatedAnnealingSolver::setEnergyRNG(const RNG& rng)
{
CV_Assert(impl);
impl->rEnergy = rng;
}
void SimulatedAnnealingSolver::setInitialTemperature(double x) void SimulatedAnnealingSolver::setInitialTemperature(double x)
{ {
CV_Assert(impl);
CV_Assert(x>0); CV_Assert(x>0);
impl->initialT = x; impl->initialT = x;
}; }
void SimulatedAnnealingSolver::setFinalTemperature(double x) void SimulatedAnnealingSolver::setFinalTemperature(double x)
{ {
CV_Assert(impl);
CV_Assert(x>0); CV_Assert(x>0);
impl->finalT = x; impl->finalT = x;
}; }
double SimulatedAnnealingSolver::getFinalTemperature() double SimulatedAnnealingSolver::getFinalTemperature()
{ {
CV_Assert(impl);
return impl->finalT; return impl->finalT;
}; }
void SimulatedAnnealingSolver::setCoolingRatio(double x) void SimulatedAnnealingSolver::setCoolingRatio(double x)
{ {
CV_Assert(impl);
CV_Assert(x>0 && x<1); CV_Assert(x>0 && x<1);
impl->coolingRatio = x; impl->coolingRatio = x;
}; }
class SimulatedAnnealingANN_MLP : public ml::SimulatedAnnealingSolver class SimulatedAnnealingANN_MLP : public SimulatedAnnealingSolverSystem
{ {
public: protected:
ml::ANN_MLP *nn; ml::ANN_MLP& nn;
Ptr<ml::TrainData> data; Ptr<ml::TrainData> data;
int nbVariables; int nbVariables;
vector<double*> adrVariables; vector<double*> adrVariables;
...@@ -165,32 +222,37 @@ public: ...@@ -165,32 +222,37 @@ public:
RNG rIndex; RNG rIndex;
double varTmp; double varTmp;
int index; int index;
public:
SimulatedAnnealingANN_MLP(ml::ANN_MLP *x, Ptr<ml::TrainData> d) : nn(x), data(d) SimulatedAnnealingANN_MLP(ml::ANN_MLP& x, const Ptr<ml::TrainData>& d) : nn(x), data(d)
{ {
initVarMap(); initVarMap();
}; }
void changedState() ~SimulatedAnnealingANN_MLP() {}
protected:
void changeState()
{ {
index = rIndex.uniform(0, nbVariables); index = rIndex.uniform(0, nbVariables);
double dv = rVar.uniform(-1.0, 1.0); double dv = rVar.uniform(-1.0, 1.0);
varTmp = *adrVariables[index]; varTmp = *adrVariables[index];
*adrVariables[index] = dv; *adrVariables[index] = dv;
}; }
void reverseChangedState()
void reverseState()
{ {
*adrVariables[index] = varTmp; *adrVariables[index] = varTmp;
}; }
double energy() { return nn->calcError(data, false, noArray()); }
double energy() const { return nn.calcError(data, false, noArray()); }
protected: protected:
void initVarMap() void initVarMap()
{ {
Mat l = nn->getLayerSizes(); Mat l = nn.getLayerSizes();
nbVariables = 0; nbVariables = 0;
adrVariables.clear(); adrVariables.clear();
for (int i = 1; i < l.rows-1; i++) for (int i = 1; i < l.rows-1; i++)
{ {
Mat w = nn->getWeights(i); Mat w = nn.getWeights(i);
for (int j = 0; j < w.rows; j++) for (int j = 0; j < w.rows; j++)
{ {
for (int k = 0; k < w.cols; k++, nbVariables++) for (int k = 0; k < w.cols; k++, nbVariables++)
...@@ -274,6 +336,13 @@ void ANN_MLP::setAnnealItePerStep(int val) ...@@ -274,6 +336,13 @@ void ANN_MLP::setAnnealItePerStep(int val)
this_->setAnnealItePerStep(val); this_->setAnnealItePerStep(val);
} }
void ANN_MLP::setAnnealEnergyRNG(const RNG& rng)
{
ANN_MLP_ANNEAL* this_ = dynamic_cast<ANN_MLP_ANNEAL*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
this_->setAnnealEnergyRNG(rng);
}
class ANN_MLPImpl : public ANN_MLP_ANNEAL class ANN_MLPImpl : public ANN_MLP_ANNEAL
{ {
...@@ -301,6 +370,9 @@ public: ...@@ -301,6 +370,9 @@ public:
CV_IMPL_PROPERTY(double, AnnealCoolingRatio, params.coolingRatio) CV_IMPL_PROPERTY(double, AnnealCoolingRatio, params.coolingRatio)
CV_IMPL_PROPERTY(int, AnnealItePerStep, params.itePerStep) CV_IMPL_PROPERTY(int, AnnealItePerStep, params.itePerStep)
//CV_IMPL_PROPERTY(RNG, AnnealEnergyRNG, params.rEnergy)
inline void setAnnealEnergyRNG(const RNG& val) { params.rEnergy = val; }
void clear() void clear()
{ {
min_val = max_val = min_val1 = max_val1 = 0.; min_val = max_val = min_val1 = max_val1 = 0.;
...@@ -1018,7 +1090,8 @@ public: ...@@ -1018,7 +1090,8 @@ public:
} }
int train_anneal(const Ptr<TrainData>& trainData) int train_anneal(const Ptr<TrainData>& trainData)
{ {
SimulatedAnnealingANN_MLP t(this, trainData); SimulatedAnnealingSolver t(Ptr<SimulatedAnnealingANN_MLP>(new SimulatedAnnealingANN_MLP(*this, trainData)));
t.setEnergyRNG(params.rEnergy);
t.setFinalTemperature(params.finalT); t.setFinalTemperature(params.finalT);
t.setInitialTemperature(params.initialT); t.setInitialTemperature(params.initialT);
t.setCoolingRatio(params.coolingRatio); t.setCoolingRatio(params.coolingRatio);
...@@ -1665,70 +1738,6 @@ Ptr<ANN_MLP> ANN_MLP::load(const String& filepath) ...@@ -1665,70 +1738,6 @@ Ptr<ANN_MLP> ANN_MLP::load(const String& filepath)
return ann; return ann;
} }
double ANN_MLP_ANNEAL::getAnnealInitialT() const
{
const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
return this_->getAnnealInitialT();
}
void ANN_MLP_ANNEAL::setAnnealInitialT(double val)
{
ANN_MLPImpl* this_ = dynamic_cast< ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
this_->setAnnealInitialT(val);
}
double ANN_MLP_ANNEAL::getAnnealFinalT() const
{
const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
return this_->getAnnealFinalT();
}
void ANN_MLP_ANNEAL::setAnnealFinalT(double val)
{
ANN_MLPImpl* this_ = dynamic_cast<ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
this_->setAnnealFinalT(val);
}
double ANN_MLP_ANNEAL::getAnnealCoolingRatio() const
{
const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
return this_->getAnnealCoolingRatio();
}
void ANN_MLP_ANNEAL::setAnnealCoolingRatio(double val)
{
ANN_MLPImpl* this_ = dynamic_cast< ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
this_->setAnnealInitialT(val);
}
int ANN_MLP_ANNEAL::getAnnealItePerStep() const
{
const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
return this_->getAnnealItePerStep();
}
void ANN_MLP_ANNEAL::setAnnealItePerStep(int val)
{
ANN_MLPImpl* this_ = dynamic_cast<ANN_MLPImpl*>(this);
if (!this_)
CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
this_->setAnnealInitialT(val);
}
}} }}
/* End of file. */ /* End of file. */
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include "test_precomp.hpp" #include "test_precomp.hpp"
//#define GENERATE_TESTDATA
using namespace cv; using namespace cv;
using namespace std; using namespace std;
...@@ -248,7 +250,7 @@ TEST(ML_ANN, ActivationFunction) ...@@ -248,7 +250,7 @@ TEST(ML_ANN, ActivationFunction)
#endif #endif
} }
} }
//#define GENERATE_TESTDATA
TEST(ML_ANN, Method) TEST(ML_ANN, Method)
{ {
String folder = string(cvtest::TS::ptr()->get_data_path()); String folder = string(cvtest::TS::ptr()->get_data_path());
...@@ -275,6 +277,7 @@ TEST(ML_ANN, Method) ...@@ -275,6 +277,7 @@ TEST(ML_ANN, Method)
methodName.push_back("_anneal"); methodName.push_back("_anneal");
// methodName.push_back("_backprop"); -----> NO BACKPROP TEST // methodName.push_back("_backprop"); -----> NO BACKPROP TEST
#ifdef GENERATE_TESTDATA #ifdef GENERATE_TESTDATA
{
Ptr<ml::ANN_MLP> xx = ml::ANN_MLP_ANNEAL::create(); Ptr<ml::ANN_MLP> xx = ml::ANN_MLP_ANNEAL::create();
Mat_<int> layerSizesXX(1, 4); Mat_<int> layerSizesXX(1, 4);
layerSizesXX(0, 0) = tdata->getNVars(); layerSizesXX(0, 0) = tdata->getNVars();
...@@ -290,6 +293,7 @@ TEST(ML_ANN, Method) ...@@ -290,6 +293,7 @@ TEST(ML_ANN, Method)
fs.open(dataname + "_init_weight.yml.gz", FileStorage::WRITE + FileStorage::BASE64); fs.open(dataname + "_init_weight.yml.gz", FileStorage::WRITE + FileStorage::BASE64);
xx->write(fs); xx->write(fs);
fs.release(); fs.release();
}
#endif #endif
for (size_t i = 0; i < methodType.size(); i++) for (size_t i = 0; i < methodType.size(); i++)
{ {
...@@ -300,6 +304,7 @@ TEST(ML_ANN, Method) ...@@ -300,6 +304,7 @@ TEST(ML_ANN, Method)
x->setTrainMethod(methodType[i]); x->setTrainMethod(methodType[i]);
if (methodType[i] == ml::ANN_MLP::ANNEAL) if (methodType[i] == ml::ANN_MLP::ANNEAL)
{ {
x->setAnnealEnergyRNG(RNG(CV_BIG_INT(0xffffffff)));
x->setAnnealInitialT(12); x->setAnnealInitialT(12);
x->setAnnealFinalT(0.15); x->setAnnealFinalT(0.15);
x->setAnnealCoolingRatio(0.96); x->setAnnealCoolingRatio(0.96);
......
#include <opencv2/opencv.hpp> #include <opencv2/opencv.hpp>
using namespace std;
using namespace cv; using namespace cv;
void DrawTravelMap(Mat &img, vector<Point> &p, vector<int> &n); class TravelSalesman : public ml::SimulatedAnnealingSolverSystem
class TravelSalesman : public ml::SimulatedAnnealingSolver
{ {
private : private :
vector<Point> &posCity; const std::vector<Point>& posCity;
vector<int> &next; std::vector<int>& next;
RNG rng; RNG rng;
int d0,d1,d2,d3; int d0,d1,d2,d3;
public: public:
TravelSalesman(std::vector<Point> &p, std::vector<int> &n) :
TravelSalesman(vector<Point> &p,vector<int> &n):posCity(p),next(n) posCity(p), next(n)
{ {
rng = theRNG(); rng = theRNG();
}; }
/** Give energy value for a state of system.*/ /** Give energy value for a state of system.*/
virtual double energy(); /*virtual*/ double energy() const;
/** Function which change the state of system (random pertubation).*/ /** Function which change the state of system (random pertubation).*/
virtual void changedState(); /*virtual*/ void changeState();
/** Function to reverse to the previous state.*/ /** Function to reverse to the previous state.*/
virtual void reverseChangedState(); /*virtual*/ void reverseState();
}; };
void TravelSalesman::changedState() void TravelSalesman::changeState()
{ {
d0 = rng.uniform(0,static_cast<int>(posCity.size())); d0 = rng.uniform(0,static_cast<int>(posCity.size()));
d1 = next[d0]; d1 = next[d0];
d2 = next[d1]; d2 = next[d1];
d3 = next[d2]; d3 = next[d2];
int d0Tmp = d0;
int d1Tmp = d1;
int d2Tmp = d2;
next[d0Tmp] = d2; next[d0] = d2;
next[d2Tmp] = d1; next[d2] = d1;
next[d1Tmp] = d3; next[d1] = d3;
} }
void TravelSalesman::reverseChangedState() void TravelSalesman::reverseState()
{ {
next[d0] = d1; next[d0] = d1;
next[d1] = d2; next[d1] = d2;
next[d2] = d3; next[d2] = d3;
} }
double TravelSalesman::energy() double TravelSalesman::energy() const
{ {
double e=0; double e = 0;
for (size_t i = 0; i < next.size(); i++) for (size_t i = 0; i < next.size(); i++)
{ {
e += norm(posCity[i]-posCity[next[i]]); e += norm(posCity[i]-posCity[next[i]]);
} }
return e; return e;
} }
void DrawTravelMap(Mat &img, vector<Point> &p, vector<int> &n) static void DrawTravelMap(Mat &img, std::vector<Point> &p, std::vector<int> &n)
{ {
for (size_t i = 0; i < n.size(); i++) for (size_t i = 0; i < n.size(); i++)
{ {
...@@ -74,12 +68,12 @@ int main(void) ...@@ -74,12 +68,12 @@ int main(void)
{ {
int nbCity=40; int nbCity=40;
Mat img(500,500,CV_8UC3,Scalar::all(0)); Mat img(500,500,CV_8UC3,Scalar::all(0));
RNG &rng=theRNG(); RNG rng(123456);
int radius=static_cast<int>(img.cols*0.45); int radius=static_cast<int>(img.cols*0.45);
Point center(img.cols/2,img.rows/2); Point center(img.cols/2,img.rows/2);
vector<Point> posCity(nbCity); std::vector<Point> posCity(nbCity);
vector<int> next(nbCity); std::vector<int> next(nbCity);
for (size_t i = 0; i < posCity.size(); i++) for (size_t i = 0; i < posCity.size(); i++)
{ {
double theta = rng.uniform(0., 2 * CV_PI); double theta = rng.uniform(0., 2 * CV_PI);
...@@ -87,25 +81,33 @@ int main(void) ...@@ -87,25 +81,33 @@ int main(void)
posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y; posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y;
next[i]=(i+1)%nbCity; next[i]=(i+1)%nbCity;
} }
TravelSalesman ts(posCity,next); Ptr<TravelSalesman> ts_system(new TravelSalesman(posCity, next));
ml::SimulatedAnnealingSolver ts(ts_system);
ts.setIterPerStep(10000*nbCity);
ts.setCoolingRatio(0.99); ts.setCoolingRatio(0.99);
ts.setInitialTemperature(100); ts.setInitialTemperature(100);
ts.setIterPerStep(10000*nbCity);
ts.setFinalTemperature(100*0.97); ts.setFinalTemperature(100*0.97);
DrawTravelMap(img,posCity,next); DrawTravelMap(img,posCity,next);
imshow("Map",img); imshow("Map",img);
waitKey(10); waitKey(10);
for (int i = 0; i < 100; i++) for (int i = 0, zeroChanges = 0; zeroChanges < 10; i++)
{ {
ts.run(); int changesApplied = ts.run();
img = Mat::zeros(img.size(),CV_8UC3); img = Mat::zeros(img.size(),CV_8UC3);
DrawTravelMap(img, posCity, next); DrawTravelMap(img, posCity, next);
imshow("Map", img); imshow("Map", img);
waitKey(10); int k = waitKey(10);
double ti=ts.getFinalTemperature(); double ti=ts.getFinalTemperature();
cout<<ti <<" -> "<<ts.energy()<<"\n"; std::cout << "i=" << i << " changesApplied=" << changesApplied << " temp=" << ti << " result=" << ts_system->energy() << std::endl;
if (k == 27 || k == 'q' || k == 'Q')
return 0;
if (changesApplied == 0)
zeroChanges++;
ts.setInitialTemperature(ti); ts.setInitialTemperature(ti);
ts.setFinalTemperature(ti*0.97); ts.setFinalTemperature(ti*0.97);
} }
std::cout << "Done" << std::endl;
waitKey(0);
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment