00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "config.h"
00027 #include "CaDesigner.h"
00028 #include "Color.h"
00029
00030 #ifndef GA_PARTIAL_RESULTS
00031 # define GA_PARTIAL_RESULTS 0
00032 #endif
00033
00034 #ifndef BUILDING_DOX
00035 # if GA_PARTIAL_RESULTS
00036 # include <fcntl.h>
00037 # include <unistd.h>
00038 # endif
00039
00040 # include <iomanip>
00041 # include <list>
00042 # include <math.h>
00043 # include <set>
00044
00045 # include <boost/lexical_cast.hpp>
00046
00047 # include <ga/GA1DBinStrGenome.h>
00048 # include <ga/GASimpleGA.h>
00049 # include <ga/GAStatistics.h>
00050 #endif // BUILDING_DOX
00051
00052 #if 0
00053 #include <ga/GASStateGA.h>
00054 #include <ga/GAIncGA.h>
00055 #include <ga/GADemeGA.h>
00056 #endif
00057
00062 typedef GASimpleGA TGeneticAlgorithm;
00063
00064
00065
00066 #ifndef BUILDING_DOX
00067 struct GaCaRules::Private {
00068 size_t size;
00069 GABinaryString bs;
00070
00071 Private(unsigned size_):
00072 size(size_),
00073 bs(size_*size_*RULE_WIDTH)
00074 {
00075 }
00076 };
00077 #endif
00078
00079 GaCaRules::GaCaRules():
00080 d(new Private(1))
00081 {
00082
00083 }
00084
00085 GaCaRules::GaCaRules(const std::string &str):
00086 d(new Private(1))
00087 {
00088
00089 size_t len = str.size();
00090 size_t caSize = static_cast<size_t>(sqrt(
00091 static_cast<float> (len / RULE_WIDTH)));
00092
00093 if (caSize*caSize*RULE_WIDTH != len)
00094
00095 throw std::runtime_error("GaCaRules::GaCaRules: input error (not handled)");
00096
00097
00098 d->size = caSize;
00099 d->bs.resize(len);
00100 for (unsigned i = 0; i < len; ++i)
00101 d->bs.bit(i, boost::lexical_cast<bool>(str[i]));
00102 }
00103
00104 GaCaRules::GaCaRules(size_t size, const GABinaryString &bs):
00105 d(new Private(size))
00106 {
00107
00108 d->bs.copy(bs);
00109 }
00110
00111 GaCaRules::GaCaRules(const GaCaRules &other):
00112 d(new Private(other.d->size))
00113 {
00114
00115 d->bs.copy(other.d->bs);
00116 }
00117
00118 GaCaRules::~GaCaRules() {
00119 delete d;
00120 }
00121
00122 GaCaRules* GaCaRules::clone() const {
00123 return new GaCaRules(*this);
00124 }
00125
00126 void GaCaRules::getRuleAtPos(Pos pos, TRule5N &rule) const {
00127
00128 int offset = pos.row * d->size + pos. col;
00129 offset *= RULE_WIDTH;
00130 for (int i = 0; i < RULE_WIDTH; ++i) {
00131 assert(i + offset < d->bs.size());
00132 rule[i] = d->bs.bit(i + offset);
00133 }
00134 }
00135
00136 size_t GaCaRules::size() const {
00137 return d->bs.size();
00138 }
00139
00140 bool GaCaRules::operator[] (unsigned index) const {
00141 return d->bs.bit(index);
00142 }
00143
00144 std::ostream& operator<< (std::ostream &str, const GaCaRules &data) {
00145 for (unsigned i = 0; i < data.size(); ++i)
00146 str << data[i];
00147 return str;
00148 }
00149
00150
00151
00152 #ifndef BUILDING_DOX
00153 struct CaDesigner::Private {
00154 CaEvaluator *evaluator;
00155 CaDesigner *solver;
00156 float maxFitness;
00157 GA1DBinaryStringGenome *genome;
00158 TGeneticAlgorithm *ga;
00159 GaCaRulesSet *resultSet;
00160
00161 static float fitness(GAGenome &);
00162 };
00163 #endif
00164
00165
00166 CaDesigner::CaDesigner (CaEvaluator *evaluator):
00167 d(new Private)
00168 {
00169 d->evaluator = evaluator;
00170 d->solver = this;
00171 d->maxFitness = 0.0;
00172
00173 const size_t caSize = evaluator->caSize();
00174 const size_t genomeSize = caSize * caSize * RULE_WIDTH;
00175 d->genome = new GA1DBinaryStringGenome(genomeSize, Private::fitness, d);
00176
00177 d->ga = new TGeneticAlgorithm(*(d->genome));
00178 d->ga->populationSize(GA_POP_SIZE);
00179 d->ga->nGenerations(GA_INITAL_NGEN);
00180
00181 d->resultSet = new GaCaRulesSet;
00182 }
00183
00184 CaDesigner::~CaDesigner() {
00185 delete d->resultSet;
00186 delete d->ga;
00187 delete d->genome;
00188 delete d;
00189 }
00190
00191
00192 CaDesigner* CaDesigner::create (CaEvaluator *evaluator) {
00193 CaDesigner *obj = new CaDesigner(evaluator);
00194 obj->initialize();
00195 return obj;
00196 }
00197
00198 const GAStatistics& CaDesigner::getStatistics() const {
00199 return d->ga->statistics();
00200 }
00201
00202 int CaDesigner::getSolutionsCount() {
00203 return d->resultSet->size();
00204 }
00205
00206 int CaDesigner::stopAtGeneration() const {
00207 return d->ga->nGenerations();
00208 }
00209
00210 float CaDesigner::minFitness() {
00211 return d->ga->statistics().offlineMin();
00212 }
00213
00214 float CaDesigner::avgFitness() {
00215 return d->ga->statistics().offlineMax();
00216 }
00217
00218 float CaDesigner::maxFitness() {
00219 return d->maxFitness;
00220 }
00221
00222
00223 void CaDesigner::initialize() {
00224 GARandomSeed();
00225 d->maxFitness = 0.0;
00226 d->ga->initialize();
00227 d->ga->nGenerations(GA_INITAL_NGEN);
00228 }
00229
00230
00231 void CaDesigner::doStep() {
00232 GAGeneticAlgorithm &ga= *(d->ga);
00233 ga.step();
00234 if (ga.done()) {
00235 this->stop();
00236 GAStatistics stats= ga.statistics();
00237 const int generation = stats.generation();
00238 std::cerr << Color(C_YELLOW) << "--- Stopped by GAlib in "
00239 << generation << ". generation"
00240 << Color(C_NO_COLOR) << std::endl;
00241 }
00242 }
00243
00244 float CaDesigner::Private::fitness(GAGenome &genome) {
00245
00246 Private *d = reinterpret_cast<Private *>(genome.userData());
00247 CaEvaluator *evaluator = dynamic_cast<CaEvaluator *>(d->evaluator);
00248 CaDesigner *solver = dynamic_cast<CaDesigner *>(d->solver);
00249 const GABinaryString &bs= dynamic_cast<GABinaryString &>(genome);
00250 GaCaRulesSet *resultSet= dynamic_cast<GaCaRulesSet *>(d->resultSet);
00251
00252
00253 GaCaRules data(evaluator->caSize(), bs);
00254 float fitness = evaluator->eval(&data);
00255 if (d->maxFitness < fitness) {
00256
00257 float conFit = 1.0;
00258 for (unsigned i = 0; i < GA_PER_FIT_NGEN_POWER; ++i)
00259 conFit *= fitness;
00260 int total = static_cast<int>(conFit * GA_PER_FIT_NGEN);
00261 if (total < GA_INITAL_NGEN)
00262 total = GA_INITAL_NGEN;
00263 total += d->ga->statistics().generation();
00264 if (d->ga->nGenerations() < total)
00265 d->ga->nGenerations(total);
00266
00267
00268 d->maxFitness = fitness;
00269 solver->notify();
00270
00271 #if GA_PARTIAL_RESULTS
00272
00273
00274 const int fd = 3;
00275 if (-1 != fcntl(fd, F_GETFD)) {
00276 std::ostringstream str;
00277 str << data << std::endl;
00278 const std::string &text = str.str();
00279
00280 write(fd, text.c_str(), text.size());
00281 }
00282 #endif
00283 }
00284
00285 if (1.0 <= fitness) {
00286 size_t last = resultSet->size();
00287 resultSet->add(data.clone());
00288 if (last != resultSet->size()) {
00289
00290 solver->notify();
00291
00292
00293 std::cout << data << std::endl;
00294 }
00295 };
00296
00297 return fitness;
00298 }
00299
00300
00301
00302
00303 #ifndef BUILDING_DOX
00304 struct AbstractSubject::Private {
00305 typedef std::list<IObserver *> TContainer;
00306 TContainer container;
00307 };
00308 #endif
00309
00310 AbstractSubject::AbstractSubject():
00311 d(new Private)
00312 {
00313 }
00314
00315 AbstractSubject::~AbstractSubject() {
00316
00317 delete d;
00318 }
00319
00320 void AbstractSubject::addObserver(IObserver *observer) {
00321 d->container.push_back(observer);
00322 }
00323
00324 void AbstractSubject::notify() {
00325 Private::TContainer::iterator iter;
00326 for(iter=d->container.begin(); iter!=d->container.end(); iter++) {
00327 IObserver *observer = *iter;
00328 observer->notify();
00329 }
00330 }
00331
00332
00333
00334 #ifndef BUILDING_DOX
00335 struct AbstractProcess::Private {
00336 bool running;
00337 int steps;
00338 };
00339 #endif
00340
00341 AbstractProcess::AbstractProcess():
00342 d(new Private)
00343 {
00344 d->running = false;
00345 d->steps = 0;
00346 }
00347
00348 AbstractProcess::~AbstractProcess() {
00349 delete d;
00350 }
00351
00352 void AbstractProcess::start() {
00353 for(d->running=true; d->running; d->steps++) {
00354 this->doStep();
00355 this->notify();
00356 }
00357 }
00358
00359 void AbstractProcess::stop() {
00360 d->running = false;
00361 }
00362
00363 void AbstractProcess::reset() {
00364 d->running = false;
00365 d->steps = 0;
00366 this->initialize();
00367 }
00368
00369 int AbstractProcess::getStepsCount() {
00370 return d->steps;
00371 }
00372
00373
00374
00375 #ifndef BUILDING_DOX
00376 struct AbstractProcessWatched::Private {
00377 static const long RATIO = CLOCKS_PER_SEC/1000L;
00378 clock_t start;
00379 long total;
00380 bool running;
00381 long currentElapsed() {
00382 clock_t diff = clock() - start;
00383 return diff/RATIO;
00384 }
00385 };
00386 #endif
00387
00388 AbstractProcessWatched::AbstractProcessWatched():
00389 d(new Private)
00390 {
00391 d->total = 0;
00392 d->running = false;
00393 }
00394
00395 AbstractProcessWatched::~AbstractProcessWatched() {
00396 delete d;
00397 }
00398
00399 void AbstractProcessWatched::start() {
00400 d->start = clock();
00401 d->running = true;
00402
00403 AbstractProcess::start();
00404 }
00405
00406 void AbstractProcessWatched::stop() {
00407 if (d->running) {
00408 d->running = false;
00409 d->total += d->currentElapsed();
00410 }
00411
00412 AbstractProcess::stop();
00413 }
00414
00415 void AbstractProcessWatched::reset() {
00416 d->running = false;
00417 d->total = 0;
00418
00419 AbstractProcess::reset();
00420 }
00421
00422 long AbstractProcessWatched::getTimeElapsed() {
00423 long total = d->total;
00424 if (d->running)
00425 total+= d->currentElapsed();
00426 return total;
00427 }
00428
00429
00430
00431 #ifndef BUILDING_DOX
00432 struct GaCaRulesSet::Private {
00433 class GaCaRulesCmpDecorator: public GaCaRules {
00434 public:
00435 GaCaRulesCmpDecorator(GaCaRules *item):
00436 item_(item)
00437 {
00438 }
00439 void dispose() {
00440 delete item_;
00441 }
00442 virtual size_t size() const {
00443 return item_->size();
00444 }
00445 virtual bool operator[] (unsigned index) const {
00446 return item_->operator[] (index);
00447 }
00448 virtual GaCaRules* clone() const {
00449 return item_->clone();
00450 }
00451 bool operator< (const GaCaRulesCmpDecorator &other) const {
00452 for(unsigned i=0; i<size(); i++) {
00453 if (!this->operator[](i) && other[i])
00454 return true;
00455 else if (this->operator[](i) && !other[i])
00456 return false;
00457 }
00458 return false;
00459 }
00460 private:
00461 GaCaRules *item_;
00462 };
00463 typedef std::set<GaCaRulesCmpDecorator> TSet;
00464 TSet set;
00465
00466 void add(GaCaRules *item) {
00467 GaCaRulesCmpDecorator comparableItem(item);
00468 if (set.end()==set.find(comparableItem))
00469 set.insert(comparableItem);
00470 else
00471 comparableItem.dispose();
00472 }
00473 };
00474 #endif // BUILDING_DOX
00475
00476 GaCaRulesSet::GaCaRulesSet():
00477 d(new Private)
00478 {
00479 }
00480
00481 GaCaRulesSet::~GaCaRulesSet() {
00482 this->clear();
00483 delete d;
00484 }
00485
00486 size_t GaCaRulesSet::size() const {
00487 return d->set.size();
00488 }
00489
00490 void GaCaRulesSet::add(GaCaRules *item) {
00491 d->add(item);
00492 }
00493
00494 void GaCaRulesSet::clear() {
00495 Private::TSet::iterator iter;
00496 for(iter=d->set.begin(); iter!=d->set.end(); iter++) {
00497 Private::GaCaRulesCmpDecorator &i=
00498 const_cast<Private::GaCaRulesCmpDecorator &>(*iter);
00499 i.dispose();
00500 }
00501 d->set.clear();
00502 }
00503
00504
00505
00506 #ifndef BUILDING_DOX
00507 struct SolutionsCountStop::Private {
00508 CaDesigner *solver;
00509 int minCountOfSolutions;
00510 };
00511 #endif
00512
00513 SolutionsCountStop::SolutionsCountStop(CaDesigner *solver, int minCountOfSolutions):
00514 d(new Private)
00515 {
00516 d->solver = solver;
00517 d->minCountOfSolutions = minCountOfSolutions;
00518 }
00519
00520 SolutionsCountStop::~SolutionsCountStop() {
00521 delete d;
00522 }
00523
00524 void SolutionsCountStop::notify() {
00525 const int nSolutions= d->solver->getSolutionsCount();
00526 if (nSolutions >= d->minCountOfSolutions)
00527 d->solver->stop();
00528 }
00529
00530
00531
00532
00533 #ifndef BUILDING_DOX
00534 struct TimedStop::Private {
00535 AbstractProcessWatched *process;
00536 long msec;
00537 };
00538 #endif
00539
00540 TimedStop::TimedStop(AbstractProcessWatched *process, long msec):
00541 d(new Private)
00542 {
00543 d->process = process;
00544 d->msec = msec;
00545 }
00546
00547 TimedStop::~TimedStop() {
00548 delete d;
00549 }
00550
00551 void TimedStop::notify() {
00552 long elapsed = d->process->getTimeElapsed();
00553 if (elapsed > d->msec) {
00554 std::cerr << Color(C_YELLOW) << "--- Run timed out"
00555 << Color(C_NO_COLOR) << std::endl;
00556 d->process->stop();
00557 }
00558 }
00559
00560 namespace {
00561 void writeStats(CaDesigner *solver, std::ostream &str) {
00562 GAStatistics stats = solver->getStatistics();
00563 const int generation = stats.generation();
00564 const int stopAtGeneration = solver->stopAtGeneration();
00565 const float timeElapsed = solver->getTimeElapsed()/1000.0;
00566 const float timeRemaining = timeElapsed / generation
00567 * (stopAtGeneration - generation);
00568
00569 #if (1 < GA_POP_SIZE)
00570 str << " (avg:" << FixedFloat(3,1) << solver->avgFitness() * 100.0
00571 << ", min:" << FixedFloat(3,1) << solver->minFitness() * 100.0
00572 << ")";
00573 #endif
00574 str << ", generation " << Color(C_LIGHT_GREEN)
00575 << std::setw(8) << generation << Color(C_NO_COLOR)
00576 << " of " << std::setw(8) << stopAtGeneration
00577 << ", time elapsed: " << Color(C_YELLOW)
00578 << FixedFloat(6,2) << timeElapsed << " s" << Color(C_NO_COLOR)
00579 << ", ttl = " << FixedFloat(6,2) << timeRemaining << " s";
00580 }
00581 }
00582
00583
00584
00585 #ifndef BUILDING_DOX
00586 struct FitnessWatch::Private {
00587 CaDesigner *solver;
00588 std::ostream &stream;
00589 float maxFitness;
00590
00591 Private(std::ostream &streamTo): stream(streamTo) { }
00592 };
00593 #endif
00594
00595 FitnessWatch::FitnessWatch(CaDesigner *solver, std::ostream &streamTo):
00596 d(new Private(streamTo))
00597 {
00598 d->solver = solver;
00599 d->maxFitness = 0.0;
00600 }
00601
00602 FitnessWatch::~FitnessWatch() {
00603 delete d;
00604 }
00605
00606 void FitnessWatch::notify() {
00607 CaDesigner *solver= d->solver;
00608 float maxFitness = solver->maxFitness();
00609 if (maxFitness <= d->maxFitness)
00610
00611 return;
00612
00613 GAStatistics stats = solver->getStatistics();
00614 if (0 == stats.generation())
00615 return;
00616
00617
00618 d->maxFitness = maxFitness;
00619
00620 d->stream << "--- satisfaction:" << Color(C_LIGHT_BLUE)
00621 << FixedFloat(3,1) << maxFitness*100.0 << "%"
00622 << Color(C_NO_COLOR);
00623 writeStats(solver, d->stream);
00624 d->stream << std::endl;
00625 }
00626
00627 void FitnessWatch::reset() {
00628 d->maxFitness = 0.0;
00629 }
00630
00631
00632
00633 #ifndef BUILDING_DOX
00634 struct ResultsWatch::Private {
00635 CaDesigner *solver;
00636 std::ostream &stream;
00637 int nResults;
00638
00639 Private(std::ostream &streamTo): stream(streamTo) { }
00640 };
00641 #endif
00642
00643 ResultsWatch::ResultsWatch(CaDesigner *solver, std::ostream &streamTo):
00644 d(new Private(streamTo))
00645 {
00646 d->solver = solver;
00647 d->nResults = 0;
00648 }
00649
00650 ResultsWatch::~ResultsWatch() {
00651 delete d;
00652 }
00653
00654 void ResultsWatch::notify() {
00655 CaDesigner *solver= d->solver;
00656 const int nResults= solver->getSolutionsCount();
00657 if (nResults <= d->nResults)
00658 return;
00659 d->nResults = nResults;
00660
00661 GAStatistics stats = solver->getStatistics();
00662 if (0 == stats.generation())
00663 return;
00664
00665 d->stream << Color(C_LIGHT_BLUE) << "--- " << std::setw(6) << nResults
00666 << ". solution found" << Color(C_NO_COLOR);
00667 writeStats(solver, d->stream);
00668 d->stream << std::endl;
00669 }
00670
00671 #ifndef BUILDING_DOX
00672 struct ProgressWatch::Private {
00673 AbstractProcess *process;
00674 int stepsTotal;
00675 int last;
00676 std::ostream &stream;
00677
00678 Private(std::ostream &streamTo): stream(streamTo) { }
00679 };
00680 #endif
00681
00682 ProgressWatch::ProgressWatch(AbstractProcess *process, int stepsTotal, std::ostream &streamTo):
00683 d(new Private(streamTo))
00684 {
00685 d->process = process;
00686 d->stepsTotal = stepsTotal;
00687 d->last = 0;
00688 }
00689
00690 ProgressWatch::~ProgressWatch() {
00691 delete d;
00692 }
00693
00694 void ProgressWatch::notify() {
00695
00696
00697 const int currentStep= d->process->getStepsCount();
00698 const int percents=
00699 currentStep*100 /
00700 d->stepsTotal;
00701 if (percents == d->last)
00702 return;
00703 d->last = percents;
00704
00705
00706 d->stream
00707 << Color(C_GREEN) << "--- Progress:"
00708 << std::setw(3) << percents << "%"
00709 << Color() << std::endl;
00710 }