CaDesigner.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
00003  *
00004  * This file is part of nucad (Non-Uniform CA Designer).
00005  *
00006  * nucad is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * any later version.
00010  *
00011  * nucad is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with nucad.  If not, see <http://www.gnu.org/licenses/>.
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 // GaCaRules implementation
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     // dummy constructor used by GaCaRulesCmpDecorator
00083 }
00084 
00085 GaCaRules::GaCaRules(const std::string &str):
00086     d(new Private(1))
00087 {
00088     // guess CA size
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         // unexpected size of input
00095         throw std::runtime_error("GaCaRules::GaCaRules: input error (not handled)");
00096 
00097     // deserialize
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     // deep copy
00108     d->bs.copy(bs);
00109 }
00110 
00111 GaCaRules::GaCaRules(const GaCaRules &other):
00112     d(new Private(other.d->size))
00113 {
00114     // deep copy
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     // FIXME: should it respect the CA_CYCLIC_NEIGHBORHOOD compile-time option?
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 // CaDesigner implementation
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 // protected
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 // it is not safe to call virtual methods in constructor
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 // protected
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 // protected
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     // static to non-static binding
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     // compute fitness
00253     GaCaRules data(evaluator->caSize(), bs);
00254     float fitness = evaluator->eval(&data);
00255     if (d->maxFitness < fitness) {
00256         // compute nGenerations bonus
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         // update maxFitness and notify observers
00268         d->maxFitness = fitness;
00269         solver->notify();
00270 
00271 #if GA_PARTIAL_RESULTS
00272         // FIXME: use observer for this
00273         // FIXME: read fd as cmd-line argument
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             // FIXME: repeat write(2) on EINTR
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             // notify observers
00290             solver->notify();
00291 
00292             // FIXME: use observer for this
00293             std::cout << data << std::endl;
00294         }
00295     };
00296 
00297     return fitness;
00298 }
00299 
00300 
00301 // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00302 // AbstractSubject implementation
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     // ATTENTION: Observers are not deleted on object destruction
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 // AbstractProcess implementation
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 // AbstractProcessWatched implementation
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     // Delegate to base
00403     AbstractProcess::start();
00404 }
00405  
00406 void AbstractProcessWatched::stop() {
00407     if (d->running) {
00408         d->running = false;
00409         d->total += d->currentElapsed();
00410     }
00411     // Delegate to base
00412     AbstractProcess::stop();
00413 }
00414  
00415 void AbstractProcessWatched::reset() {
00416     d->running = false;
00417     d->total = 0;
00418     // Delegate to base
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 // GaCaRulesSet implementation
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 // SolutionsCountStop implementation
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 // TimedStop implementation
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 // FitnessWatch implementation
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         // Fitness not changed
00611         return;
00612 
00613     GAStatistics stats = solver->getStatistics();
00614     if (0 == stats.generation())
00615         return;
00616 
00617     // Save maxFitness for next call
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 // ResultsWatch implementation
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     // Check percentage value
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     // Write out message
00706     d->stream
00707         << Color(C_GREEN) << "--- Progress:"
00708         << std::setw(3) << percents << "%"
00709         << Color() << std::endl;
00710 }

Generated on Sat May 2 16:39:31 2009 for nucad by  doxygen 1.5.4