Skip to content

Commit

Permalink
generalize genetic algorithm implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dmishin committed Sep 16, 2013
1 parent f18841c commit 3f13410
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 152 deletions.
303 changes: 184 additions & 119 deletions include/ifs_genetics.hpp
Original file line number Diff line number Diff line change
@@ -1,119 +1,184 @@
#ifndef __IFS_GENETICS_HPP_INCLUDED__
#define __IFS_GENETICS_HPP_INCLUDED__
#include <iostream>

/**FItness function evaluates genome and determines, how good it is.
It must return positive value;
*/
template< typename Genome >
class FitnessFunction{
public:
virtual double fitness(const Genome &rule)=0;
};

/**Genetics is collection of operations over genomes.
*/
template< typename Genome >
class Genetics{
public:
virtual Genome *orphan()=0;
virtual Genome *clone(const Genome &g)=0;
virtual Genome *mutant(const Genome &g)=0;
virtual Genome *crossover(const Genome &g1, const Genome &g2)=0;
virtual void deallocate( Genome *g )=0;
};

class Transform;
class PixelMap;
class Ruleset;

Transform merge_transforms(const Transform &t1, const Transform &t2, double p);
void normalize_pixmap( PixelMap &p );

class GeneticalOptimizer{
public:
struct PoolRecord{
Ruleset *genome;
double fitness;
std::string origin;
size_t generation;
PoolRecord():genome(NULL), fitness(-1){};
PoolRecord(Ruleset *g): genome(g), fitness(-1){};
PoolRecord(Ruleset *g, const std::string &o): genome(g), fitness(-1), origin(o){};
};
typedef std::vector<PoolRecord> PoolT;
private:
size_t pool_size;
size_t orphans_per_generation;
size_t n_mutants;
size_t n_crossovers;
size_t generations;
size_t stop_if_no_improvement_after;
size_t die_if_older_than;

Genetics<Ruleset> &genetics;
FitnessFunction<Ruleset> &fitness_function;
PoolT pool;
PoolRecord best;
size_t generation;
private:
void initialize_pool();
void add_mutant();
void add_crossover();
void add_orphan();
void update_fitness_values();
void clear_pool();
public:
GeneticalOptimizer(Genetics<Ruleset> &genetics_, FitnessFunction<Ruleset> &fitness_function_);
~GeneticalOptimizer();
void set_parameters( size_t pool_size_,
size_t orphans_per_generation_,
size_t n_mutants_,
size_t n_crossovers_,
size_t stop_if_no_improvement_after_,
size_t die_if_older_than_);
void run(size_t generations);
const PoolRecord &get_best()const{ return best; };
};
class RulesetGenetics: public Genetics<Ruleset>
{
private:
void mutate_global_noise(Ruleset &r);
void mutate_insert(Ruleset &r);
void mutate_delete(Ruleset &r);
void mutate_modify(Ruleset &r);
void random_modify_rule( Ruleset::Rule &r, double amount );

public:

double noise_amount_global;
double noise_amount_point;
int crossover_size_jitter;
size_t max_rules;

RulesetGenetics();
virtual Ruleset *orphan();
virtual Ruleset *clone(const Ruleset &g);
virtual Ruleset *mutant(const Ruleset &g);
virtual Ruleset *crossover(const Ruleset &g1, const Ruleset &g2);
virtual void deallocate( Ruleset *g );

};

/**MEasures similarity of the image, produced by the IFS ruleset, and the given image,
using cosine distance
If image is normalized, then result if between 0 and 1.
*/
class CosineMeasureFitness: public FitnessFunction<Ruleset>{
const PixelMap &sample;
PixelMap canvas;
point_t origin, size;
double gamma;
public:
size_t RENDER_STEPS_PER_PIXEL;
CosineMeasureFitness( const PixelMap &sample_, const point_t &p0, const point_t &p1 );
void set_gamma(double g){ gamma = g; };
virtual double fitness(const Ruleset &rule);
};

#endif
#ifndef __IFS_GENETICS_HPP_INCLUDED__
#define __IFS_GENETICS_HPP_INCLUDED__
#include <iostream>

typedef void *GenericGenomePtr;
typedef const void *GenericGenomeCPtr;

class GenericFitnessFunction{
protected:
virtual double _fitness(GenericGenomeCPtr g)=0;
template <typename T> friend class GeneticalOptimizer;
friend class GenericGeneticalOptimizer;
};

/**FItness function evaluates genome and determines, how good it is.
It must return positive value;
*/
template< typename Genome >
class FitnessFunction: public GenericFitnessFunction{
protected:
virtual double _fitness(GenericGenomeCPtr g){return fitness(*(Genome*)g);};
public:
virtual double fitness(const Genome &rule)=0;
friend class GenericGeneticalOptimizer;
};
class GenericGenetics{
protected:
virtual GenericGenomePtr _orphan()=0;
virtual GenericGenomePtr _clone(GenericGenomeCPtr g)=0;
virtual GenericGenomePtr _mutant(GenericGenomeCPtr g)=0;
virtual GenericGenomePtr _crossover(GenericGenomeCPtr g1, GenericGenomeCPtr g2)=0;
virtual void _deallocate( GenericGenomePtr )=0;
virtual void _to_stream( std::ostream & os, GenericGenomeCPtr g )=0;
friend class GenericGeneticalOptimizer;
friend class ShowGenericGenome;
};

/**Genetics is collection of operations over genomes.
*/
template< typename Genome >
class Genetics: public GenericGenetics{
private:
const Genome *from_generic(GenericGenomeCPtr p)const{ return (const Genome*)p; };
Genome *from_generic(GenericGenomePtr p)const{ return (Genome*)p; };
GenericGenomePtr to_generic( Genome *p )const{ return (GenericGenomePtr)p; };

protected:

virtual GenericGenomePtr _orphan()
{return to_generic(orphan()); };
virtual GenericGenomePtr _clone(GenericGenomeCPtr g)
{return to_generic(clone( *from_generic(g)));};
virtual GenericGenomePtr _mutant(GenericGenomeCPtr g)
{return to_generic(mutant( *from_generic(g) ));};
virtual GenericGenomePtr _crossover(GenericGenomeCPtr g1, GenericGenomeCPtr g2)
{return to_generic(crossover(*from_generic(g1), *from_generic(g2)));};
virtual void _deallocate( GenericGenomePtr g)
{deallocate( from_generic(g));};
virtual void _to_stream( std::ostream & os, GenericGenomeCPtr g ){to_stream(os, *from_generic(g));};
public:
virtual Genome *orphan()=0;
virtual Genome *clone(const Genome &g)=0;
virtual Genome *mutant(const Genome &g)=0;
virtual Genome *crossover(const Genome &g1, const Genome &g2)=0;
virtual void deallocate( Genome *g )=0;
virtual void to_stream(std::ostream &os, const Genome &g){ os<<"[genome]"; };
};

class Transform;
class PixelMap;
class Ruleset;

Transform merge_transforms(const Transform &t1, const Transform &t2, double p);
void normalize_pixmap( PixelMap &p );

class ShowGenericGenome{
GenericGenomeCPtr genome;
GenericGenetics &genetics;
public:
ShowGenericGenome(GenericGenomeCPtr genome_, GenericGenetics &genetics_):genome(genome_), genetics(genetics_){};
void to_stream(std::ostream &os)const{genetics._to_stream(os, genome);};
};
inline std::ostream & operator << (std::ostream &os, const ShowGenericGenome &show)
{
show.to_stream(os);
return os;
}
class GenericGeneticalOptimizer{
public:
struct PoolRecord{
GenericGenomePtr genome;
double fitness;
std::string origin;
size_t generation;
PoolRecord():genome(NULL), fitness(-1){};
PoolRecord(GenericGenomePtr g): genome(g), fitness(-1){};
PoolRecord(GenericGenomePtr g, const std::string &o): genome(g), fitness(-1), origin(o){};
};
typedef std::vector<PoolRecord> PoolT;
private:
size_t pool_size;
size_t orphans_per_generation;
size_t n_mutants;
size_t n_crossovers;
size_t generations;
size_t stop_if_no_improvement_after;
size_t die_if_older_than;

GenericGenetics &genetics;
GenericFitnessFunction &fitness_function;
PoolT pool;
PoolRecord best;
size_t generation;
private:
void initialize_pool();
void add_mutant();
void add_crossover();
void add_orphan();
void update_fitness_values();
void clear_pool();
public:
GenericGeneticalOptimizer(GenericGenetics &genetics_, GenericFitnessFunction &fitness_function_);
~GenericGeneticalOptimizer();
void set_parameters( size_t pool_size_,
size_t orphans_per_generation_,
size_t n_mutants_,
size_t n_crossovers_,
size_t stop_if_no_improvement_after_,
size_t die_if_older_than_);
void run(size_t generations);
const PoolRecord &get_best()const{ return best; };
};

template< typename Genome >
class GeneticalOptimizer: public GenericGeneticalOptimizer{
public:
GeneticalOptimizer(Genetics<Genome> &g, FitnessFunction<Genome> &f)
:GenericGeneticalOptimizer(g,f){};
};

class RulesetGenetics: public Genetics<Ruleset>
{
private:
void mutate_global_noise(Ruleset &r);
void mutate_insert(Ruleset &r);
void mutate_delete(Ruleset &r);
void mutate_modify(Ruleset &r);
void random_modify_rule( Ruleset::Rule &r, double amount );

public:

double noise_amount_global;
double noise_amount_point;
int crossover_size_jitter;
size_t max_rules;

RulesetGenetics();
virtual Ruleset *orphan();
virtual Ruleset *clone(const Ruleset &g);
virtual Ruleset *mutant(const Ruleset &g);
virtual Ruleset *crossover(const Ruleset &g1, const Ruleset &g2);
void to_stream( std::ostream &os, const Ruleset&r );
virtual void deallocate( Ruleset *g );

};

/**MEasures similarity of the image, produced by the IFS ruleset, and the given image,
using cosine distance
If image is normalized, then result if between 0 and 1.
*/
class CosineMeasureFitness: public FitnessFunction<Ruleset>{
const PixelMap &sample;
PixelMap canvas;
point_t origin, size;
double gamma;
public:
size_t RENDER_STEPS_PER_PIXEL;
CosineMeasureFitness( const PixelMap &sample_, const point_t &p0, const point_t &p1 );
void set_gamma(double g){ gamma = g; };
virtual double fitness(const Ruleset &rule);
};

#endif

Expand Down
4 changes: 2 additions & 2 deletions src/ifs-rand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ int main( int argc, char *argv[] )
CosineMeasureFitness fitness( pix1, point_t(-1,-1), point_t(1,1) );
RulesetGenetics genetics;

GeneticalOptimizer optimizer(genetics, fitness);
GeneticalOptimizer<Ruleset> optimizer(genetics, fitness);
optimizer.set_parameters(
10, //pool
8, //orp
Expand All @@ -80,7 +80,7 @@ int main( int argc, char *argv[] )
render_ruleset( pix2,
point_t(-1.5,-1.5),
point_t(3,3),
*optimizer.get_best().genome,
*(Ruleset*)optimizer.get_best().genome,
pix2.width*pix2.height*100 );
pix2.normalize(1);
pix2.apply_gamma(5);
Expand Down
Loading

0 comments on commit 3f13410

Please sign in to comment.