diff options
61 files changed, 5605 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d45b26f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/*.a +**/*.d +**/*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5b6acff --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +LIBRARY := lib/libHyperNeat.a +SOURCES := $(wildcard src/*.cpp) $(wildcard src/Utils/*.cpp) +OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES)) +DEPS    := $(patsubst %.o,%.d,$(OBJECTS)) +CFLAGS  := -c -O3 -Wall -std=c++11 -MMD -Iinclude -IC:/cereal/include +LFLAGS  := rvs + +all: $(OBJECTS) +	ar $(LFLAGS) $(LIBRARY) $(OBJECTS) +	make -C plugins/CppnExplorer + +-include $(DEPS) + +$(OBJECTS): $(patsubst obj/%.o,src/%.cpp,$@) +	g++ $(CFLAGS) $(patsubst obj/%.o,src/%.cpp,$@) -o $@ + +rebuild: clean all + +clean: +	del lib\*.a +	del obj\*.o +	del obj\*.d +	del obj\Utils\*.o +	del obj\Utils\*.d diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e68cec --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +rtES-HyperNeat (Real Time Evolving Substrate Hypercube based Neuro-Evolution of +Augmenting Topologies) is a real time neuro-evolution algorithm based on the +papers written by Kenneth Stanley and other researchers at the EPLEX group +([http://eplex.cs.ucf.edu/](http://eplex.cs.ucf.edu/)). More specifically, +rtES-HyperNeat tries to blend the existing ES-HyperNeat +([http://eplex.cs.ucf.edu/ESHyperNEAT/](http://eplex.cs.ucf.edu/ESHyperNEAT/)) +algorithm with rtNeat +([http://nn.cs.utexas.edu/?rtNEAT](http://nn.cs.utexas.edu/?rtNEAT)), a previous +version which allowed real time evolution of agents on a virtual field. + +The main problem with trying to make ES-HyperNeat real-timed was that the CPPNs +(genotypes) had to be converted into functional Neural Networks (phenotypes) on +a single time-step. This was proven to be impossible, so, as a solution, the +library handles these transformations on separate execution threads. This way, +the algorithm flows seamlessly. + +Although several implementations existed for HyperNeat, I've decided to code +mine from scratch, based only on the original papers by EPLEX. My goal is to +construct a simple, easy to use, well documented and tutorialized C++ library +that will allow any user to evolve Neural Networks for any imaginable task. I +also plan to apply this library to my Guppies experiment once its finished (see +my channel for more info on Guppies). diff --git a/include/HyperNeat/Behavior.hpp b/include/HyperNeat/Behavior.hpp new file mode 100644 index 0000000..2f474a6 --- /dev/null +++ b/include/HyperNeat/Behavior.hpp @@ -0,0 +1,40 @@ +#ifndef __HYPERNEAT_BEHAVIOR_HPP__ +#define __HYPERNEAT_BEHAVIOR_HPP__ + +#include <HyperNeat/Utils/Size.hpp> +#include <HyperNeat/Utils/Vector.hpp> + +namespace hyperneat +{ +    class Organism; +    class NoveltyMetric; + +    class Behavior +    { +    public: +        void clear(); +        void reset(bool archive = true); + +        double& at(size_t i); +        double getNoveltyScore() const; +        bool isToBeArchived() const; +        Organism& getOrganism(); +        const NoveltyMetric& getNoveltyMetric() const; +        const Vector<double>& getCharacterization() const; + +        bool _criteriaReached = true; + +    private: +        double         _noveltyScore  = 0.0; +        bool           _isReady       = false; +        bool           _toBeArchived  = false; +        Organism*      _organism      = nullptr; +        NoveltyMetric* _noveltyMetric = nullptr; +        Vector<double> _characterization; + +        friend class LoadFile; +        friend class NoveltyMetric; +    }; +} + +#endif diff --git a/include/HyperNeat/Cppn.hpp b/include/HyperNeat/Cppn.hpp new file mode 100644 index 0000000..a4511c8 --- /dev/null +++ b/include/HyperNeat/Cppn.hpp @@ -0,0 +1,58 @@ +#ifndef __HYPERNEAT_CPPN_HPP__ +#define __HYPERNEAT_CPPN_HPP__ + +#include <HyperNeat/Utils/Size.hpp> +#include <HyperNeat/Utils/ValueMap.hpp> +#include <HyperNeat/Utils/Vector2D.hpp> +#include <HyperNeat/Utils/NodeTypes.hpp> + +namespace hyperneat +{ +    class Genome; +    class NodeSearchPrms; + +    class Cppn +    { +    public: +        Cppn() = default; + +        void create(const Genome& genome); +        void clear(); + +        size_t getInputsCount() const; +        size_t getOutputsCount() const; +        size_t getNodesCount() const; + +        double& inputAt(size_t i); +        double outputAt(size_t i) const; + +        void cycle(); +        void findNodesIn2DSection(ValueMap& valueMap, const NodeSearchPrms& qpPrms, const Point& source = Point()); + +    private: +        class Node +        { +        public: +            void appendInput(); +            void flushOutput(); + +            class Link +            { +            public: +                double* _input  = nullptr; +                double  _weight = 0.0; +            }; + +            Vector<Link> _links; +            NodeType     _nodeType    = NodeType::NULL_TYPE; +            double       _storedInput = 0.0; +            double       _output      = 0.0; +        }; + +        Vector<double>  _inputs; +        Vector<double*> _outputs; +        Vector2D<Node>  _nodeLayers; +    }; +} + +#endif diff --git a/include/HyperNeat/Genome.hpp b/include/HyperNeat/Genome.hpp new file mode 100644 index 0000000..d8f678f --- /dev/null +++ b/include/HyperNeat/Genome.hpp @@ -0,0 +1,42 @@ +#ifndef __HYPERNEAT_GENOME_HPP__ +#define __HYPERNEAT_GENOME_HPP__ + +#include <HyperNeat/Utils/Map.hpp> +#include <HyperNeat/Utils/Size.hpp> +#include <HyperNeat/Utils/NodeTypes.hpp> + +namespace hyperneat +{ +    class Genome +    { +    public: +        Genome() = default; +        explicit Genome(size_t inputs); + +        class NodeGene +        { +        public: +            NodeGene() = default; +            NodeGene(double depth, NodeType nodeType); + +            class LinkGene +            { +            public: +                LinkGene() = default; +                LinkGene(double weight, bool isEnabled = true); + +                double _weight    = 0.0; +                bool   _isEnabled = true; +            }; + +            double                _depth    = 0.0; +            NodeType              _nodeType = NodeType::NULL_TYPE; +            Map<size_t, LinkGene> _linkGenes; +        }; + +        size_t                _inputs = 0; +        Map<size_t, NodeGene> _nodeGenes; +    }; +} + +#endif diff --git a/include/HyperNeat/Innovation.hpp b/include/HyperNeat/Innovation.hpp new file mode 100644 index 0000000..ac618e5 --- /dev/null +++ b/include/HyperNeat/Innovation.hpp @@ -0,0 +1,25 @@ +#ifndef __HYPERNEAT_INNOVATION_HPP__ +#define __HYPERNEAT_INNOVATION_HPP__ + +#include <Hyperneat/Utils/Size.hpp> +#include <Hyperneat/Utils/NodeTypes.hpp> + +namespace hyperneat +{ +    class Innovation +    { +    public: +        Innovation() = default; +        Innovation(size_t number, size_t source, size_t target, double depth, NodeType nodeType); + +        bool operator== (const Innovation& other) const; + +        size_t   _number   = 0; +        size_t   _source   = 0; +        size_t   _target   = 0; +        double   _depth    = 0.0; +        NodeType _nodeType = NodeType::NULL_TYPE; +    }; +} + +#endif diff --git a/include/HyperNeat/NeuralNet.hpp b/include/HyperNeat/NeuralNet.hpp new file mode 100644 index 0000000..7f4a81f --- /dev/null +++ b/include/HyperNeat/NeuralNet.hpp @@ -0,0 +1,78 @@ +#ifndef __HYPERNEAT_NEURALNET_HPP__ +#define __HYPERNEAT_NEURALNET_HPP__ + +#include <HyperNeat/Utils/Size.hpp> +#include <HyperNeat/Utils/ValueMap.hpp> + +namespace hyperneat +{ +    class Cppn; +    class NeuralNetPrms; + +    class NeuralNet +    { +    public: +        class Neuron; + +        NeuralNet() = default; + +        void create(Cppn& cppn, const NeuralNetPrms& nnPrms); +        void clear(); + +        size_t getInputsCount() const; +        size_t getOutputsCount() const; +        size_t getNeuronsCount() const; + +        const Vector<double*>& getInputs() const; +        const Vector<double*>& getOutputs() const; +        const Vector<Neuron>& getNeurons() const; + +        double getAverageActivation() const; + +        double& inputAt(size_t i); +        double outputAt(size_t i) const; + +        void cycle(); + +        class Neuron +        { +        public: +            enum class Type { +                INPUT, HIDDEN, OUTPUT +            }; + +            Neuron() = default; +            Neuron(const Point& position, Type type, double bias); + +            void appendInput(); +            void flushOutput(); + +            class Synapse +            { +            public: +                Synapse() = default; +                Synapse(Neuron* inputNeuron, double weight); + +                double* _input  = nullptr; +                Neuron* _neuron = nullptr; +                double  _weight = 0.0; +            }; + +            Vector<Synapse> _synapses; +            Point           _position; +            Type            _type        = Type::HIDDEN; +            double          _bias        = 0.0; +            double          _storedInput = 0.0; +            double          _output      = 0.0; +        }; + +    private: +        Vector<double*> _inputs; +        Vector<double*> _outputs; +        Vector<Neuron>  _neurons; + +        friend class Organism; +    }; +} + +#endif diff --git a/include/HyperNeat/NeuralNetPrms.hpp b/include/HyperNeat/NeuralNetPrms.hpp new file mode 100644 index 0000000..fb5c349 --- /dev/null +++ b/include/HyperNeat/NeuralNetPrms.hpp @@ -0,0 +1,25 @@ +#ifndef __HYPERNEAT_NEURALNETPRMS_HPP__ +#define __HYPERNEAT_NEURALNETPRMS_HPP__ + +#include <HyperNeat/Utils/Size.hpp> +#include <HyperNeat/Utils/Point.hpp> +#include <HyperNeat/Utils/Vector.hpp> + +namespace hyperneat +{ +    class NeuralNetPrms +    { +    public: +        Vector<Point> _inputMap; +        Vector<Point> _outputMap; +        size_t        _testGridLevel        = 3; +        size_t        _maxQuadTreeLevel     = SIZE_MAX; +        size_t        _minQuadTreeLevel     = 0; +        double        _bandPruningThreshold = 0.3; +        double        _varianceThreshold    = 0.03; +        double        _divisionThreshold    = 0.03; +        size_t        _iterations           = SIZE_MAX; +    }; +} + +#endif diff --git a/include/HyperNeat/NodeSearchPrms.hpp b/include/HyperNeat/NodeSearchPrms.hpp new file mode 100644 index 0000000..52d9083 --- /dev/null +++ b/include/HyperNeat/NodeSearchPrms.hpp @@ -0,0 +1,33 @@ +#ifndef __HYPERNEAT_QUERYPLANEPRMS_HPP__ +#define __HYPERNEAT_QUERYPLANEPRMS_HPP__ + +#include <HyperNeat/Utils/Size.hpp> + +namespace hyperneat +{ +    class NeuralNetPrms; + +    class NodeSearchPrms +    { +    public: +        NodeSearchPrms() = default; +        NodeSearchPrms(size_t o, size_t x, size_t y); +        NodeSearchPrms(size_t o, size_t x, size_t y, size_t d); + +        void importFrom(const NeuralNetPrms& nnPrms); + +        size_t _o                    = 0; +        size_t _x                    = 0; +        size_t _y                    = 1; +        bool   _useDistance          = true; +        size_t _d                    = 4; +        size_t _testGridLevel        = 3; +        size_t _maxQuadTreeLevel     = -1; +        size_t _minQuadTreeLevel     = 0; +        double _bandPruningThreshold = 0.3; +        double _varianceThreshold    = 0.03; +        double _divisionThreshold    = 0.03; +    }; +} + +#endif diff --git a/include/HyperNeat/NoveltyMetric.hpp b/include/HyperNeat/NoveltyMetric.hpp new file mode 100644 index 0000000..01a6f75 --- /dev/null +++ b/include/HyperNeat/NoveltyMetric.hpp @@ -0,0 +1,37 @@ +#ifndef __HYPERNEAT_NOVELTY_METRIC_HPP__ +#define __HYPERNEAT_NOVELTY_METRIC_HPP__ + +#include <Hyperneat/Behavior.hpp> +#include <Hyperneat/Utils/Vector2D.hpp> +#include <Hyperneat/NoveltyMetricPrms.hpp> + +namespace hyperneat +{ +    class Population; + +    class NoveltyMetric +    { +    public: +        const NoveltyMetricPrms& getPrms() const; +        const Vector<Behavior>& getBehaviors() const; +        const Vector2D<double>& getArchive() const; + +        Behavior& getBehaviorOf(size_t i); + +    private: +        void initialize(const NoveltyMetricPrms& prms, Population* population = nullptr); +        void setScores(); + +        double getDistance(const Vector<double>& v1, const Vector<double>& v2) const; + +        NoveltyMetricPrms _prms; +        Vector<Behavior>  _behaviors; +        Vector2D<double>  _archive; + +        friend class Behavior; +        friend class LoadFile; +        friend class Population; +    }; +} + +#endif diff --git a/include/HyperNeat/NoveltyMetricPrms.hpp b/include/HyperNeat/NoveltyMetricPrms.hpp new file mode 100644 index 0000000..305d075 --- /dev/null +++ b/include/HyperNeat/NoveltyMetricPrms.hpp @@ -0,0 +1,20 @@ +#ifndef __HYPERNEAT_NOVELTY_METRIC_PRMS_HPP__ +#define __HYPERNEAT_NOVELTY_METRIC_PRMS_HPP__ + +#include <Hyperneat/Utils/Size.hpp> + +namespace hyperneat +{ +    class Population; + +    class NoveltyMetricPrms +    { +    public: +        double _noveltyThreshold         = 10.0; +        size_t _referenceOrganisms       = 15; +        size_t _characterizationSize     = 3; +        bool   _criteriaReachedByDefault = true; +    }; +} + +#endif diff --git a/include/HyperNeat/Organism.hpp b/include/HyperNeat/Organism.hpp new file mode 100644 index 0000000..d35210c --- /dev/null +++ b/include/HyperNeat/Organism.hpp @@ -0,0 +1,71 @@ +#ifndef __HYPERNEAT_ORGANISM_HPP__ +#define __HYPERNEAT_ORGANISM_HPP__ + +#include <HyperNeat/Genome.hpp> +#include <HyperNeat/NeuralNet.hpp> +#include <HyperNeat/Utils/Atomic.hpp> +#include <HyperNeat/Utils/Pointer.hpp> + +namespace hyperneat +{ +    class Behavior; +    class NeuralNet; +    class Population; +    class NeuralNetPrms; + +    class Organism +    { +    public: +        Organism(const Organism& other); +        Organism& operator=(const Organism& other); + +        size_t getIndex() const; + +        void lock(); +        void unlock(); +        bool isLocked() const; + +        void freeze(); +        void unfreeze(); +        bool isFrozen() const; + +        bool isBeingGenerated() const; +        size_t getSpecie() const; +        bool isOld() const; +        size_t getLifetime() const; + +        Behavior& getBehavior(); +        const Genome& getGenome() const; + +        bool isChampion() const; +        Population& getPopulation() const; + +        void createNeuralNet(); + +        Pointer<NeuralNet> _neuralNet; +        double             _fitness = 0.0; + +    private: +        Organism(Population* population); +        Organism(size_t inputs, Population* population); + +        void reset(bool archive = false); + +        size_t       _index            = 0; +        bool         _isLocked         = false; +        bool         _isFrozen         = false; +        Atomic<bool> _isBeingGenerated = {false}; +        size_t       _specie           = 0; +        size_t       _lifetime         = 0; +        Behavior*    _behavior         = nullptr; +        Genome       _genome; + +        Population* _population = nullptr; + +        friend class LoadFile; +        friend class Population; +        friend class NoveltyMetric; +    }; +} + +#endif diff --git a/include/HyperNeat/Population.hpp b/include/HyperNeat/Population.hpp new file mode 100644 index 0000000..6d79d14 --- /dev/null +++ b/include/HyperNeat/Population.hpp @@ -0,0 +1,148 @@ +#ifndef __HYPERNEAT_POPULATION_HPP__ +#define __HYPERNEAT_POPULATION_HPP__ + +#include <HyperNeat/Organism.hpp> +#include <HyperNeat/Innovation.hpp> +#include <HyperNeat/Utils/Random.hpp> +#include <HyperNeat/Utils/Vector.hpp> +#include <HyperNeat/Utils/Pointer.hpp> +#include <HyperNeat/NeuralNetPrms.hpp> +#include <HyperNeat/NoveltyMetric.hpp> +#include <HyperNeat/Utils/Vector2D.hpp> +#include <HyperNeat/Utils/Function.hpp> +#include <HyperNeat/PopulationPrms.hpp> + +namespace hyperneat +{ +    class NeuralNet; +    class NoveltyMetricPrms; + +    class Population +    { +    public: +        void create(const PopulationPrms& popPrms); +        void create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms); +        void create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms, const NoveltyMetricPrms& nmPrms); +        void shutdown(bool resetOrganisms = false, bool archiveOrganisms = false); +        ~Population(); + +        void setMinimumLifetime(size_t lifetime); + +        const PopulationPrms& getPopulationPrms() const; +        const NeuralNetPrms& getNeuralNetPrms() const; +        bool hasNeuralNets() const; +        const Vector<Organism>& getAllOrganisms() const; +        const Vector2D<Organism*>& getSpecies() const; + +        Organism& getOrganism(size_t i); +        Organism& getChampion(); +        const Vector<Organism*>& getSpecie(size_t i) const; + +        void lock(); +        void unlock(); +        bool isLocked() const; + +        void lockOrganism(size_t i); +        void unlockOrganism(size_t i); +        bool isOrganismLocked(size_t i) const; +        bool isAnyOrganismLocked() const; +        size_t getLockedOrganisms() const; + +        void freezeOrganism(size_t i); +        void unfreezeOrganism(size_t i); +        bool isOrganismFrozen(size_t i) const; +        bool isAnyOrganismFrozen() const; +        size_t getFrozenOrganisms() const; + +        bool isOrganismBeingGenerated(size_t i) const; +        bool isAnyOrganismBeingGenerated() const; +        size_t getOrganismsBeingGenerated() const; + +        size_t getReadyOrganisms() const; + +        const Vector<Innovation>& getInnovations() const; +        size_t getInnovationsCount() const; +        size_t getBasicInnovationsCount() const; +        Organism* getLastReplacement(); +        Organism* getLastMother(); +        Organism* getLastFather(); +        size_t getReplacements() const; +        bool recentReplacement() const; +        double getDistanceThreshold() const; +        size_t getOldOrganisms() const; +        size_t getMinimumOldOrganisms() const; +        double getAverageFitness() const; +        double getAverageOldFitness() const; + +        void setNoveltyMetric(const NoveltyMetricPrms& prms); +        void clearNoveltyMetric(); +        bool isNoveltyMetricSet() const; +        const NoveltyMetric& getNoveltyMetric() const; + +        size_t getUpdates() const; + +        double& fitnessOf(size_t i); +        bool update(Function<void(void)> beforeReplacement = []() {}, Function<void(void)> afterReplacement = []() {}); + +    private: +        void generateAllNeuralNets(); + +        void replaceOrganism(); +        Organism* killPoorOrganism(); +        Vector<Organism*>* chooseParentSpecie(); + +        void breedAsexually(Genome& child, const Genome& mother); +        void breedSexually(Genome& child, const Genome& mother, const Genome& father); +        bool mutateNodesAndLinks(Genome& child); + +        void assignToSpecie(Organism& org); +        void organizeSpecies(); +        double computeDistance(const Genome& g1, const Genome& g2) const; + +        size_t getRandSeed() const; +        size_t getRandSize(size_t low, size_t hi); +        double getRandReal(double low, double hi); +        double getRandWeight(); +        double getWeightDeviation(); +        NodeType getRandNodeType(); +        bool getChance(double ratio); + +        PopulationPrms         _prms; +        Pointer<NeuralNetPrms> _nnPrms; +        Vector2D<Organism*>    _species; +        Vector<Organism>       _allOrganisms; + +        bool           _populationLock          = false; +        size_t         _lockedOrganisms         = 0; +        size_t         _frozenOrganisms         = 0; +        Atomic<size_t> _organismsBeingGenerated = {0}; + +        Vector<Innovation> _innovations; +        size_t             _basicInnovs = 0; + +        Organism* _lastReplacement   = nullptr; +        Organism* _lastMother        = nullptr; +        Organism* _lastFather        = nullptr; +        size_t    _replacements      = 0; +        bool      _recentReplacement = false; +        double    _distanceThreshold = 0.0; +        size_t    _oldOrganisms      = 0; +        size_t    _minOldOrganisms   = 0; + +        Pointer<NoveltyMetric> _noveltyMetric; + +        size_t _updates = 0; + +        RandGen  _randGen; +        IntDist  _nodeTypeSelector = IntDist(0, NODE_TYPES_COUNT - 1); +        RealDist _weightSelector   = RealDist(0.0, 1.0); +        BellDist _weightDeviator; +        RealDist _chanceSelector; + +        friend class LoadFile; +        friend class Organism; +        friend class NoveltyMetric; +    }; +} + +#endif diff --git a/include/HyperNeat/PopulationPrms.hpp b/include/HyperNeat/PopulationPrms.hpp new file mode 100644 index 0000000..21a6bc3 --- /dev/null +++ b/include/HyperNeat/PopulationPrms.hpp @@ -0,0 +1,63 @@ +#ifndef __HYPERNEAT_POPULATIONPRMS_HPP__ +#define __HYPERNEAT_POPULATIONPRMS_HPP__ + +// #include <cereal/cereal.hpp> +#include <HyperNeat/Utils/Size.hpp> + +namespace hyperneat +{ +    class PopulationPrms +    { +    public: +        size_t _popSize                  = 200; +        size_t _cppnInputs               = 6; +        size_t _cppnOutputs              = 2; +        size_t _seed                     = 0; +        double _weightRange              = 1.0; +        double _c1Disjoint               = 1.0; +        double _c3WeightDifference       = 0.4; +        double _initialDistanceThreshold = 4.0; +        double _distanceThresholdShift   = 0.3; +        double _sexualReproductionRate   = 0.5; +        double _weightMutationRate       = 0.94; +        double _weightDeviation          = 0.25; +        double _interspeciesMatingRate   = 0.001; +        double _geneDisablingRatio       = 0.75; +        double _linkMutationRate         = 0.03; +        double _nodeMutationRate         = 0.01; +        size_t _targetSpeciesCount       = 8; +        double _eligibilityRatio         = 0.5; +        size_t _minimumLifetime          = 120; +        size_t _replBeforeReorganization = 5; + +    // private: +    //     friend class cereal::access; + +    //     template <class Archive> +    //     void serialize(Archive &ar) +    //     { +    //         ar(CEREAL_NVP(_popSize)); +    //         ar(CEREAL_NVP(_cppnInputs)); +    //         ar(CEREAL_NVP(_cppnOutputs)); +    //         ar(CEREAL_NVP(_seed)); +    //         ar(CEREAL_NVP(_weightRange)); +    //         ar(CEREAL_NVP(_c1Disjoint)); +    //         ar(CEREAL_NVP(_c3WeightDifference)); +    //         ar(CEREAL_NVP(_initialDistanceThreshold)); +    //         ar(CEREAL_NVP(_distanceThresholdShift)); +    //         ar(CEREAL_NVP(_sexualReproductionRate)); +    //         ar(CEREAL_NVP(_weightMutationRate)); +    //         ar(CEREAL_NVP(_weightDeviation)); +    //         ar(CEREAL_NVP(_interspeciesMatingRate)); +    //         ar(CEREAL_NVP(_geneDisablingRatio)); +    //         ar(CEREAL_NVP(_linkMutationRate)); +    //         ar(CEREAL_NVP(_nodeMutationRate)); +    //         ar(CEREAL_NVP(_targetSpeciesCount)); +    //         ar(CEREAL_NVP(_eligibilityRatio)); +    //         ar(CEREAL_NVP(_minimumLifetime)); +    //         ar(CEREAL_NVP(_replBeforeReorganization)); +    //     } +    }; +} + +#endif diff --git a/include/HyperNeat/QuadTree.hpp b/include/HyperNeat/QuadTree.hpp new file mode 100644 index 0000000..8090254 --- /dev/null +++ b/include/HyperNeat/QuadTree.hpp @@ -0,0 +1,30 @@ +#ifndef __HYPERNEAT_QUADTREE_HPP__ +#define __HYPERNEAT_QUADTREE_HPP__ + +#include <HyperNeat/Utils/Vector.hpp> +#include <HyperNeat/Utils/Function.hpp> + +namespace hyperneat +{ +    class QuadTree +    { +    public: +        QuadTree() = default; +        QuadTree(double segment, double x, double y); + +        double getSegment() const; +        double getX() const; +        double getY() const; + +        void subdivide(Function<bool(QuadTree*)> subdivider); +        void traverse(Function<void(const QuadTree*)> traverser) const; + +    private: +        Vector<QuadTree> _children; +        double           _segment = 0.0; +        double           _x       = 0.0; +        double           _y       = 0.0; +    }; +} + +#endif diff --git a/include/HyperNeat/Utils/Atomic.hpp b/include/HyperNeat/Utils/Atomic.hpp new file mode 100644 index 0000000..850a06e --- /dev/null +++ b/include/HyperNeat/Utils/Atomic.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_ATOM_HPP__ +#define __HYPERNEAT_ATOM_HPP__ + +#include <atomic> + +namespace hyperneat +{ +    template <class T> +    using Atomic = std::atomic<T>; +} + +#endif diff --git a/include/HyperNeat/Utils/Function.hpp b/include/HyperNeat/Utils/Function.hpp new file mode 100644 index 0000000..ebcb27b --- /dev/null +++ b/include/HyperNeat/Utils/Function.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_FUNCTION_HPP__ +#define __HYPERNEAT_FUNCTION_HPP__ + +#include <functional> + +namespace hyperneat +{ +    template <class F> +    using Function = std::function<F>; +} + +#endif diff --git a/include/HyperNeat/Utils/LoadFile.hpp b/include/HyperNeat/Utils/LoadFile.hpp new file mode 100644 index 0000000..1960e90 --- /dev/null +++ b/include/HyperNeat/Utils/LoadFile.hpp @@ -0,0 +1,40 @@ +#ifndef __HYPERNEAT_LOADFILE_HPP__ +#define __HYPERNEAT_LOADFILE_HPP__ + +#include <iostream> +#include <HyperNeat/Utils/String.hpp> +#include <HyperNeat/Utils/Vector.hpp> + +namespace hyperneat +{ +    using Istream = std::istream; + +    class Genome; +    class Organism; +    class Population; +    class NoveltyMetric; +    class PopulationPrms; +    class NoveltyMetricPrms; + +    class LoadFile +    { +    public: +        LoadFile(Istream& stream); + +        void loadPopulation(Population& population); +        void loadPopulationPrms(PopulationPrms& prms); +        void loadNeuralNetPrms(NeuralNetPrms& prms); +        void loadNoveltyMetric(NoveltyMetric& noveltyMetric); +        void loadNoveltyMetricPrms(NoveltyMetricPrms& prms); +        void loadOrganism(Organism& organism); +        void loadGenome(Genome& genome); + +    private: +        Istream& nextPrm(bool arrayVal = false); +        Istream& nextArrayValue(); + +        Istream& _stream; +    }; +} + +#endif diff --git a/include/HyperNeat/Utils/Map.hpp b/include/HyperNeat/Utils/Map.hpp new file mode 100644 index 0000000..c735ab3 --- /dev/null +++ b/include/HyperNeat/Utils/Map.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_MAP_HPP__ +#define __HYPERNEAT_MAP_HPP__ + +#include <map> + +namespace hyperneat +{ +    template <class K, class V> +    using Map = std::map<K, V>; +} + +#endif diff --git a/include/HyperNeat/Utils/NodeTypes.hpp b/include/HyperNeat/Utils/NodeTypes.hpp new file mode 100644 index 0000000..815214e --- /dev/null +++ b/include/HyperNeat/Utils/NodeTypes.hpp @@ -0,0 +1,22 @@ +#ifndef __HYPERNEAT_NODETYPES_HPP__ +#define __HYPERNEAT_NODETYPES_HPP__ + +#include <HyperNeat/Utils/String.hpp> + +namespace hyperneat +{ +    enum class NodeType { +        NULL_TYPE = -1, +        SIGMOID   =  0, +        GAUSSIAN  =  1, +        SINE      =  2, +        ABSOLUTE  =  3, +    }; + +    String nodeToString(NodeType type); +    NodeType stringToNode(const String& str); + +    const size_t NODE_TYPES_COUNT = 4; +} + +#endif diff --git a/include/HyperNeat/Utils/Pi.hpp b/include/HyperNeat/Utils/Pi.hpp new file mode 100644 index 0000000..00a3df2 --- /dev/null +++ b/include/HyperNeat/Utils/Pi.hpp @@ -0,0 +1,9 @@ +#ifndef __HYPERNEAT_PI_HPP__ +#define __HYPERNEAT_PI_HPP__ + +namespace hyperneat +{ +    const double PI = 3.14159265359; +} + +#endif diff --git a/include/HyperNeat/Utils/Point.hpp b/include/HyperNeat/Utils/Point.hpp new file mode 100644 index 0000000..ba51bac --- /dev/null +++ b/include/HyperNeat/Utils/Point.hpp @@ -0,0 +1,21 @@ +#ifndef __HYPERNEAT_POINT_HPP__ +#define __HYPERNEAT_POINT_HPP__ + +namespace hyperneat +{ +    class Point +    { +    public: +        Point() = default; +        Point(double x, double y); + +        double distance(const Point& other) const; +        bool operator== (const Point& other) const; +        bool operator< (const Point& other) const; + +        double _x = 0.0; +        double _y = 0.0; +    }; +} + +#endif diff --git a/include/HyperNeat/Utils/Pointer.hpp b/include/HyperNeat/Utils/Pointer.hpp new file mode 100644 index 0000000..f02e853 --- /dev/null +++ b/include/HyperNeat/Utils/Pointer.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_POINTER_HPP__ +#define __HYPERNEAT_POINTER_HPP__ + +#include <memory> + +namespace hyperneat +{ +    template <class T> +    using Pointer = std::unique_ptr<T>; +} + +#endif diff --git a/include/HyperNeat/Utils/Random.hpp b/include/HyperNeat/Utils/Random.hpp new file mode 100644 index 0000000..4a4d979 --- /dev/null +++ b/include/HyperNeat/Utils/Random.hpp @@ -0,0 +1,14 @@ +#ifndef __HYPERNEAT_RANDOM_HPP__ +#define __HYPERNEAT_RANDOM_HPP__ + +#include <random> + +namespace hyperneat +{ +    using RandGen  = std::mt19937_64; +    using IntDist  = std::uniform_int_distribution<size_t>; +    using RealDist = std::uniform_real_distribution<double>; +    using BellDist = std::normal_distribution<double>; +} + +#endif diff --git a/include/HyperNeat/Utils/SaveFile.hpp b/include/HyperNeat/Utils/SaveFile.hpp new file mode 100644 index 0000000..18cad38 --- /dev/null +++ b/include/HyperNeat/Utils/SaveFile.hpp @@ -0,0 +1,45 @@ +#ifndef __HYPERNEAT_SAVEFILE_HPP__ +#define __HYPERNEAT_SAVEFILE_HPP__ + +#include <iostream> +#include <HyperNeat/Utils/String.hpp> +#include <HyperNeat/Utils/Vector.hpp> + +namespace hyperneat +{ +    using Ostream = std::ostream; + +    class Genome; +    class Organism; +    class Population; +    class NoveltyMetric; +    class NeuralNetPrms; +    class PopulationPrms; +    class NoveltyMetricPrms; + +    class SaveFile +    { +    public: +        SaveFile(Ostream& stream); + +        void savePopulation(Population& population, bool shuttedDown = false, size_t tabs = 0, +            const String& prefix = ""); +        void savePopulationPrms(const PopulationPrms& prms, size_t tabs = 0, const String& prefix = ""); +        void saveNeuralNetPrms(const NeuralNetPrms& prms, size_t tabs = 0, const String& prefix = ""); +        void saveOrganism(const Organism& organism, bool shuttedDown = false, size_t tabs = 0, +            const String& prefix = ""); +        void saveGenome(const Genome& genome, size_t tabs = 0, const String& prefix = ""); +        void saveNoveltyMetric(const NoveltyMetric& noveltyMetric, bool shuttedDown = false, size_t tabs = 0, +            const String& prefix = ""); +        void saveNoveltyMetricPrms(const NoveltyMetricPrms& noveltyMetricPrms, size_t tabs = 0, +            const String& prefix = ""); + +    private: +        Ostream& print(size_t tabs = 0); +        String   newl(size_t lines = 1); + +        Ostream& _stream; +    }; +} + +#endif diff --git a/include/HyperNeat/Utils/Set.hpp b/include/HyperNeat/Utils/Set.hpp new file mode 100644 index 0000000..d403e6b --- /dev/null +++ b/include/HyperNeat/Utils/Set.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_SET_HPP__ +#define __HYPERNEAT_SET_HPP__ + +#include <set> + +namespace hyperneat +{ +    template <class V> +    using Set = std::set<V>; +} + +#endif diff --git a/include/HyperNeat/Utils/Size.hpp b/include/HyperNeat/Utils/Size.hpp new file mode 100644 index 0000000..0ef5616 --- /dev/null +++ b/include/HyperNeat/Utils/Size.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_SIZE_HPP__ +#define __HYPERNEAT_SIZE_HPP__ + +#include <cstddef> +#include <climits> + +namespace hyperneat +{ +    using std::size_t; +} + +#endif diff --git a/include/HyperNeat/Utils/String.hpp b/include/HyperNeat/Utils/String.hpp new file mode 100644 index 0000000..ab74d45 --- /dev/null +++ b/include/HyperNeat/Utils/String.hpp @@ -0,0 +1,11 @@ +#ifndef HYPERNEAT_STRING_HPP +#define HYPERNEAT_STRING_HPP + +#include <string> + +namespace hyperneat +{ +    using String = std::string; +} + +#endif diff --git a/include/HyperNeat/Utils/Thread.hpp b/include/HyperNeat/Utils/Thread.hpp new file mode 100644 index 0000000..4b861e3 --- /dev/null +++ b/include/HyperNeat/Utils/Thread.hpp @@ -0,0 +1,11 @@ +#ifndef __HYPERNEAT_THREAD_HPP__ +#define __HYPERNEAT_THREAD_HPP__ + +#include <thread> + +namespace hyperneat +{ +    using Thread = std::thread; +} + +#endif diff --git a/include/HyperNeat/Utils/ValueMap.hpp b/include/HyperNeat/Utils/ValueMap.hpp new file mode 100644 index 0000000..c2910b5 --- /dev/null +++ b/include/HyperNeat/Utils/ValueMap.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_VALUEMAP_HPP__ +#define __HYPERNEAT_VALUEMAP_HPP__ + +#include <HyperNeat/Utils/Vector.hpp> +#include <HyperNeat/Utils/ValuePoint.hpp> + +namespace hyperneat +{ +    using ValueMap = Vector<ValuePoint>; +} + +#endif diff --git a/include/HyperNeat/Utils/ValuePoint.hpp b/include/HyperNeat/Utils/ValuePoint.hpp new file mode 100644 index 0000000..b9e15ab --- /dev/null +++ b/include/HyperNeat/Utils/ValuePoint.hpp @@ -0,0 +1,19 @@ +#ifndef __HYPERNEAT_VALUEPOINT_HPP__ +#define __HYPERNEAT_VALUEPOINT_HPP__ + +#include <HyperNeat/Utils/Point.hpp> + +namespace hyperneat +{ +    class ValuePoint : public Point +    { +    public: +        ValuePoint() = default; +        ValuePoint(double x, double y, double value, double segment); + +        double _value   = 0.0; +        double _segment = 0.0; +    }; +} + +#endif diff --git a/include/HyperNeat/Utils/Vector.hpp b/include/HyperNeat/Utils/Vector.hpp new file mode 100644 index 0000000..f7352e4 --- /dev/null +++ b/include/HyperNeat/Utils/Vector.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_VECTOR_HPP__ +#define __HYPERNEAT_VECTOR_HPP__ + +#include <vector> + +namespace hyperneat +{ +    template <class V> +    using Vector = std::vector<V>; +} + +#endif diff --git a/include/HyperNeat/Utils/Vector2D.hpp b/include/HyperNeat/Utils/Vector2D.hpp new file mode 100644 index 0000000..257dbe6 --- /dev/null +++ b/include/HyperNeat/Utils/Vector2D.hpp @@ -0,0 +1,12 @@ +#ifndef __HYPERNEAT_VECTOR2D_HPP__ +#define __HYPERNEAT_VECTOR2D_HPP__ + +#include <Hyperneat/Utils/Vector.hpp> + +namespace hyperneat +{ +    template <class V> +    using Vector2D = Vector<Vector<V>>; +} + +#endif diff --git a/lib/.keep b/lib/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/.keep diff --git a/obj/.keep b/obj/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/obj/.keep diff --git a/obj/Utils/.keep b/obj/Utils/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/obj/Utils/.keep diff --git a/plugins/CppnExplorer/CppnExplorer.sublime-project b/plugins/CppnExplorer/CppnExplorer.sublime-project new file mode 100644 index 0000000..dee3d7f --- /dev/null +++ b/plugins/CppnExplorer/CppnExplorer.sublime-project @@ -0,0 +1,41 @@ +{ +    "build_systems": +    [ +        { +            "cmd": +            [ +                "make", +                "-C", +                "${project_path}" +            ], +            "name": "Build" +        }, +        { +            "cmd": +            [ +                "make", +                "clean", +                "-C", +                "${project_path}" +            ], +            "name": "Clean" +        } +    ], +    "folders": +    [ +        { +            "file_exclude_patterns": +            [ +                "*.sublime-project", +                "*.sublime-workspace" +            ], +            "folder_exclude_patterns": +            [ +                "obj", +                "lib", +                "Algorithm Documentation" +            ], +            "path": "." +        } +    ] +} diff --git a/plugins/CppnExplorer/CppnExplorer.sublime-workspace b/plugins/CppnExplorer/CppnExplorer.sublime-workspace new file mode 100644 index 0000000..cf691cc --- /dev/null +++ b/plugins/CppnExplorer/CppnExplorer.sublime-workspace @@ -0,0 +1,1199 @@ +{ +	"auto_complete": +	{ +		"selected_items": +		[ +			[ +				"fiel", +				"fieldGenerator" +			], +			[ +				"_ne", +				"_neuralNetReady" +			], +			[ +				"_neu", +				"_neuralNetReady" +			], +			[ +				"_neur", +				"_neuralNet" +			], +			[ +				"setOu", +				"setOutlineColor" +			], +			[ +				"PIX", +				"PIXEL_SIZE" +			], +			[ +				"Neu", +				"Neuron" +			], +			[ +				"IN", +				"INPUT" +			], +			[ +				"setO", +				"setOrigin" +			], +			[ +				"Uin", +				"Uint8" +			], +			[ +				"PI", +				"PIXEL_SIZE" +			], +			[ +				"Neur", +				"Neuron" +			], +			[ +				"Bl", +				"BlendAdd" +			], +			[ +				"_wi", +				"_withNeuralNet" +			], +			[ +				"neura", +				"neuralNetGenerator" +			], +			[ +				"neural", +				"_neuralNetGenerator" +			], +			[ +				"_win", +				"_windowOpen" +			], +			[ +				"eve", +				"event" +			], +			[ +				"joi", +				"joinable" +			], +			[ +				"win", +				"_windowThread" +			], +			[ +				"grid", +				"gridSpacing" +			], +			[ +				"Rende", +				"RenderTarget" +			], +			[ +				"Render", +				"RenderWindow" +			], +			[ +				"sr", +				"srcNeuron" +			], +			[ +				"colo", +				"colorMult" +			], +			[ +				"setOutl", +				"setOutlineThickness" +			], +			[ +				"gri", +				"gridClr" +			], +			[ +				"_sh", +				"_showGrid" +			], +			[ +				"res", +				"resolution" +			], +			[ +				"fie", +				"field" +			], +			[ +				"fi", +				"_field" +			], +			[ +				"out", +				"outputAt" +			], +			[ +				"cpp", +				"_cppn" +			], +			[ +				"_bia", +				"_biasTexture" +			], +			[ +				"in", +				"inputAt" +			], +			[ +				"INV", +				"INV_WEIGHTS" +			], +			[ +				"col", +				"colorInt" +			], +			[ +				"C", +				"CircleShape" +			], +			[ +				"Neural", +				"NeuralNet" +			], +			[ +				"_cur", +				"_cursorPos" +			], +			[ +				"_cu", +				"_cursorPos" +			], +			[ +				"prin", +				"printWeights" +			], +			[ +				"Key", +				"Keyboard" +			], +			[ +				"Cpp", +				"CppnExplorer" +			], +			[ +				"co", +				"Color" +			], +			[ +				"_is", +				"_isLocked" +			], +			[ +				"Ne", +				"Neuron" +			], +			[ +				"_re", +				"_recentReplacement" +			], +			[ +				"re", +				"relateIO" +			], +			[ +				"_in", +				"_inputMap" +			], +			[ +				"en", +				"endl" +			], +			[ +				"_ou", +				"_output" +			], +			[ +				"_", +				"_position" +			], +			[ +				"_out", +				"_outputMap" +			], +			[ +				"pu", +				"previousNeurons" +			], +			[ +				"tem", +				"tempNeurons" +			], +			[ +				"def", +				"default" +			], +			[ +				"gene", +				"generateNeuralNet" +			], +			[ +				"c", +				"const" +			], +			[ +				"ato", +				"atomic_size_t" +			], +			[ +				"db", +				"dbgFileName" +			], +			[ +				"dbg", +				"dbgFileName" +			], +			[ +				"th", +				"threadID" +			], +			[ +				"Pop", +				"PopulationDefaults" +			], +			[ +				"Vec", +				"Vector2D" +			], +			[ +				"wor", +				"worldFile" +			], +			[ +				"ste", +				"onStep" +			], +			[ +				"pr", +				"print" +			], +			[ +				"str", +				"struct	struct" +			], +			[ +				"SE", +				"SELECT_LOAD" +			], +			[ +				"SELE", +				"SELECT_NEW" +			], +			[ +				"pri", +				"printCommand" +			], +			[ +				"com", +				"command" +			], +			[ +				"arg", +				"argv" +			], +			[ +				"org", +				"organismIdx" +			], +			[ +				"spe", +				"specieSize" +			], +			[ +				"nod", +				"nodeType" +			], +			[ +				"loa", +				"loadGenome" +			], +			[ +				"load", +				"loadPopulationPrms" +			], +			[ +				"getCHa", +				"getChampionIdx" +			], +			[ +				"cham", +				"champIdx" +			], +			[ +				"size", +				"size_t" +			], +			[ +				"file", +				"fileName" +			], +			[ +				"fil", +				"fileName" +			], +			[ +				"Po", +				"Population" +			], +			[ +				"File", +				"FileStream" +			], +			[ +				"Fil", +				"FileStream" +			], +			[ +				"Inp", +				"InputFile" +			], +			[ +				"pop", +				"population" +			], +			[ +				"isO", +				"isOrganismBeingGenerated" +			], +			[ +				"isA", +				"isAnyOrganismBeingGenerated" +			], +			[ +				"organ", +				"organismIsBeingGenerated" +			], +			[ +				"_orga", +				"_organismsBeingGenerated" +			], +			[ +				"is", +				"isBeingGenerated" +			], +			[ +				"_or", +				"_organismsBeingGenerated" +			], +			[ +				"_org", +				"_organismIsLocked" +			], +			[ +				"_isL", +				"_isLocked" +			], +			[ +				"organi", +				"_organismsBeingGenerated" +			], +			[ +				"_lock", +				"_lockedOrganisms" +			], +			[ +				"isL", +				"isLockedByReplacement" +			], +			[ +				"si", +				"size_t" +			], +			[ +				"_pop", +				"_populationLock" +			], +			[ +				"leve", +				"levelToSegment" +			], +			[ +				"inc", +				"include" +			], +			[ +				"beg", +				"begin" +			], +			[ +				"dis", +				"distance" +			], +			[ +				"emp", +				"emplace_back" +			], +			[ +				"mu", +				"mutex" +			], +			[ +				"incl", +				"inclIter" +			], +			[ +				"siz", +				"size_t" +			], +			[ +				"cr", +				"crntInclusions" +			], +			[ +				"sour", +				"sourceNeuron" +			], +			[ +				"neuro", +				"_neurons" +			], +			[ +				"syn", +				"synTot" +			], +			[ +				"thre", +				"threadVec" +			], +			[ +				"_organi", +				"_allOrganisms" +			], +			[ +				"poo", +				"poorOrganism" +			], +			[ +				"fta", +				"fatherIdx" +			], +			[ +				"fath", +				"fatherIdx" +			], +			[ +				"fat", +				"fatherIdx" +			], +			[ +				"orga", +				"organismReplaced" +			], +			[ +				"repla", +				"replaceOrganism" +			], +			[ +				"ran", +				"randWeight" +			], +			[ +				"_cpp", +				"_cppnInputs" +			], +			[ +				"_i", +				"_innovationNo" +			], +			[ +				"gen", +				"geneIdx" +			], +			[ +				"ra", +				"randSeed" +			], +			[ +				"_o", +				"_output" +			] +		] +	}, +	"buffers": +	[ +		{ +			"file": "todolist.txt", +			"settings": +			{ +				"buffer_size": 1115, +				"line_ending": "Windows" +			} +		}, +		{ +			"file": "include/CppnExplorer.hpp", +			"settings": +			{ +				"buffer_size": 4318, +				"line_ending": "Windows" +			} +		}, +		{ +			"file": "src/CppnExplorer.cpp", +			"settings": +			{ +				"buffer_size": 17141, +				"line_ending": "Windows" +			} +		} +	], +	"build_system": "Build", +	"command_palette": +	{ +		"height": 375.0, +		"selected_items": +		[ +			[ +				"tas", +				"Tasks: New document" +			], +			[ +				"TAS", +				"Tasks: New document" +			], +			[ +				"", +				"Build: Build" +			], +			[ +				"ops", +				"View: Toggle Open Files in Side Bar" +			] +		], +		"width": 378.0 +	}, +	"console": +	{ +		"height": 118.0, +		"history": +		[ +		] +	}, +	"distraction_free": +	{ +		"menu_visible": true, +		"show_minimap": false, +		"show_open_files": false, +		"show_tabs": false, +		"side_bar_visible": false, +		"status_bar_visible": false +	}, +	"expanded_folders": +	[ +		"/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer" +	], +	"file_history": +	[ +		"/C/Projects/Applications/NeuroRacers/bin/current.population", +		"/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/Makefile", +		"/C/Users/Paul/Downloads/ID/Adobe Indesign CS6/DLL FILE/IMPORTANT.txt", +		"/C/Users/Paul/Downloads/ID/Adobe Indesign CS6/INSTALLING INSTRUCTIONS.txt", +		"/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/CppnExplorer.sublime-project", +		"/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/src/CppnExplorer.cpp", +		"/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/include/CppnExplorer.hpp", +		"/C/TBB/include/tbb/atomic.h", +		"/C/Program Files (x86)/Orbiter/Modules/D3D11Shaders/Planet_Clouds.fx", +		"/C/Program Files (x86)/Orbiter/Modules/D3D11Shaders/Planet.fx", +		"/C/Program Files (x86)/Orbiter/Config/NGPlanetConfig/Earth_ng.cfg", +		"/C/Program Files (x86)/Orbiter/Config/Jupiter.cfg", +		"/C/Program Files (x86)/Orbiter/Config/NGPlanetConfig/Titan_ng.cfg", +		"/C/Program Files (x86)/Orbiter/D3D11Client.cfg", +		"/C/Projects/.git", +		"/C/Projects/New Text Document.txt", +		"/C/Users/Paul/Downloads/orbiter100830/Config/Mars.cfg", +		"/C/Projects/Libraries/HyperNeat/plugins/CppnExplorer/todo", +		"/C/Users/Paul/Downloads/orbiter100830/Config/Earth.cfg", +		"/C/Users/Paul/Downloads/asmi-ovp-1f2ee85a8579/asmi-ovp-1f2ee85a8579/D3D11CLIENT README.txt", +		"/C/Users/Paul/Downloads/orbiter100830/readme.txt", +		"/C/Users/Paul/Downloads/orbiter100830/patch.txt", +		"/C/Sublime Text 3/Data/Packages/User/Preferences.sublime-settings", +		"/C/Users/Paul/Documents/Trabajo/Will Bourdreau/Laurieta Rose/NextStepsBoat.txt", +		"/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/src/CppnExplorer.cpp", +		"/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/Makefile", +		"/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/include/CppnExplorer.hpp", +		"/C/Projects/Libraries/HyperNeat/plugins/cppn.explorer/cppn.explorer.sublime-project", +		"/C/Projects/Libraries/HyperNeat/HyperNeat.sublime-project", +		"/C/Projects/Libraries/HyperNeat/src/Organism.cpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Population.hpp", +		"/C/Projects/Libraries/HyperNeat/src/Population.cpp", +		"/C/Projects/Libraries/HyperNeat/src/NeuralNet.cpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/NeuralNet.hpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Organism.hpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Atomic.hpp", +		"/C/Projects/Libraries/HyperNeat/Makefile", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Future.hpp", +		"/C/Projects/Libraries/HyperNeat/todo", +		"/C/Users/Paul/Downloads/tbb42_20130725oss_win/tbb42_20130725oss/include/tbb/tbb.h", +		"/C/Users/Paul/Downloads/tbb41_20130516oss_src/tbb41_20130516oss_src/tbb41_20130516oss/README.txt", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Vector.hpp", +		"/C/Projects/Libraries/HyperNeat/src/Utils/Point.cpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Point.hpp", +		"/C/Projects/Libraries/HyperNeat/src/QuadTree.cpp", +		"/C/Projects/Libraries/HyperNeat/src/Utils/LoadFile.cpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Atom.hpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Vector2D.hpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Debugger.hpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Thread.hpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Utils/Mutex.hpp", +		"/C/Projects/Libraries/HyperNeat/src/Cppn.cpp", +		"/C/Projects/Libraries/HyperNeat/src/Cppn.s", +		"/C/Users/Paul/Downloads/FitVids.js-master/FitVids.js-master/tests.html", +		"/C/Users/Paul/Downloads/FitVids.js-master/FitVids.js-master/CONTRIBUTING.md", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/StackMacros.hpp", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/PopulationPrms.hpp", +		"/C/Users/Paul/Downloads/Ida Pro v6.1/READ ME !!.txt", +		"/C/Projects/Libraries/HyperNeat/src/QueryPlanePrms.cpp", +		"/C/Projects/Libraries/HyperNeat/src/Utils/SaveFile.cpp", +		"/C/SFML/build-debug/CMakeCache.txt", +		"/C/Box2D/build-debug/CMakeCache.txt", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Genome.hpp", +		"/C/Projects/Applications/NeuroRacers/bin/population", +		"/C/Projects/Libraries/HyperNeat/include/HyperNeat/Cppn.hpp", +		"/C/SFML/build-dynamic/CMakeCache.txt", +		"/C/Box2D/build-dynamic/CMakeCache.txt", +		"/C/Projects/Libraries/HyperNeat/src/Utils/TEMP_Vector.cpp", +		"/C/Projects/Applications/HyperGuppies/Makefile", +		"/C/Projects/Applications/Guppies SFML/SimBase_Execute.cpp", +		"/C/Projects/Applications/HyperGuppies/include/Utils/String.hpp", +		"/C/Projects/Applications/HyperGuppies/todo", +		"/C/Programming/Applications/HyperGuppies/include/Utils/RLUtils.hpp", +		"/C/Programming/Applications/HyperGuppies/include/WorldParams.hpp", +		"/C/Users/Paul/Downloads/pdc25_vc_w32/README", +		"/C/Programming/Applications/HyperGuppies/bin/worlds/default.world", +		"/C/Programming/Applications/HyperGuppies/include/Utils/File.hpp", +		"/C/Programming/Applications/HyperGuppies/Makefile", +		"/C/Programming/Applications/HyperGuppies/HyperGuppies.sublime-project", +		"/C/Programming/Applications/Guppies SFML/Params.hpp", +		"/C/Users/Paul/Downloads/SFML/SFML-master/CMakeLists.txt", +		"/C/Programming/Applications/HyperGuppies/include/Utils/Function.hpp", +		"/C/Users/Paul/Downloads/RBTray-4_3/readme.txt", +		"/C/Programming/Applications/HyperGuppies/src/Main.cpp", +		"/C/Programming/Applications/HyperGuppies/todo", +		"/C/RLUtil/RLUtil.hpp", +		"/C/Users/Paul/Downloads/PlainTasks-master/PlainTasks-master/Readme.md", +		"/C/Programming/Applications/HyperGuppies/include/App.hpp", +		"/C/Programming/Applications/HyperGuppies/src/App.cpp", +		"/C/Users/Paul/Downloads/rlutil-master/rlutil-master/rlutil.hpp", +		"/C/Users/Paul/Downloads/rlutil-master/rlutil-master/example.c", +		"/C/Users/Paul/Downloads/rlutil-master/rlutil-master/test.cpp", +		"/C/Users/Paul/Downloads/rlutil-master/rlutil-master/rlutil.h", +		"/C/Box2D/include/Common/b2Settings.h", +		"/C/Users/Paul/Desktop/Box2D/Box2D/Common/b2Settings.h", +		"/C/Users/Paul/Desktop/Box2D/CMakeLists.txt", +		"/C/Users/Paul/Desktop/Box2D/Box2D/CMakeLists.txt", +		"/C/Programming/Libraries/HyperNeat/Makefile", +		"/C/Users/Paul/Downloads/neuro.3.0.3/neuro/style.css", +		"/C/Users/Paul/Downloads/tapio-rlutil-c49f5ae/tapio-rlutil-c49f5ae/rlutil.h", +		"/C/Programming/Libraries/HyperNeat/src/Utils/LoadFile.cpp", +		"/C/Programming/Applications/NeuroRacers/bin/population", +		"/C/Programming/Libraries/HyperNeat/todo", +		"/C/Programming/Libraries/HyperNeat/include/Population.hpp", +		"/C/Programming/Libraries/HyperNeat/include/Utils/LoadFile.hpp", +		"/C/Programming/Libraries/HyperNeat/src/Utils/SaveFile.cpp", +		"/C/Programming/Libraries/HyperNeat/include/Utils/SaveFile.hpp", +		"/C/Programming/Libraries/HyperNeat/include/Organism.hpp", +		"/C/Users/Paul/Desktop/Box2D_v2.2.1/Box2D/Common/b2Settings.h", +		"/C/Users/Paul/Desktop/Box2D_v2.2.1/Building.txt", +		"/C/Users/Paul/Desktop/Box2D_v2.2.1/Box2D/Box2D.h", +		"/C/Users/Paul/Desktop/Box2D_v2.2.1/Readme.txt", +		"/C/Programming/Libraries/HyperNeat/src/Genome.cpp", +		"/C/Programming/Libraries/HyperNeat/include/Genome.hpp", +		"/C/Programming/Libraries/HyperNeat/src/Cppn.cpp", +		"/C/Programming/Libraries/HyperNeat/include/Cppn.hpp", +		"/C/Programming/Libraries/HyperNeat/src/Organism.cpp", +		"/C/Programming/Libraries/HyperNeat/src/Population.cpp", +		"/C/Box2D/src/Dynamics/b2World.cpp", +		"/C/Box2D/src/Dynamics/b2World.h", +		"/C/Box2D/src/Dynamics/b2WorldCallbacks.h", +		"/C/Programming/Libraries/HyperNeat/include/Utils/NodeTypes.hpp", +		"/C/Programming/Libraries/HyperNeat/include/Utils/String.hpp", +		"/C/Programming/Libraries/HyperNeat/src/LoadSaveSystem.cpp", +		"/C/Programming/Libraries/HyperNeat/include/LoadSaveSystem.hpp", +		"/C/Programming/Libraries/HyperNeat/include/Saver.hpp", +		"/C/Programming/Libraries/HyperNeat/src/Utils/File.cpp", +		"/C/Programming/Libraries/HyperNeat/include/Utils/File.hpp" +	], +	"find": +	{ +		"height": 36.0 +	}, +	"find_in_files": +	{ +		"height": 92.0, +		"where_history": +		[ +			"" +		] +	}, +	"find_state": +	{ +		"case_sensitive": true, +		"find_history": +		[ +			"BlendMode", +			"fieldGenerator", +			"value", +			"_grid", +			"223", +			"refNeuron", +			"0", +			"PIXEL_SIZE", +			"cout", +			"_windowOpen", +			"64", +			"bias", +			"pos", +			"bias", +			"PIXEL", +			"CPPN_EX_WIDTH", +			"_withNeuralNet", +			"600", +			"512", +			"_window", +			"System", +			"Graphics", +			"RenderWindow", +			"WIN", +			"sf::", +			"gridClr", +			"64", +			"sf::", +			" = nullptr", +			"16", +			"128", +			"=", +			"_resolution", +			"SunDir", +			"16", +			"128", +			"32", +			"sf::Uint8", +			"Alpha", +			"sf::Color::White", +			"{ 0, 0, 0, 0 }", +			"sf::Color::Black", +			"Add", +			"2", +			"1.0f", +			"Thickness", +			"setOrigin", +			"0", +			"_uiColor", +			"0.0", +			"resolution", +			"Neurons", +			"\\", +			"{ 0, 0, 0 }", +			"_uiColor", +			"6", +			"8", +			"10", +			"3", +			"_uiColor", +			"{ 0, 0, 0 }", +			", 128", +			"PIXEL * 1.0f", +			"6", +			"4", +			"0", +			"_cppn.outputAt(0)", +			"_valueImage.", +			"bias", +			"mage", +			"val", +			"*", +			"{ 0, 0, 0, 128 }", +			"_uiColor", +			"4.", +			"3.0", +			"2", +			"1.5", +			"colorInt / 2", +			"radius", +			"_body", +			"64", +			"0", +			"20", +			"128", +			"20.0", +			"16", +			"10.0", +			"0.025f", +			"2", +			"4", +			"x1", +			"1", +			"x", +			"_weight", +			"64", +			"PIXEL", +			"0.008f", +			"0", +			"_body", +			"128", +			"0.1", +			"Scale", +			"H", +			", 2, sf::Lines", +			")", +			"sf::Vertex(", +			"sf::Vector2f", +			"Color", +			"cursor", +			"cVal", +			"weight", +			"_cppn", +			"weight", +			"_cppn", +			"cVal", +			" - cBias", +			"abs(", +			"cVal", +			"val", +			"static_cast<double>(", +			"0", +			"int", +			"int(255)", +			"sf::Uint8", +			"float", +			"x", +			"cppn" +		], +		"highlight": true, +		"in_selection": false, +		"preserve_case": false, +		"regex": true, +		"replace_history": +		[ +			"_" +		], +		"reverse": false, +		"show_context": true, +		"use_buffer2": true, +		"whole_word": false, +		"wrap": true +	}, +	"groups": +	[ +		{ +			"selected": 2, +			"sheets": +			[ +				{ +					"buffer": 0, +					"file": "todolist.txt", +					"semi_transient": false, +					"settings": +					{ +						"buffer_size": 1115, +						"regions": +						{ +						}, +						"selection": +						[ +							[ +								363, +								363 +							] +						], +						"settings": +						{ +							"BracketHighlighterBusy": false, +							"bh_regions": +							[ +								"bh_double_quote", +								"bh_double_quote_center", +								"bh_double_quote_open", +								"bh_double_quote_close", +								"bh_square", +								"bh_square_center", +								"bh_square_open", +								"bh_square_close", +								"bh_regex", +								"bh_regex_center", +								"bh_regex_open", +								"bh_regex_close", +								"bh_curly", +								"bh_curly_center", +								"bh_curly_open", +								"bh_curly_close", +								"bh_angle", +								"bh_angle_center", +								"bh_angle_open", +								"bh_angle_close", +								"bh_tag", +								"bh_tag_center", +								"bh_tag_open", +								"bh_tag_close", +								"bh_default", +								"bh_default_center", +								"bh_default_open", +								"bh_default_close", +								"bh_round", +								"bh_round_center", +								"bh_round_open", +								"bh_round_close", +								"bh_unmatched", +								"bh_unmatched_center", +								"bh_unmatched_open", +								"bh_unmatched_close", +								"bh_single_quote", +								"bh_single_quote_center", +								"bh_single_quote_open", +								"bh_single_quote_close" +							], +							"syntax": "Packages/PlainTasks/PlainTasks.tmLanguage", +							"tab_size": 2, +							"translate_tabs_to_spaces": true +						}, +						"translation.x": 0.0, +						"translation.y": 0.0, +						"zoom_level": 1.0 +					}, +					"stack_index": 2, +					"type": "text" +				}, +				{ +					"buffer": 1, +					"file": "include/CppnExplorer.hpp", +					"semi_transient": false, +					"settings": +					{ +						"buffer_size": 4318, +						"regions": +						{ +						}, +						"selection": +						[ +							[ +								391, +								391 +							] +						], +						"settings": +						{ +							"BracketHighlighterBusy": false, +							"bh_regions": +							[ +								"bh_double_quote", +								"bh_double_quote_center", +								"bh_double_quote_open", +								"bh_double_quote_close", +								"bh_square", +								"bh_square_center", +								"bh_square_open", +								"bh_square_close", +								"bh_regex", +								"bh_regex_center", +								"bh_regex_open", +								"bh_regex_close", +								"bh_curly", +								"bh_curly_center", +								"bh_curly_open", +								"bh_curly_close", +								"bh_angle", +								"bh_angle_center", +								"bh_angle_open", +								"bh_angle_close", +								"bh_tag", +								"bh_tag_center", +								"bh_tag_open", +								"bh_tag_close", +								"bh_default", +								"bh_default_center", +								"bh_default_open", +								"bh_default_close", +								"bh_round", +								"bh_round_center", +								"bh_round_open", +								"bh_round_close", +								"bh_unmatched", +								"bh_unmatched_center", +								"bh_unmatched_open", +								"bh_unmatched_close", +								"bh_single_quote", +								"bh_single_quote_center", +								"bh_single_quote_open", +								"bh_single_quote_close" +							], +							"syntax": "Packages/C++ Starting Kit/CCpp.tmLanguage", +							"tab_size": 4, +							"translate_tabs_to_spaces": true +						}, +						"translation.x": 0.0, +						"translation.y": 0.0, +						"zoom_level": 1.0 +					}, +					"stack_index": 1, +					"type": "text" +				}, +				{ +					"buffer": 2, +					"file": "src/CppnExplorer.cpp", +					"semi_transient": false, +					"settings": +					{ +						"buffer_size": 17141, +						"regions": +						{ +						}, +						"selection": +						[ +							[ +								1778, +								1778 +							] +						], +						"settings": +						{ +							"BracketHighlighterBusy": false, +							"bh_regions": +							[ +								"bh_single_quote", +								"bh_single_quote_center", +								"bh_single_quote_open", +								"bh_single_quote_close", +								"bh_unmatched", +								"bh_unmatched_center", +								"bh_unmatched_open", +								"bh_unmatched_close", +								"bh_round", +								"bh_round_center", +								"bh_round_open", +								"bh_round_close", +								"bh_default", +								"bh_default_center", +								"bh_default_open", +								"bh_default_close", +								"bh_square", +								"bh_square_center", +								"bh_square_open", +								"bh_square_close", +								"bh_regex", +								"bh_regex_center", +								"bh_regex_open", +								"bh_regex_close", +								"bh_curly", +								"bh_curly_center", +								"bh_curly_open", +								"bh_curly_close", +								"bh_angle", +								"bh_angle_center", +								"bh_angle_open", +								"bh_angle_close", +								"bh_tag", +								"bh_tag_center", +								"bh_tag_open", +								"bh_tag_close", +								"bh_double_quote", +								"bh_double_quote_center", +								"bh_double_quote_open", +								"bh_double_quote_close" +							], +							"syntax": "Packages/C++ Starting Kit/CCpp.tmLanguage", +							"tab_size": 4, +							"translate_tabs_to_spaces": true +						}, +						"translation.x": 0.0, +						"translation.y": 828.0, +						"zoom_level": 1.0 +					}, +					"stack_index": 0, +					"type": "text" +				} +			] +		} +	], +	"incremental_find": +	{ +		"height": 0.0 +	}, +	"input": +	{ +		"height": 30.0 +	}, +	"layout": +	{ +		"cells": +		[ +			[ +				0, +				0, +				1, +				1 +			] +		], +		"cols": +		[ +			0.0, +			1.0 +		], +		"rows": +		[ +			0.0, +			1.0 +		] +	}, +	"menu_visible": false, +	"output.exec": +	{ +		"height": 96.0 +	}, +	"output.find_results": +	{ +		"height": 0.0 +	}, +	"project": "CppnExplorer.sublime-project", +	"replace": +	{ +		"height": 64.0 +	}, +	"save_all_on_build": true, +	"select_file": +	{ +		"height": 0.0, +		"selected_items": +		[ +		], +		"width": 0.0 +	}, +	"select_project": +	{ +		"height": 500.0, +		"selected_items": +		[ +			[ +				"", +				"C:\\Projects\\Libraries\\HyperNeat\\HyperNeat.sublime-project" +			] +		], +		"width": 805.0 +	}, +	"select_symbol": +	{ +		"height": 0.0, +		"selected_items": +		[ +		], +		"width": 0.0 +	}, +	"settings": +	{ +	}, +	"show_minimap": true, +	"show_open_files": false, +	"show_tabs": true, +	"side_bar_visible": true, +	"side_bar_width": 160.0, +	"status_bar_visible": true, +	"template_settings": +	{ +	} +} diff --git a/plugins/CppnExplorer/Makefile b/plugins/CppnExplorer/Makefile new file mode 100644 index 0000000..0d31499 --- /dev/null +++ b/plugins/CppnExplorer/Makefile @@ -0,0 +1,19 @@ +LIBRARY := lib/libCppnExplorer.a +SOURCES := $(wildcard src/*.cpp) +OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES)) +DEPS    := $(patsubst %.o,%.d,$(OBJECTS)) +CFLAGS  := -c -O3 -Wall -std=c++11 -MMD -Iinclude -I../../include -IC:/SFML/include +LFLAGS  := rvs + +all: $(OBJECTS) +	ar $(LFLAGS) $(LIBRARY) $(OBJECTS) + +-include $(DEPS) + +$(OBJECTS): $(patsubst obj/%.o,src/%.cpp,$@) +	g++ $(CFLAGS) $(patsubst obj/%.o,src/%.cpp,$@) -o $@ + +clean: +	del lib\*.a +	del obj\*.o +	del obj\*.d diff --git a/plugins/CppnExplorer/include/CppnExplorer.hpp b/plugins/CppnExplorer/include/CppnExplorer.hpp new file mode 100644 index 0000000..5ca20c5 --- /dev/null +++ b/plugins/CppnExplorer/include/CppnExplorer.hpp @@ -0,0 +1,129 @@ +#ifndef __CPPN_EXPLORER_HPP__ +#define __CPPN_EXPLORER_HPP__ + +#include <Hyperneat/Cppn.hpp> +#include <Hyperneat/Genome.hpp> +#include <Hyperneat/NeuralNet.hpp> +#include <SFML/Graphics/Texture.hpp> +#include <HyperNeat/Utils/Atomic.hpp> +#include <HyperNeat/Utils/Thread.hpp> +#include <Hyperneat/NeuralNetPrms.hpp> +#include <SFML/Graphics/VertexArray.hpp> +#include <SFML/Graphics/CircleShape.hpp> +#include <SFML/Graphics/RenderWindow.hpp> +#include <SFML/Graphics/RectangleShape.hpp> + +namespace hyperneat +{ +    class CppnExplorer +    { +    public: +        CppnExplorer(); +        ~CppnExplorer(); + +        void run(const Genome& genome, const NeuralNetPrms* nnPrms = nullptr, sf::RenderTarget* target = nullptr); +        void shutdown(); +        void draw(); + +        // void run(const Genome& genome, const NeuralNetPrms& nnPrms); +        // void shutdown(); + +    private: +        void windowHandler(); +        void eventHandler(); +        void neuralNetGenerator(); +        void fieldGenerator(); + +        class Neuron +        { +        public: +            Neuron(const NeuralNet::Neuron& refNeuron); + +            sf::VertexArray _synapses = sf::VertexArray(sf::Lines); +            sf::CircleShape _nucleus  = sf::CircleShape(4.0f * PIXEL_SIZE, 12); +        }; + +        Cppn           _cppn; +        Genome         _genome; +        NeuralNetPrms  _nnPrms; +        Vector<Neuron> _neurons; +        NeuralNet      _neuralNet; +        bool           _withNeuralNet  = false; +        Atomic<bool>   _neuralNetReady = {false}; + +        sf::RenderWindow  _window; +        Atomic<bool>      _windowOpen = {false}; +        sf::RenderTarget* _target     = nullptr; +        const sf::Color   _uiColor    = {255, 255, 255, 8}; + +        sf::Image          _fieldImage; +        sf::RectangleShape _fieldSprite; +        sf::Texture        _fieldTexture; +        size_t             _currentField = 0; +        Atomic<bool>       _fieldReady   = {false}; + +        Thread _windowHandler; +        Thread _fieldGenerator; +        Thread _neuralNetGenerator; + +        static constexpr unsigned RESOLUTION = 512; +        static constexpr float    PIXEL_SIZE = 1.0f / static_cast<float>(RESOLUTION); + +        // class Neuron +        // { +        // public: +        //     enum class Type { +        //         INPUT, +        //         HIDDEN, +        //         OUTPUT +        //     }; + +        //     Type            _type; +        //     sf::CircleShape _body     = sf::CircleShape(0.0f, 30); +        //     sf::CircleShape _nucleus  = sf::CircleShape(0.0f, 30); +        //     sf::VertexArray _synapses = sf::VertexArray(sf::Lines); +        // }; + +        // void print(const sf::Color* field); +        // void placeCursorAt(const sf::Vector2f& newPos); +        // void createNeuron(Neuron& repNeuron, const NeuralNet::Neuron& srcNeuron); + +        // Cppn          _cppn; +        // Genome        _genome; +        // NeuralNet     _neuralNet; +        // NeuralNetPrms _nnPrms; + +        // const unsigned   RESOLUTION = 512; +        // sf::RenderWindow _window; +        // Atomic<bool>     _running; +        // Thread           _executor; + +        // const sf::Color  WEIGHTS      = { 128,   0, 255 }; +        // const sf::Color  INV_WEIGHTS  = { 255,   0, 128 }; +        // const sf::Color  BIAS         = {   0, 255, 255 }; +        // const sf::Color* _field       = &WEIGHTS; + +        // sf::Image          _valueImage; +        // sf::Texture        _valueTexture; +        // sf::RectangleShape _valueSprite; +        // sf::Image          _biasImage; +        // sf::Texture        _biasTexture; +        // sf::RectangleShape _biasSprite; +        // bool               _showBias = false; + +        // const sf::Color _uiColor = { 64, 64, 64 }; +        // const float     PIXEL    = 1.0f / static_cast<float>(RESOLUTION); + +        // sf::Vector2f       _cursorPos = { 0.0f, 0.0f }; +        // sf::RectangleShape _cursorH   = sf::RectangleShape(sf::Vector2f(0.2f, PIXEL * 3.0f)); +        // sf::RectangleShape _cursorV   = sf::RectangleShape(sf::Vector2f(PIXEL * 3.0f, 0.2f)); +        // sf::VertexArray    _grid      = sf::VertexArray(sf::Lines); + +        // bool           _showField   = true; +        // bool           _showNeurons = true; +        // bool           _showGrid    = true; +        // Vector<Neuron> _neurons; +    }; +} + +#endif diff --git a/plugins/CppnExplorer/lib/.keep b/plugins/CppnExplorer/lib/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/CppnExplorer/lib/.keep diff --git a/plugins/CppnExplorer/obj/.keep b/plugins/CppnExplorer/obj/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/CppnExplorer/obj/.keep diff --git a/plugins/CppnExplorer/src/CppnExplorer.cpp b/plugins/CppnExplorer/src/CppnExplorer.cpp new file mode 100644 index 0000000..555922a --- /dev/null +++ b/plugins/CppnExplorer/src/CppnExplorer.cpp @@ -0,0 +1,549 @@ +#include <CppnExplorer.hpp> +#include <SFML/Window/Event.hpp> +#include <HyperNeat/Utils/Point.hpp> + +using namespace sf; +using namespace hyperneat; + +CppnExplorer::CppnExplorer() +{ +    _fieldSprite.setOrigin(1.0f, 1.0f); +    _fieldSprite.setPosition(0.0f, 0.0f); +    _fieldSprite.setTexture(&_fieldTexture); +    _fieldSprite.setSize(Vector2f(2.0f, 2.0f)); +    _fieldImage.create(RESOLUTION, RESOLUTION); +} + +CppnExplorer::~CppnExplorer() +{ +    shutdown(); +} + +void +CppnExplorer::run(const Genome& genome, const NeuralNetPrms* nnPrms, RenderTarget* target) +{ +    shutdown(); +    _target = target; +    _genome = genome; + +    _cppn.clear(); +    _cppn.create(_genome); + +    if (nnPrms) { +        _withNeuralNet      = true; +        _nnPrms             = *nnPrms; +        _neuralNetGenerator = Thread(&CppnExplorer::neuralNetGenerator, this); +    } + +    if (!_target) { +        _windowOpen    = true; +        _target        = &_window; +        _windowHandler = Thread(&CppnExplorer::windowHandler, this); +    } + +    _fieldGenerator = Thread(&CppnExplorer::fieldGenerator, this); +} + +void +CppnExplorer::shutdown() +{ +    if (_neuralNetGenerator.joinable()) { +        _neuralNetGenerator.join(); +    } + +    if (_windowHandler.joinable()) { +        _windowOpen = false; +        _windowHandler.join(); +    } + +    _neurons.clear(); +    _withNeuralNet  = false; +    _neuralNetReady = false; +    _windowOpen     = false; +    _target         = nullptr; +} + +void +CppnExplorer::draw() +{ +    _target->clear({8, 8, 16}); + +    if (_neuralNetReady) { +        for (auto& i : _neurons) { +            _target->draw(i._synapses, BlendAdd); +        } + +        for (auto& i : _neurons) { +            _target->draw(i._nucleus, BlendAdd); +        } +    } + +    if (_windowOpen) { +        _window.display(); +    } +} + +void +CppnExplorer::windowHandler() +{ +    ContextSettings settings(0, 0, 8); +    String          title("Cppn Explorer"); +    View            view({-1.0f, -1.0f, 2.0f, 2.0f}); +    VideoMode       videoMode(RESOLUTION, RESOLUTION); +    Uint32          style(Style::Titlebar | Style::Close); + +    _window.create(videoMode, title, style, settings); +    _window.setVerticalSyncEnabled(true); +    _window.setView(view); + +    while (_windowOpen) { +        eventHandler(); +        draw(); +    } +} + +void +CppnExplorer::eventHandler() +{ +    Event event; + +    while (_window.pollEvent(event)) { +        switch (event.type) { +            case Event::Closed: +                _windowOpen = false; +                break; + +            default:; +        } +    } +} + +void +CppnExplorer::neuralNetGenerator() +{ +    _neuralNet.clear(); +    _neuralNet.create(_cppn, _nnPrms); + +    _neurons.reserve(_neuralNet.getNeurons().size()); + +    for (auto& i : _neuralNet.getNeurons()) { +        _neurons.emplace_back(i); +    } + +    _neuralNetReady = true; +} + +void +CppnExplorer::fieldGenerator() +{ + +} + +CppnExplorer::Neuron::Neuron(const NeuralNet::Neuron& refNeuron) +{ +    _nucleus.setPosition(refNeuron._position._x, refNeuron._position._y); +    _nucleus.setOrigin(_nucleus.getRadius(), _nucleus.getRadius()); + +    Color nColor = (refNeuron._bias > 0.0 ? Color::White : Color::Red); +    nColor.a     = static_cast<Uint8>(fabs((refNeuron._bias / 3.0) * 112.0) + 16.0); +    _nucleus.setFillColor(nColor); + +    switch (refNeuron._type) { +        case NeuralNet::Neuron::Type::INPUT: +            _nucleus.setOutlineThickness(4.0f * PIXEL_SIZE); +            _nucleus.setOutlineColor({255, 255, 255, nColor.a}); +            break; + +        case NeuralNet::Neuron::Type::OUTPUT: +            _nucleus.setOutlineThickness(4.0f * PIXEL_SIZE); +            _nucleus.setOutlineColor({255, 0, 0, nColor.a}); +            break; + +        default:; +    } + +    for (auto& i : refNeuron._synapses) { +        auto iNeuron  = *i._neuron; +        Color sColor  = (i._weight > 0.0 ? Color::White : Color::Red); +        sColor.a      = static_cast<Uint8>(fabs((i._weight / 3.0) * 112.0) + 16.0); +        Vector2f iPos = {static_cast<float>(iNeuron._position._x), static_cast<float>(iNeuron._position._y)}; +        Vector2f tPos = {static_cast<float>(refNeuron._position._x), static_cast<float>(refNeuron._position._y)}; + +        _synapses.append({iPos, sColor}); +        _synapses.append({tPos, sColor}); +    } +} + +// void +// CppnExplorer::run(const Genome& genome, const NeuralNetPrms& nnPrms) +// { +//     shutdown(); + +//     _genome = genome; +//     _nnPrms = nnPrms; + +//     _cppn.create(_genome); +//     _neuralNet.create(_cppn, _nnPrms); + +//     { +//         float gridStep    = 2.0f / 16.0f; +//         Color gridClr = _uiColor; +//         gridClr.a         = 64; + +//         for (float i = -1.0f; i <= 1.0f; i += gridStep) { +//             _grid.append({{ -1.0f,     i }, gridClr }); +//             _grid.append({{  1.0f,     i }, gridClr }); +//             _grid.append({{     i, -1.0f }, gridClr }); +//             _grid.append({{     i,  1.0f }, gridClr }); +//         } +//     } + +//     _executor = Thread([&]() { +//         _running = true; + +//         { +//             VideoMode       videoMode(RESOLUTION, RESOLUTION); +//             String          title("Cppn Explorer"); +//             Uint32          style(Style::Titlebar | Style::Close); +//             ContextSettings settings(0, 0, 8); +//             View            view(FloatRect(-1.0f, -1.0f, 2.0f, 2.0f)); + +//             _window.create(videoMode, title, style, settings); +//             _window.setVerticalSyncEnabled(true); +//             _window.setView(view); +//         } + +//         _cppn.inputAt(5) = 1.0; + +//         _valueImage.create(RESOLUTION, RESOLUTION); +//         _biasImage.create(RESOLUTION, RESOLUTION); +//         print(&WEIGHTS); +//         print(&BIAS); + +//         _valueSprite.setTexture(&_valueTexture); +//         _valueSprite.setSize(Vector2f(2.0f, 2.0f)); +//         _valueSprite.setOrigin(1.0f, 1.0f); +//         _valueSprite.setPosition(0.0f, 0.0f); + +//         _biasSprite.setTexture(&_biasTexture); +//         _biasSprite.setSize(Vector2f(2.0f, 2.0f)); +//         _biasSprite.setOrigin(1.0f, 1.0f); +//         _biasSprite.setPosition(0.0f, 0.0f); + +//         _cursorH.setFillColor(_uiColor); +//         _cursorV.setFillColor(_uiColor); +//         _cursorH.setOrigin(_cursorH.getSize() / 2.0f); +//         _cursorV.setOrigin(_cursorV.getSize() / 2.0f); +//         _cursorH.setOutlineThickness(PIXEL); +//         _cursorV.setOutlineThickness(PIXEL); +//         _cursorH.setOutlineColor({ 128, 128, 128 }); +//         _cursorV.setOutlineColor({ 128, 128, 128 }); + +//         _neurons.reserve(_neuralNet.getNeuronsCount()); + +//         for (auto& i : _neuralNet.getNeurons()) { +//             _neurons.emplace_back(); +//             createNeuron(_neurons.back(), i); +//         } + +//         while (_running) { +//             Event event; + +//             while (_window.pollEvent(event)) { +//                 switch (event.type) { +//                     case Event::KeyPressed: +//                         switch (event.key.code) { +//                             case Keyboard::B: +//                                 _showBias = !_showBias; +//                                 break; + +//                             case Keyboard::C: +//                                 placeCursorAt({ 0.0f, 0.0f }); +//                                 print(_field); +//                                 break; + +//                             case Keyboard::F: +//                                 _field == &WEIGHTS ? ++_field : --_field; +//                                 print(_field); +//                                 break; + +//                             case Keyboard::V: +//                                 _showField = !_showField; +//                                 break; + +//                             case Keyboard::N: +//                                 _showNeurons = !_showNeurons; +//                                 break; + +//                             case Keyboard::G: +//                                 _showGrid = !_showGrid; +//                                 break; + +//                             default:; +//                         } + +//                         break; + +//                     case Event::MouseButtonPressed: +//                         if (event.mouseButton.button == Mouse::Left) { +//                             placeCursorAt(_window.mapPixelToCoords(Mouse::getPosition(_window))); +//                             print(_field); +//                         } + +//                         break; + +//                     case Event::Closed: +//                         _running = false; +//                         break; + +//                     default:; +//                 } +//             } + +//             _window.clear({ 8, 8, 16 }); + +//             if (_showField) { +//                 if (_showBias) { +//                     _window.draw(_biasSprite); +//                 } else { +//                     _window.draw(_valueSprite); +//                 } +//             } + +//             if (_showGrid) { +//                 _window.draw(_grid, { BlendMode::BlendAdd }); +//             } + +//             if (_showNeurons) { +//                 for (auto& i : _neurons) { +//                     _window.draw(i._synapses); +//                 } + +//                 for (auto& i : _neurons) { +//                     if (i._type != Neuron::Type::HIDDEN) { +//                         continue; +//                     } + +//                     _window.draw(i._body); +//                     _window.draw(i._nucleus); +//                 } + +//                 for (auto& i : _neurons) { +//                     if (i._type == Neuron::Type::HIDDEN) { +//                         continue; +//                     } + +//                     _window.draw(i._body); +//                     _window.draw(i._nucleus); +//                 } +//             } + +//             _window.draw(_cursorH); +//             _window.draw(_cursorV); + +//             _window.display(); +//         } +//     }); +// } + +// void +// CppnExplorer::shutdown() +// { +//     if (_executor.joinable()) { +//         _running = false; +//         _executor.join(); +//     } + +//     this->~CppnExplorer(); +//     new (this) CppnExplorer(); +// } + +// void +// CppnExplorer::print(const Color* field) +// { +//     size_t       out     = 0; +//     double*      x1      = nullptr; +//     double*      y1      = nullptr; +//     double*      x2      = nullptr; +//     double*      y2      = nullptr; +//     Image*   image   = nullptr; +//     Texture* texture = nullptr; + +//     if (field == &WEIGHTS) { +//         x1 = &_cppn.inputAt(0); +//         y1 = &_cppn.inputAt(1); +//         x2 = &_cppn.inputAt(2); +//         y2 = &_cppn.inputAt(3); +//     } else { +//         x1 = &_cppn.inputAt(2); +//         y1 = &_cppn.inputAt(3); +//         x2 = &_cppn.inputAt(0); +//         y2 = &_cppn.inputAt(1); +//     } + +//     *x1 = _cursorPos.x; +//     *y1 = _cursorPos.y; + +//     if (field == &BIAS) { +//         out     = 1; +//         image   = &_biasImage; +//         texture = &_biasTexture; +//     } else { +//         image   = &_valueImage; +//         texture = &_valueTexture; +//     } + +//     double half = static_cast<double>(RESOLUTION / 2); + +//     for (unsigned y = 0; y < RESOLUTION; ++y) { +//         for (unsigned x = 0; x < RESOLUTION; ++x) { +//             *x2 = (static_cast<double>(x) - half) / half; +//             *y2 = (static_cast<double>(y) - half) / half; +//             _cppn.inputAt(4) = Point(*x1, *y1).distance(Point(*x2, *y2)); +//             _cppn.cycle(); + +//             auto multColor = [](const Color& base, double factor) { +//                 Color result; + +//                 result.r = static_cast<Uint8>(static_cast<double>(base.r) * factor); +//                 result.g = static_cast<Uint8>(static_cast<double>(base.g) * factor); +//                 result.b = static_cast<Uint8>(static_cast<double>(base.b) * factor); + +//                 return result; +//             }; + +//             if (_cppn.outputAt(out) > 0) { +//                  image->setPixel(x, y, multColor(Color::White, _cppn.outputAt(out))); +//             } else { +//                  image->setPixel(x, y, multColor(*field, fabs(_cppn.outputAt(out)))); +//             } +//         } +//     } + +//     texture->loadFromImage(*image); +// } + +// void +// CppnExplorer::placeCursorAt(const Vector2f& newPos) +// { +//     _cursorPos = newPos; +//     _cursorH.setPosition(_cursorPos); +//     _cursorV.setPosition(_cursorPos); +// } + +// void +// CppnExplorer::createNeuron(Neuron& repNeuron, const NeuralNet::Neuron& srcNeuron) +// { +//     repNeuron._body.setOutlineThickness(PIXEL * 2.0f); +//     repNeuron._nucleus.setOutlineThickness(PIXEL * 2.0f); + +//     float     radius      = 0.0f; +//     Color inputColor  = BIAS; +//     Color hiddenColor = INV_WEIGHTS; +//     Color outputColor = WEIGHTS; + +//     inputColor.a  = 128; +//     hiddenColor.a = 128; +//     outputColor.a = 128; + +//     switch (srcNeuron._type) { +//         case NeuralNet::Neuron::Type::INPUT: +//             repNeuron._type = Neuron::Type::INPUT; +//             repNeuron._body.setOutlineColor(inputColor); +//             repNeuron._body.setFillColor({ 0, 0, 0, 200 }); +//             radius = PIXEL * 24.0f; +//             break; + +//         case NeuralNet::Neuron::Type::HIDDEN: +//             repNeuron._type = Neuron::Type::HIDDEN; +//             repNeuron._body.setOutlineColor(hiddenColor); +//             repNeuron._body.setFillColor({ 0, 0, 0, 200 }); + +//             { +//                 float level = 1.0f; +//                 for (; srcNeuron._position._x * level != floor(srcNeuron._position._x * level); level *= 2.0f); +//                 radius = 1.0f / (level * 4.0f); + +//                 if (radius > PIXEL * 16.0f) { +//                     radius = PIXEL * 16.0f; +//                 } +//             } + +//             break; + +//         case NeuralNet::Neuron::Type::OUTPUT: +//             repNeuron._type = Neuron::Type::OUTPUT; +//             repNeuron._body.setOutlineColor(outputColor); +//             repNeuron._body.setFillColor({ 0, 0, 0, 200 }); +//             radius = PIXEL * 24.0f; +//             break; +//     } + +//     repNeuron._body.setRadius(radius); +//     repNeuron._body.setOrigin(radius, radius); +//     repNeuron._body.setPosition(srcNeuron._position._x, srcNeuron._position._y); + +//     repNeuron._nucleus.setRadius(radius / 2.0f); +//     repNeuron._nucleus.setOrigin(radius / 2.0f, radius / 2.0f); +//     repNeuron._nucleus.setPosition(srcNeuron._position._x, srcNeuron._position._y); +//     repNeuron._nucleus.setOutlineColor(repNeuron._body.getOutlineColor()); + +//     double    multInt = static_cast<Uint8>(fabs(srcNeuron._bias / 3.0) * 255.0); +//     Color colorMult(multInt, multInt, multInt, 128); + +//     if (srcNeuron._bias > 0) { +//         repNeuron._nucleus.setFillColor(Color::White * colorMult); +//     } else { +//         repNeuron._nucleus.setFillColor(BIAS * colorMult); +//     } + +//     Color synColor = WEIGHTS; + +//     for (auto& i : srcNeuron._synapses) { +//         for (auto& j : _neuralNet.getNeurons()) { +//             if (&j._output == i._input) { +//                 Uint8    weight = static_cast<Uint8>(i._weight * 20.0); +//                 Vector2f srcPos(j._position._x, j._position._y); + +//                 if (i._input == &srcNeuron._output) { +//                     Color selfSynColor; + +//                     if (i._weight > 0.0) { +//                         selfSynColor = Color(255, 255, 255, 20 + weight); +//                     } else { +//                         selfSynColor = synColor; +//                     } + +//                     float        rad2 = repNeuron._body.getRadius() * 2.0f; +//                     Vector2f p1   = repNeuron._body.getPosition() + Vector2f(-rad2, -rad2); +//                     Vector2f p2   = repNeuron._body.getPosition() + Vector2f(-rad2,  rad2); +//                     Vector2f p3   = repNeuron._body.getPosition() + Vector2f( rad2,  rad2); +//                     Vector2f p4   = repNeuron._body.getPosition() + Vector2f( rad2, -rad2); + +//                     repNeuron._synapses.append({ p1, selfSynColor }); +//                     repNeuron._synapses.append({ p2, selfSynColor }); + +//                     repNeuron._synapses.append({ p2, selfSynColor }); +//                     repNeuron._synapses.append({ p3, selfSynColor }); + +//                     repNeuron._synapses.append({ p3, selfSynColor }); +//                     repNeuron._synapses.append({ p4, selfSynColor }); + +//                     repNeuron._synapses.append({ p4, selfSynColor }); +//                     repNeuron._synapses.append({ p1, selfSynColor }); +//                 } else { +//                     repNeuron._synapses.append({ repNeuron._body.getPosition(), Color::Black }); + +//                     if (i._weight > 0.0) { +//                         repNeuron._synapses.append({{ srcPos }, Color(255, 255, 255, 20 + weight) }); +//                     } else { +//                         synColor.a = 20 + weight; +//                         repNeuron._synapses.append({{ srcPos }, synColor }); +//                     } +//                 } + +//                 break; +//             } +//         } +//     } +// } diff --git a/plugins/CppnExplorer/todolist.txt b/plugins/CppnExplorer/todolist.txt new file mode 100644 index 0000000..5677680 --- /dev/null +++ b/plugins/CppnExplorer/todolist.txt @@ -0,0 +1,21 @@ +Cppn Explorer: +  ☐ Render to any sf::RenderTarget +  ☐ Calculate field on separate thread (keep 2 textures) +  ☐ Render Neurons as crossmarks +  ☐ (When Rendering to Window) Cycle fields with F key +  ☐ (When Rendering to Window) Cycle between Neurons and Synapses using arrow keys +  ☐ Display text data +  ☐ (When Rendering to Window) Embed icon +  ☐ Show Cppn Network + + +___________________ +Archive: + ✔ Display connection to same neuron as square around neuron @done (13-12-10 00:29) @project(Cppn Explorer) + ✔ Use better color and blending for neurons @done (13-11-25 00:24) @project(Cppn Explorer) + ✔ Display Synapses as blended lines with Transparency representing Weights @done (13-11-25 00:24) @project(Cppn Explorer) + ✔ Display cursor beatifully @done (13-11-23 20:31) @project(Cppn Explorer) + ✔ Display grid @done (13-11-23 01:58) @project(Cppn Explorer) + ✔ Fix cursor @done (13-11-21 02:18) @project(Cppn Explorer) + ✔ Print and switch between fields @done (13-11-06 04:35) @project(Cppn Explorer) + ✔ Display Neurons beautifully (with bias represented as a nucleus) @done (13-11-04 20:52) @project(Cppn Explorer) diff --git a/src/Behavior.cpp b/src/Behavior.cpp new file mode 100644 index 0000000..15b2ad9 --- /dev/null +++ b/src/Behavior.cpp @@ -0,0 +1,59 @@ +#include <HyperNeat/Behavior.hpp> +#include <HyperNeat/NoveltyMetric.hpp> + +using namespace hyperneat; + +void +Behavior::clear() +{ +    _characterization.assign(_characterization.size(), 0.0); +} + +void +Behavior::reset(bool archive) +{ +    if (_toBeArchived && archive) { +        _noveltyMetric->_archive.emplace_back(_characterization); +    } + +    _noveltyScore    = 0.0; +    _toBeArchived    = false; +    _criteriaReached = _noveltyMetric->_prms._criteriaReachedByDefault; +    _characterization.assign(_characterization.size(), 0.0); +} + +double& +Behavior::at(size_t i) +{ +    return _characterization[i]; +} + +double +Behavior::getNoveltyScore() const +{ +    return _noveltyScore; +} + +bool +Behavior::isToBeArchived() const +{ +    return _toBeArchived; +} + +Organism& +Behavior::getOrganism() +{ +    return *_organism; +} + +const NoveltyMetric& +Behavior::getNoveltyMetric() const +{ +    return *_noveltyMetric; +} + +const Vector<double>& +Behavior::getCharacterization() const +{ +    return _characterization; +} diff --git a/src/Cppn.cpp b/src/Cppn.cpp new file mode 100644 index 0000000..fb1d19d --- /dev/null +++ b/src/Cppn.cpp @@ -0,0 +1,292 @@ +#include <cmath> +#include <HyperNeat/Cppn.hpp> +#include <HyperNeat/Genome.hpp> +#include <HyperNeat/QuadTree.hpp> +#include <HyperNeat/Utils/Pi.hpp> +#include <HyperNeat/NodeSearchPrms.hpp> + +using namespace std; +using namespace hyperneat; + +void +Cppn::create(const Genome& genome) +{ +    using DepthSorter = Map<double, Map<size_t, const Genome::NodeGene*>>; +    DepthSorter dSorter; + +    for (auto& i : genome._nodeGenes) { +        dSorter[i.second._depth][i.first] = &i.second; +    } + +    _inputs.resize(genome._inputs, 0.0); +    _nodeLayers.resize(dSorter.size()); + +    { +        auto layerIter = _nodeLayers.begin(); + +        for (auto& i : dSorter) { +            layerIter->resize(i.second.size()); +            auto nodeIter = layerIter->begin(); + +            for (auto& j : i.second) { +                size_t enabledLinks = 0; + +                for (auto& k : j.second->_linkGenes) { +                    if (k.second._isEnabled) { +                        ++enabledLinks; +                    } +                } + +                nodeIter->_links.resize(enabledLinks); +                ++nodeIter; +            } + +            ++layerIter; +        } +    } + +    size_t layerIdx = 0; + +    for (auto& i : dSorter) { +        size_t nodeIdx = 0; + +        for (auto& j : i.second) { +            Node& crntNode = _nodeLayers[layerIdx][nodeIdx]; +            size_t linkIdx = 0; + +            for (auto& k : j.second->_linkGenes) { +                if (k.second._isEnabled) { +                    Node::Link& crntLink = crntNode._links[linkIdx]; + +                    if (k.first < _inputs.size()) { +                        crntLink._input = &_inputs[k.first]; +                    } else { +                        double depth = genome._nodeGenes.at(k.first)._depth; +                        size_t layer = distance(dSorter.begin(), dSorter.find(depth)); +                        size_t node  = distance(dSorter[depth].begin(), dSorter[depth].find(k.first)); + +                        crntLink._input = &_nodeLayers[layer][node]._output; +                    } + +                    crntLink._weight = k.second._weight; +                    ++linkIdx; +                } +            } + +            crntNode._nodeType = j.second->_nodeType; +            ++nodeIdx; + +            if (i.first == 1.0) { +                _outputs.push_back(&crntNode._output); +            } +        } + +        ++layerIdx; +    } +} + +void +Cppn::clear() +{ +    _inputs.clear(); +    _outputs.clear(); +    _nodeLayers.clear(); +} + +size_t +Cppn::getInputsCount() const +{ +    return _inputs.size(); +} + +size_t +Cppn::getOutputsCount() const +{ +    return _outputs.size(); +} + +size_t +Cppn::getNodesCount() const +{ +    size_t nodesCount = 0; + +    for (auto& i : _nodeLayers) { +        nodesCount += i.size(); +    } + +    return nodesCount; +} + +double& +Cppn::inputAt(size_t i) +{ +    return _inputs[i]; +} + +double +Cppn::outputAt(size_t i) const +{ +    return *_outputs[i]; +} + +void +Cppn::cycle() +{ +    for (auto& i : _nodeLayers) { +        for (auto& j : i) { +            j.appendInput(); +        } + +        for (auto& j : i) { +            j.flushOutput(); +        } +    } +} + +void +Cppn::findNodesIn2DSection(ValueMap& valueMap, const NodeSearchPrms& nsPrms, const Point& source) +{ +    QuadTree qTree(1.0, 0.0, 0.0); + +    qTree.subdivide([&](QuadTree* qt) { +        auto levelToSegment = [](size_t level) { +            double dlevel = static_cast<double>(level); +            return 1.0 / pow(2.0, dlevel); +        }; + +        double minQuadTreeSegment = levelToSegment(nsPrms._maxQuadTreeLevel); +        double maxQuadTreeSegment = levelToSegment(nsPrms._minQuadTreeLevel); +        double testGridResolution = levelToSegment(nsPrms._testGridLevel); + +        if (qt->getSegment() <= minQuadTreeSegment) { +            return false; +        } + +        if (qt->getSegment() > maxQuadTreeSegment) { +            return true; +        } + +        double gridStep = qt->getSegment() * 2.0 * testGridResolution; +        double gridHalf = gridStep / 2.0; +        double initX    = qt->getX() - qt->getSegment() + gridHalf; +        double initY    = qt->getY() - qt->getSegment() + gridHalf; +        double endX     = qt->getX() + qt->getSegment(); +        double endY     = qt->getY() + qt->getSegment(); +        double cellsNo  = (1.0 / testGridResolution) * (1.0 / testGridResolution); + +        Vector<double> w; +        w.reserve(static_cast<size_t>(cellsNo)); + +        for (double y = initY; y < endY; y += gridStep) { +            for (double x = initX; x < endX; x += gridStep) { +                _inputs[nsPrms._x] = x; +                _inputs[nsPrms._y] = y; + +                if (nsPrms._useDistance) { +                    _inputs[nsPrms._d] = Point(x, y).distance(source); +                } + +                cycle(); +                w.emplace_back(*_outputs[nsPrms._o]); +            } +        } + +        double wMean    = 0.0; +        double variance = 0.0; + +        for (auto& i : w) { +            wMean += i; +        } + +        wMean /= cellsNo; + +        for (auto& i : w) { +            variance += (wMean - i) * (wMean - i); +        } + +        variance /= cellsNo; + +        if (variance > nsPrms._varianceThreshold) { +            return true; +        } + +        return false; +    }); + +    qTree.traverse([&](const QuadTree* qt) { +        auto measureDistAndIO = [&]() { +            if (nsPrms._useDistance) { +                _inputs[nsPrms._d] = Point(_inputs[nsPrms._x], _inputs[nsPrms._y]).distance(source); +            } + +            cycle(); +            return *_outputs[nsPrms._o]; +        }; + +        double gridSize  = qt->getSegment() * 2.0; + +        _inputs[nsPrms._y] = qt->getY(); +        _inputs[nsPrms._x] = qt->getX() - gridSize; +        double valLeft     = measureDistAndIO(); + +        _inputs[nsPrms._x] = qt->getX() + gridSize; +        double valRight    = measureDistAndIO(); + +        _inputs[nsPrms._x] = qt->getX(); +        _inputs[nsPrms._y] = qt->getY() - gridSize; +        double valBottom   = measureDistAndIO(); + +        _inputs[nsPrms._y] = qt->getY() + gridSize; +        double valTop      = measureDistAndIO(); + +        _inputs[nsPrms._y] = qt->getY(); +        double valCenter   = measureDistAndIO(); + +        valLeft   = fabs(valCenter - valLeft); +        valRight  = fabs(valCenter - valRight); +        valBottom = fabs(valCenter - valBottom); +        valTop    = fabs(valCenter - valTop); + +        double bandValue = max(min(valLeft, valRight), min(valBottom, valTop)); + +        if (bandValue > nsPrms._bandPruningThreshold) { +            valueMap.emplace_back(qt->getX(), qt->getY(), valCenter, qt->getSegment()); +        } +    }); +} + +void +Cppn::Node::appendInput() +{ +    for (auto& i : _links) { +        _storedInput += *i._input * i._weight; +    } +} + +void +Cppn::Node::flushOutput() +{ +    switch (_nodeType) { +        case NodeType::SIGMOID: +            _output = 1.0 / (1.0 + exp(-_storedInput * 2.0)); +            _output = _output * 2.0 - 1.0; +            break; + +        case NodeType::GAUSSIAN: +            _output = exp(-_storedInput * _storedInput); +            _output = _output * 2.0 - 1.0; +            break; + +        case NodeType::SINE: +            _output = sin((_storedInput / 2.0) * PI); +            break; + +        case NodeType::ABSOLUTE: +            _output = max(min(fabs(_storedInput), 0.0), 1.0); +            break; + +        default:; +    } + +    _storedInput = 0.0; +} diff --git a/src/Genome.cpp b/src/Genome.cpp new file mode 100644 index 0000000..ce5fc11 --- /dev/null +++ b/src/Genome.cpp @@ -0,0 +1,15 @@ +#include <HyperNeat/Genome.hpp> + +using namespace hyperneat; + +Genome::Genome(size_t inputs) +    : _inputs(inputs) +{} + +Genome::NodeGene::NodeGene(double depth, NodeType nodeType) +    : _depth(depth), _nodeType(nodeType) +{} + +Genome::NodeGene::LinkGene::LinkGene(double weight, bool isEnabled) +    : _weight(weight), _isEnabled(isEnabled) +{} diff --git a/src/Innovation.cpp b/src/Innovation.cpp new file mode 100644 index 0000000..0332616 --- /dev/null +++ b/src/Innovation.cpp @@ -0,0 +1,16 @@ +#include <Hyperneat/Innovation.hpp> + +using namespace hyperneat; + +Innovation::Innovation(size_t number, size_t source, size_t target, double depth, NodeType nodeType) +    : _number(number), _source(source), _target(target), _depth(depth), _nodeType(nodeType) +{} + +bool +Innovation::operator==(const Innovation& other) const +{ +    return (_source   == other._source  ) && +           (_target   == other._target  ) && +           (_depth    == other._depth   ) && +           (_nodeType == other._nodeType); +} diff --git a/src/NeuralNet.cpp b/src/NeuralNet.cpp new file mode 100644 index 0000000..abed262 --- /dev/null +++ b/src/NeuralNet.cpp @@ -0,0 +1,294 @@ +#include <cmath> +#include <algorithm> +#include <HyperNeat/Cppn.hpp> +#include <HyperNeat/NeuralNet.hpp> +#include <HyperNeat/Utils/Map.hpp> +#include <HyperNeat/Utils/Set.hpp> +#include <HyperNeat/NeuralNetPrms.hpp> +#include <HyperNeat/Utils/Function.hpp> +#include <HyperNeat/NodeSearchPrms.hpp> + +using namespace std; +using namespace hyperneat; + +void +NeuralNet::create(Cppn& cppn, const NeuralNetPrms& nnPrms) +{ +    class TempNeuronSynapse { +    public: +        TempNeuronSynapse() = default; +        TempNeuronSynapse(double weight, Point neuronSource) +            : _weight(weight), _neuronSource(neuronSource) +        {} + +        double _weight = 0.0; +        Point  _neuronSource; +    }; + +    class TempNeuron { +    public: +        bool                      _isIncluded = false; +        double                    _bias       = 0.0; +        Vector<TempNeuronSynapse> _neuronSynapses; +    }; + +    _inputs.reserve(nnPrms._inputMap.size()); +    _outputs.reserve(nnPrms._outputMap.size()); + +    NodeSearchPrms nsPrms(0, 2, 3, 4); +    nsPrms.importFrom(nnPrms); +    cppn.inputAt(5) = 1.0; + +    Map<Point, TempNeuron> tempNeurons; + +    auto findConnections = [&](const Point& source, size_t x1, size_t y1, size_t x2, size_t y2, size_t d, +            bool checkExist, Function<void(double, const Point&)> storeConn) { +        cppn.inputAt(x1) = source._x; +        cppn.inputAt(y1) = source._y; +        cppn.inputAt(x2) = 0.0; +        cppn.inputAt(y2) = 0.0; +        cppn.inputAt(d)  = 0.0; + +        ValueMap newConnections; +        cppn.findNodesIn2DSection(newConnections, nsPrms, source); + +        for (auto& i : newConnections) { +            if (checkExist && !tempNeurons.count(i)) { +                continue; +            } + +            if (fabs(i._value) > 0.2) { +                storeConn((i._value + (i._value > 0 ? -0.2 : 0.2)) * 3.75, i); +            } +        } +    }; + +    { +        Set<Point>  neuronSet1; +        Set<Point>  neuronSet2; +        Set<Point>* previousNeurons = &neuronSet1; +        Set<Point>* nextNeurons     = &neuronSet2; + +        for (auto& i : nnPrms._inputMap) { +            tempNeurons[i]; +            previousNeurons->insert(i); +        } + +        for (size_t i = 0; i < nnPrms._iterations && !previousNeurons->empty(); ++i) { +            Map<Point, TempNeuron> newNeurons; + +            for (auto& j : *previousNeurons) { +                findConnections(j, 0, 1, 2, 3, 4, false, [&](double weight, const Point& target) { +                    if (tempNeurons.count(target)) { +                        auto& synapses = tempNeurons[target]._neuronSynapses; +                        synapses.emplace_back(weight, j); +                    } else { +                        auto& synapses = newNeurons[target]._neuronSynapses; +                        synapses.emplace_back(weight, j); +                        nextNeurons->insert(target); +                    } +                }); +            } + +            previousNeurons->clear(); +            swap(nextNeurons, previousNeurons); +            tempNeurons.insert(newNeurons.begin(), newNeurons.end()); +        } +    } + +    nsPrms._x = 0; +    nsPrms._y = 1; + +    { +        Vector<TempNeuron*>  inclusionSet1; +        Vector<TempNeuron*>  inclusionSet2; +        Vector<TempNeuron*>* crntInclusions = &inclusionSet1; +        Vector<TempNeuron*>* nextInclusions = &inclusionSet2; + +        for (auto& i : nnPrms._outputMap) { +            tempNeurons[i]._isIncluded = true; +            nextInclusions->push_back(&tempNeurons[i]); + +            findConnections(i, 2, 3, 0, 1, 4, true, [&](double weight, const Point& target) { +                auto& synapses = tempNeurons[i]._neuronSynapses; +                synapses.emplace_back(weight, target); +            }); +        } + +        while (!nextInclusions->empty()) { +            crntInclusions->clear(); +            swap(crntInclusions, nextInclusions); + +            for (auto& i : *crntInclusions) { +                for (auto& j : i->_neuronSynapses) { +                    auto& sourceNeuron = tempNeurons.at(j._neuronSource); + +                    if (!sourceNeuron._isIncluded) { +                        nextInclusions->push_back(&sourceNeuron); +                        sourceNeuron._isIncluded = true; +                    } +                } +            } +        } +    } + +    for (auto& i : nnPrms._inputMap) { +        tempNeurons[i]._isIncluded = true; +    } + +    cppn.inputAt(2) = 0.0; +    cppn.inputAt(3) = 0.0; +    cppn.inputAt(4) = 0.0; + +    for (auto i = tempNeurons.begin(), end = tempNeurons.end(); i != end;) { +        if (i->second._isIncluded) { +            cppn.inputAt(0) = i->first._x; +            cppn.inputAt(1) = i->first._y; +            cppn.inputAt(4) = i->first.distance(Point()); +            cppn.cycle(); +            i->second._bias = cppn.outputAt(1) * 3.0; +            ++i; +        } else { +            i = tempNeurons.erase(i); +        } +    } + +    _neurons.resize(tempNeurons.size()); + +    { +        auto nIter = _neurons.begin(); + +        for (auto& i : tempNeurons) { +            nIter->_bias         = i.second._bias; +            nIter->_position     = i.first; +            auto& crntNrnSyns    = nIter->_synapses; +            auto& neuronSynapses = i.second._neuronSynapses; +            crntNrnSyns.reserve(neuronSynapses.size()); + +            for (auto& j : neuronSynapses) { +                auto src    = tempNeurons.find(j._neuronSource); +                size_t sIdx = distance(tempNeurons.begin(), src); +                crntNrnSyns.emplace_back(&_neurons[sIdx], j._weight); +            } + +            ++nIter; +        } +    } + +    auto relateIO = [&](Vector<double*>& ptrVec, const Vector<Point>& map, Neuron::Type type) { +        for (auto& i : map) { +            auto neuron          = tempNeurons.find(i); +            size_t nIdx          = distance(tempNeurons.begin(), neuron); +            _neurons[nIdx]._type = type; +            ptrVec.push_back(&_neurons[nIdx]._output); +        } +    }; + +    relateIO(_inputs, nnPrms._inputMap, Neuron::Type::INPUT); +    relateIO(_outputs, nnPrms._outputMap, Neuron::Type::OUTPUT); +} + +void +NeuralNet::clear() +{ +    _inputs.clear(); +    _outputs.clear(); +    _neurons.clear(); +} + +size_t +NeuralNet::getInputsCount() const +{ +    return _inputs.size(); +} + +size_t +NeuralNet::getOutputsCount() const +{ +    return _outputs.size(); +} + +size_t +NeuralNet::getNeuronsCount() const +{ +    return _neurons.size(); +} + +double +NeuralNet::getAverageActivation() const +{ +    double totalActivation = 0.0; + +    for (auto& i : _neurons) { +        totalActivation += i._output; +    } + +    return totalActivation / static_cast<double>(_neurons.size()); +} + +double& +NeuralNet::inputAt(size_t i) +{ +    return *_inputs[i]; +} + +double +NeuralNet::outputAt(size_t i) const +{ +    return *_outputs[i]; +} + +const Vector<double*>& +NeuralNet::getInputs() const +{ +    return _inputs; +} + +const Vector<double*>& +NeuralNet::getOutputs() const +{ +    return _outputs; +} + +const Vector<NeuralNet::Neuron>& +NeuralNet::getNeurons() const +{ +    return _neurons; +} + +void +NeuralNet::cycle() +{ +    for (auto& i : _neurons) { +        i.appendInput(); +    } + +    for (auto& i : _neurons) { +        i.flushOutput(); +    } +} + +NeuralNet::Neuron::Neuron(const Point& position, Type type, double bias) +    : _position(position), _type(type), _bias(bias) +{} + +void +NeuralNet::Neuron::appendInput() +{ +    for (auto& i : _synapses) { +        _storedInput += *i._input * i._weight; +    } + +    _storedInput += _bias; +} + +void +NeuralNet::Neuron::flushOutput() +{ +    _output      = 1.0 / (1.0 + exp(-_storedInput * 4.9)); +    _storedInput = 0.0; +} + +NeuralNet::Neuron::Synapse::Synapse(Neuron* inputNeuron, double weight) +    : _input(&inputNeuron->_output), _neuron(inputNeuron), _weight(weight) +{} diff --git a/src/NodeSearchPrms.cpp b/src/NodeSearchPrms.cpp new file mode 100644 index 0000000..db2421a --- /dev/null +++ b/src/NodeSearchPrms.cpp @@ -0,0 +1,23 @@ +#include <HyperNeat/NeuralNetPrms.hpp> +#include <HyperNeat/NodeSearchPrms.hpp> + +using namespace hyperneat; + +NodeSearchPrms::NodeSearchPrms(size_t o, size_t x, size_t y) +    : _o(o), _x(x), _y(y), _useDistance(false) +{} + +NodeSearchPrms::NodeSearchPrms(size_t o, size_t x, size_t y, size_t d) +    : _o(o), _x(x), _y(y), _d(d) +{} + +void +NodeSearchPrms::importFrom(const NeuralNetPrms& nnPrms) +{ +    _testGridLevel        = nnPrms._testGridLevel; +    _maxQuadTreeLevel     = nnPrms._maxQuadTreeLevel; +    _minQuadTreeLevel     = nnPrms._minQuadTreeLevel; +    _bandPruningThreshold = nnPrms._bandPruningThreshold; +    _varianceThreshold    = nnPrms._varianceThreshold; +    _divisionThreshold    = nnPrms._divisionThreshold; +} diff --git a/src/NoveltyMetric.cpp b/src/NoveltyMetric.cpp new file mode 100644 index 0000000..dd40118 --- /dev/null +++ b/src/NoveltyMetric.cpp @@ -0,0 +1,101 @@ +#include <algorithm> +#include <Hyperneat/Population.hpp> +#include <Hyperneat/NoveltyMetric.hpp> + +using namespace std; +using namespace hyperneat; + +const NoveltyMetricPrms& +NoveltyMetric::getPrms() const +{ +    return _prms; +} + +const Vector<Behavior>& +NoveltyMetric::getBehaviors() const +{ +    return _behaviors; +} + +const Vector2D<double>& +NoveltyMetric::getArchive() const +{ +    return _archive; +} + +Behavior& +NoveltyMetric::getBehaviorOf(size_t i) +{ +    return _behaviors[i]; +} + +void +NoveltyMetric::initialize(const NoveltyMetricPrms& prms, Population* population) +{ +    _prms = prms; +    _behaviors.resize(population->getAllOrganisms().size()); + +    for (size_t i = 0; i < _behaviors.size(); ++i) { +        population->getOrganism(i)._behavior = &_behaviors[i]; +        _behaviors[i]._organism              = &population->getOrganism(i); +        _behaviors[i]._noveltyMetric         = this; +        _behaviors[i]._criteriaReached       = prms._criteriaReachedByDefault; +        _behaviors[i]._characterization.resize(prms._characterizationSize, 0.0); +    } +} + +void +NoveltyMetric::setScores() +{ +    size_t readyOrganisms = 0; + +    for (auto& i : _behaviors) { +        if ((i._isReady = (i._organism->isOld() && i._criteriaReached))) { +            ++readyOrganisms; +        } +    } + +    for (auto& i : _behaviors) { +        if (!i._isReady) { +            i._toBeArchived       = false; +            i._organism->_fitness = i._noveltyScore = 0.0; +            continue; +        } + +        Vector<double> distances; +        distances.reserve(readyOrganisms + _archive.size() - 1); + +        for (auto& j : _behaviors) { +            if (j._isReady && (&i != &j)) { +                distances.emplace_back(getDistance(i._characterization, j._characterization)); +            } +        } + +        for (auto& j : _archive) { +            distances.emplace_back(getDistance(i._characterization, j)); +        } + +        auto dEnd = distances.end(); +        auto dBeg = distances.begin(); +        auto dRef = dBeg + _prms._referenceOrganisms; + +        partial_sort(dBeg, dRef, dEnd); + +        double totalDistance  = accumulate(dBeg, dRef, 0.0); +        i._organism->_fitness = i._noveltyScore = (totalDistance / static_cast<double>(_prms._referenceOrganisms)); +        i._toBeArchived       = (i._noveltyScore > _prms._noveltyThreshold); +    } +} + +double +NoveltyMetric::getDistance(const Vector<double>& v1, const Vector<double>& v2) const +{ +    double result = 0.0; + +    for (size_t i = 0; i < v1.size(); ++i) { +        double diff = v1[i] - v2[i]; +        result     += diff * diff; +    } + +    return sqrt(result); +} diff --git a/src/Organism.cpp b/src/Organism.cpp new file mode 100644 index 0000000..0c2c1bc --- /dev/null +++ b/src/Organism.cpp @@ -0,0 +1,180 @@ +#include <HyperNeat/Cppn.hpp> +#include <HyperNeat/Behavior.hpp> +#include <HyperNeat/NeuralNet.hpp> +#include <HyperNeat/Population.hpp> +#include <HyperNeat/Utils/Thread.hpp> +#include <HyperNeat/NeuralNetPrms.hpp> + +using namespace std; +using namespace hyperneat; + +Organism::Organism(const Organism& other) +{ +    *this = other; +} + +Organism& +Organism::operator=(const Organism& other) +{ +    _fitness    = other._fitness; +    _index      = other._index; +    _isLocked   = other._isLocked; +    _isFrozen   = other._isFrozen; +    _specie     = other._specie; +    _lifetime   = other._lifetime; +    _genome     = other._genome; +    _population = other._population; + +    return *this; +} + +size_t +Organism::getIndex() const +{ +    return _index; +} + +void +Organism::lock() +{ +    if (!_isLocked) { +        _isLocked = true; +        ++_population->_lockedOrganisms; +    } +} + +void +Organism::unlock() +{ +    if (_isLocked) { +        _isLocked = false; +        --_population->_lockedOrganisms; +    } +} + +bool +Organism::isLocked() const +{ +    return _isLocked; +} + +void +Organism::freeze() +{ +    if (!_isFrozen) { +        _isFrozen = true; +        ++_population->_frozenOrganisms; +    } +} + +void +Organism::unfreeze() +{ +    if (_isFrozen) { +        _isFrozen = false; +        --_population->_frozenOrganisms; +    } +} + +bool +Organism::isFrozen() const +{ +    return _isFrozen; +} + +bool +Organism::isBeingGenerated() const +{ +    return _isBeingGenerated; +} + +size_t +Organism::getSpecie() const +{ +    return _specie; +} + +bool +Organism::isOld() const { +    return _lifetime >= _population->_prms._minimumLifetime; +} + +size_t +Organism::getLifetime() const +{ +    return _lifetime; +} + +Behavior& +Organism::getBehavior() +{ +    return *_behavior; +} + +const Genome& +Organism::getGenome() const +{ +    return _genome; +} + +bool +Organism::isChampion() const +{ +    return &_population->getChampion() == this; +} + +Population& +Organism::getPopulation() const +{ +    return *_population; +} + +void +Organism::createNeuralNet() +{ +    if (_isBeingGenerated) { +        return; +    } + +    _isBeingGenerated = true; +    ++_population->_organismsBeingGenerated; + +    Thread generator([&]() { +        Cppn cppn; +        cppn.create(_genome); + +        _neuralNet->clear(); +        _neuralNet->create(cppn, _population->getNeuralNetPrms()); + +        _isBeingGenerated = false; +        --_population->_organismsBeingGenerated; +    }); + +    generator.detach(); +} + +Organism::Organism(Population* population) +    : _population(population) +{} + +Organism::Organism(size_t inputs, Population* population) +    : _genome(inputs), _population(population) +{} + +void +Organism::reset(bool archive) +{ +    unlock(); +    unfreeze(); + +    if (isOld()) { +        --_population->_oldOrganisms; +    } + +    _lifetime = 0; +    _fitness  = 0.0; + +    if (_behavior) { +        _behavior->reset(archive); +    } +} diff --git a/src/Population.cpp b/src/Population.cpp new file mode 100644 index 0000000..f81887e --- /dev/null +++ b/src/Population.cpp @@ -0,0 +1,939 @@ +#include <chrono> +#include <algorithm> +#include <HyperNeat/Cppn.hpp> +#include <HyperNeat/NeuralNet.hpp> +#include <HyperNeat/Population.hpp> +#include <HyperNeat/Utils/Thread.hpp> + +using namespace std; +using namespace hyperneat; + +void +Population::create(const PopulationPrms& popPrms) +{ +    if (_prms._seed != 0) { +        _randGen.seed(_prms._seed); +    } else { +        _randGen.seed(getRandSeed()); +    } + +    _prms              = popPrms; +    _weightDeviator    = BellDist(0.0, _prms._weightDeviation); +    _weightSelector    = RealDist(-_prms._weightRange, _prms._weightRange); +    _distanceThreshold = _prms._initialDistanceThreshold; +    _minOldOrganisms   = _prms._popSize * _prms._eligibilityRatio; +    _basicInnovs       = _prms._cppnOutputs * NODE_TYPES_COUNT + _prms._cppnInputs; + +    _allOrganisms.resize(_prms._popSize, Organism(_prms._cppnInputs, this)); + +    size_t orgIndex = 0; + +    for (auto& i : _allOrganisms) { +        i._index        = orgIndex++; +        auto& nodeGenes = i._genome._nodeGenes; + +        for (size_t j = 0; j < _prms._cppnOutputs; ++j) { +            size_t nodeType    = _nodeTypeSelector(_randGen); +            size_t geneIdx     = _prms._cppnInputs + (j * NODE_TYPES_COUNT) + nodeType; +            nodeGenes[geneIdx] = {1.0, static_cast<NodeType>(nodeType)}; + +            for (size_t k = 0; k < _prms._cppnInputs; ++k) { +                nodeGenes[geneIdx]._linkGenes[k] = {getRandWeight()}; +            } +        } +    } + +    organizeSpecies(); +} + +void +Population::create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms) +{ +    create(popPrms); +    _nnPrms = Pointer<NeuralNetPrms>(new NeuralNetPrms(nnPrms)); +    generateAllNeuralNets(); +} + +void +Population::create(const PopulationPrms& popPrms, const NeuralNetPrms& nnPrms, const NoveltyMetricPrms& nmPrms) +{ +    create(popPrms, nnPrms); +    setNoveltyMetric(nmPrms); +} + +void +Population::shutdown(bool resetOrganisms, bool archiveOrganisms) +{ +    while (isAnyOrganismBeingGenerated()); + +    if (resetOrganisms) { +        for (auto& i : _allOrganisms) { +            i.reset(archiveOrganisms); +        } +    } +} + +Population::~Population() +{ +    while (isAnyOrganismBeingGenerated()); +} + +void +Population::setMinimumLifetime(size_t lifetime) +{ +    _oldOrganisms          = 0; +    _prms._minimumLifetime = lifetime; + +    for (auto& i : _allOrganisms) { +        if (i._lifetime >= lifetime) { +            ++_oldOrganisms; +        } +    } +} + +const PopulationPrms& +Population::getPopulationPrms() const +{ +    return _prms; +} + +const NeuralNetPrms& +Population::getNeuralNetPrms() const +{ +    return *_nnPrms; +} + +bool +Population::hasNeuralNets() const +{ +    return (bool)_nnPrms; +} + +const Vector<Organism>& +Population::getAllOrganisms() const +{ +    return _allOrganisms; +} + +const Vector2D<Organism*>& +Population::getSpecies() const +{ +    return _species; +} + +Organism& +Population::getOrganism(size_t i) +{ +    return _allOrganisms[i]; +} + +const Vector<Organism*>& +Population::getSpecie(size_t i) const +{ +    return _species[i]; +} + +Organism& +Population::getChampion() +{ +    auto comFitness = [](Organism& a, Organism& b) { +        return a._fitness < b._fitness; +    }; + +    auto comNovelty = [](Organism& a, Organism& b) { +        return a.getBehavior().getNoveltyScore() < b.getBehavior().getNoveltyScore(); +    }; + +    return *max_element(_allOrganisms.begin(), _allOrganisms.end(), isNoveltyMetricSet() ? comNovelty : comFitness); +} + +void +Population::lock() +{ +    _populationLock = true; +} + +void +Population::unlock() +{ +    _populationLock = false; +} + +bool +Population::isLocked() const +{ +    return _populationLock; +} + +void +Population::lockOrganism(size_t i) +{ +    _allOrganisms[i].lock(); +} + +void +Population::unlockOrganism(size_t i) +{ +    _allOrganisms[i].unlock(); +} + +bool +Population::isOrganismLocked(size_t i) const +{ +    return _allOrganisms[i]._isLocked; +} + +bool +Population::isAnyOrganismLocked() const +{ +    return _lockedOrganisms != 0 ? true : false; +} + +size_t +Population::getLockedOrganisms() const +{ +    return _lockedOrganisms; +} + +void +Population::freezeOrganism(size_t i) +{ +    _allOrganisms[i].freeze(); +} + +void +Population::unfreezeOrganism(size_t i) +{ +    _allOrganisms[i].unfreeze(); +} + +bool +Population::isOrganismFrozen(size_t i) const +{ +    return _allOrganisms[i]._isFrozen; +} + +bool +Population::isAnyOrganismFrozen() const +{ +    return _frozenOrganisms != 0 ? true : false; +} + +size_t +Population::getFrozenOrganisms() const +{ +    return _frozenOrganisms; +} + +bool +Population::isOrganismBeingGenerated(size_t i) const +{ +    return _allOrganisms[i].isBeingGenerated(); +} + +bool +Population::isAnyOrganismBeingGenerated() const +{ +    return _organismsBeingGenerated != 0 ? true : false; +} + +size_t +Population::getOrganismsBeingGenerated() const +{ +    return _organismsBeingGenerated; +} + +size_t +Population::getReadyOrganisms() const +{ +    size_t result = 0; + +    for (auto& i : _allOrganisms) { +        if (i.isOld() && !i.isLocked()) { +            ++result; +        } +    } + +    return result; +} + +const Vector<Innovation>& +Population::getInnovations() const +{ +    return _innovations; +} + +size_t +Population::getInnovationsCount() const +{ +    return _innovations.size(); +} + +size_t +Population::getBasicInnovationsCount() const +{ +    return _basicInnovs; +} + +Organism* +Population::getLastReplacement() +{ +    return _lastReplacement; +} + +Organism* +Population::getLastMother() +{ +    return _lastMother; +} + +Organism* +Population::getLastFather() +{ +    return _lastFather; +} + +size_t +Population::getReplacements() const +{ +    return _replacements; +} + +bool +Population::recentReplacement() const +{ +    return _recentReplacement; +} + +double +Population::getDistanceThreshold() const +{ +    return _distanceThreshold; +} + +size_t +Population::getOldOrganisms() const +{ +    return _oldOrganisms; +} + +size_t +Population::getMinimumOldOrganisms() const +{ +    return _minOldOrganisms; +} + +double +Population::getAverageFitness() const +{ +    double total = 0.0; + +    for (auto& i : _allOrganisms) { +        total += i._fitness; +    } + +    return total / static_cast<double>(_allOrganisms.size()); +} + +double +Population::getAverageOldFitness() const +{ +    double total = 0.0; + +    for (auto& i : _allOrganisms) { +        if (i.isOld()) { +            total += i._fitness; +        } +    } + +    return total / static_cast<double>(getOldOrganisms()); +} + +void +Population::setNoveltyMetric(const NoveltyMetricPrms& prms) { +    _noveltyMetric = Pointer<NoveltyMetric>(new NoveltyMetric); +    _noveltyMetric->initialize(prms, this); +} + +void +Population::clearNoveltyMetric() +{ +    _noveltyMetric.reset(); + +    for (auto& i : _allOrganisms) { +        i._behavior = nullptr; +    } +} + +bool +Population::isNoveltyMetricSet() const +{ +    return _noveltyMetric.get(); +} + +const NoveltyMetric& +Population::getNoveltyMetric() const +{ +    return *_noveltyMetric; +} + +size_t +Population::getUpdates() const +{ +    return _updates; +} + +double& +Population::fitnessOf(size_t i) +{ +    return _allOrganisms[i]._fitness; +} + +bool +Population::update(Function<void(void)> beforeReplacement, Function<void(void)> afterReplacement) +{ +    ++_updates; + +    for (auto& i : _allOrganisms) { +        if (!i._isFrozen && !i.isBeingGenerated()) { +            ++i._lifetime; + +            if (i._lifetime == _prms._minimumLifetime) { +                ++_oldOrganisms; +            } +        } +    } + +    if (_populationLock) { +        return false; +    } + +    if ((getReadyOrganisms() >= _minOldOrganisms) && !isAnyOrganismBeingGenerated()) { +        beforeReplacement(); + +        if (isNoveltyMetricSet()) { +            _noveltyMetric->setScores(); +        } + +        _recentReplacement = true; +        replaceOrganism(); +        afterReplacement(); +    } else { +        _recentReplacement = false; +    } + +    return _recentReplacement; +} + +void +Population::generateAllNeuralNets() +{ +    auto generateChunk = [&](size_t i, size_t end) { +        for (; i < end; ++i) { +            Cppn cppn; +            cppn.create(_allOrganisms[i].getGenome()); + +            _allOrganisms[i]._neuralNet = Pointer<NeuralNet>(new NeuralNet); +            _allOrganisms[i]._neuralNet->create(cppn, *_nnPrms); +        } +    }; + +    size_t threadCount = max(1u, Thread::hardware_concurrency()); +    size_t chunkSize   = _allOrganisms.size() / threadCount; + +    Vector<Thread> chunks(threadCount); + +    for (size_t i = 0; i < threadCount - 1; ++i) { +        chunks[i] = Thread(generateChunk, i * chunkSize, (i + 1) * chunkSize); +    } + +    chunks.back() = Thread(generateChunk, (chunks.size() - 1) * chunkSize, _allOrganisms.size()); + +    for (auto& i : chunks) { +        i.join(); +    } +} + +void +Population::replaceOrganism() +{ +    _lastReplacement  = killPoorOrganism(); +    _lastMother       = nullptr; +    _lastFather       = nullptr; +    auto parentSpecie = chooseParentSpecie(); +    Vector<Organism*> eligibleMothers; + +    for (auto& i : *parentSpecie) { +        if (i->_lifetime >= _prms._minimumLifetime) { +            eligibleMothers.emplace_back(i); +        } +    } + +    size_t motherIdx = getRandSize(0, eligibleMothers.size() - 1); +    _lastMother      = eligibleMothers[motherIdx]; + +    if (getChance(_prms._sexualReproductionRate)) { +        if (getChance(_prms._interspeciesMatingRate)) { +            Vector<Organism*> eligibleFathers; + +            for (auto& i : _species) { +                if (&i == parentSpecie) { +                    continue; +                } + +                for (auto& j : i) { +                    if (j->_lifetime >= _prms._minimumLifetime) { +                        eligibleFathers.emplace_back(j); +                    } +                } +            } + +            if (eligibleFathers.size() > 0) { +                size_t fatherIdx = getRandSize(0, eligibleFathers.size() - 1); +                _lastFather      = eligibleFathers[fatherIdx]; +            } +        } else { +            if (eligibleMothers.size() > 1) { +                size_t fatherIdx = getRandSize(0, eligibleMothers.size() - 2); + +                if (fatherIdx >= motherIdx) { +                    ++fatherIdx; +                } + +                _lastFather = eligibleMothers[fatherIdx]; +            } +        } + +        if (!_lastFather) { +            breedAsexually(_lastReplacement->_genome, _lastMother->_genome); +        } else { +            if (_lastFather->_fitness > _lastMother->_fitness) { +                swap(_lastFather, _lastMother); +            } + +            breedSexually(_lastReplacement->_genome, _lastMother->_genome, _lastFather->_genome); +        } +    } else { +        breedAsexually(_lastReplacement->_genome, _lastMother->_genome); +    } + +    assignToSpecie(*_lastReplacement); +    ++_replacements; +    --_oldOrganisms; + +    if ((_replacements % _prms._replBeforeReorganization) == 0) { +        organizeSpecies(); +    } +} + +Organism* +Population::killPoorOrganism() +{ +    Organism* poorOrganism  = nullptr; +    double    minAdjFitness = -1.0; + +    for (auto& i : _allOrganisms) { +        if (i._lifetime >= _prms._minimumLifetime && !i._isLocked) { +            double orgAdjFitness = i._fitness / static_cast<double>(_species[i._specie].size()); + +            if (orgAdjFitness < minAdjFitness || minAdjFitness == -1.0) { +                minAdjFitness = orgAdjFitness; +                poorOrganism  = &i; +            } +        } +    } + +    if (poorOrganism->_isFrozen) { +        poorOrganism->_isFrozen = false; +        --_frozenOrganisms; +    } + +    poorOrganism->_fitness  = 0.0; +    poorOrganism->_lifetime = 0; +    poorOrganism->_genome._nodeGenes.clear(); + +    if (poorOrganism->_behavior) { +        poorOrganism->_behavior->reset(); +    } + +    auto& childSpec = _species[poorOrganism->_specie]; +    auto  childIdx  = find(childSpec.begin(), childSpec.end(), poorOrganism); +    childSpec.erase(childIdx); + +    return poorOrganism; +} + +Vector<Organism*>* +Population::chooseParentSpecie() +{ +    double totalAverageFitnesses = 0.0; +    Vector<double> averageFitnesses; +    averageFitnesses.reserve(_species.size()); + +    for (auto &i : _species) { +        double specieFitness = 0.0; +        size_t specieSize    = 0; + +        for (auto &j : i) { +            if (j->_lifetime >= _prms._minimumLifetime) { +                specieFitness += j->_fitness; +                ++specieSize; +            } +        } + +        if (specieSize == 0) { +            averageFitnesses.emplace_back(0.0); +        } else { +            specieFitness /= static_cast<double>(specieSize); +            averageFitnesses.emplace_back(specieFitness); +            totalAverageFitnesses += specieFitness; +        } +    } + +    size_t specieIdx = 0; +    double selector  = getRandReal(0.0, totalAverageFitnesses) - averageFitnesses.front(); + +    while (selector > 0.0) { +        ++specieIdx; +        selector -= averageFitnesses[specieIdx]; +    } + +    return &_species[specieIdx]; +} + +void +Population::breedAsexually(Genome& child, const Genome& mother) +{ +    child = mother; + +    if (mutateNodesAndLinks(child)) { +        return; +    } + +    for (auto& i : child._nodeGenes) { +        for (auto& j : i.second._linkGenes) { +            if (getChance(_prms._weightMutationRate)) { +                j.second._weight += getWeightDeviation(); + +                if (j.second._weight > _prms._weightRange) { +                    j.second._weight = _prms._weightRange; +                } else if (j.second._weight < -_prms._weightRange) { +                    j.second._weight = -_prms._weightRange; +                } +            } +        } +    } +} + +void +Population::breedSexually(Genome& child, const Genome& mother, const Genome& father) +{ +    child = mother; + +    for (auto& i : child._nodeGenes) { +        if (father._nodeGenes.count(i.first)) { +            auto& fatherNode = father._nodeGenes.at(i.first); + +            for (auto& j : i.second._linkGenes) { +                if (fatherNode._linkGenes.count(j.first)) { +                    auto& childLink  = j.second; +                    auto& fatherLink = fatherNode._linkGenes.at(j.first); + +                    childLink._weight += fatherLink._weight; +                    childLink._weight /= 2.0; + +                    if (!childLink._isEnabled || !fatherLink._isEnabled) { +                        if (getChance(_prms._geneDisablingRatio)) { +                            childLink._isEnabled = false; +                        } else { +                            childLink._isEnabled = true; +                        } +                    } +                } +            } +        } +    } +} + +bool +Population::mutateNodesAndLinks(Genome& child) +{ +    class LinkMutation { +    public: +        LinkMutation() = default; +        LinkMutation(size_t source, size_t target) +            : _source(source), _target(target) +        {} + +        size_t _source = 0; +        size_t _target = 0; +    }; + +    class NodeMutation { +    public: +        NodeMutation() = default; +        NodeMutation(size_t source, size_t target, double weight) +            : _source(source), _target(target), _weight(weight) +        {} + +        size_t _source = 0; +        size_t _target = 0; +        double _weight = 0.0; +    }; + +    if (getChance(_prms._linkMutationRate)) { +        Vector<LinkMutation> linkMutations; + +        for (auto& i : child._nodeGenes) { +            auto& childNode  = i.first; +            auto& childLinks = i.second._linkGenes; +            auto& childDepth = i.second._depth; + +            for (size_t j = 0; j < child._inputs; ++j) { +                if (!childLinks.count(j)) { +                    linkMutations.emplace_back(j, childNode); +                } +            } + +            for (auto& j : child._nodeGenes) { +                auto& sourceNode  = j.first; +                auto& sourceDepth = j.second._depth; + +                if (!childLinks.count(sourceNode) && childDepth > sourceDepth) { +                    linkMutations.emplace_back(sourceNode, childNode); +                } +            } +        } + +        if (!linkMutations.empty()) { +            size_t mutationIdx = getRandSize(0, linkMutations.size() - 1); +            size_t target      = linkMutations[mutationIdx]._target; +            size_t source      = linkMutations[mutationIdx]._source; + +            child._nodeGenes[target]._linkGenes[source] = {0.0}; +        } + +        return true; +    } + +    if (getChance(_prms._nodeMutationRate)) { +        Vector<NodeMutation> nodeMutations; + +        for (auto& i : child._nodeGenes) { +            for (auto& j : i.second._linkGenes) { +                auto& childLink = j.second; + +                if (childLink._isEnabled) { +                    nodeMutations.emplace_back(j.first, i.first, childLink._weight); +                } +            } +        } + +        size_t mutationIdx = getRandSize(0, nodeMutations.size() - 1); +        size_t target      = nodeMutations[mutationIdx]._target; +        size_t source      = nodeMutations[mutationIdx]._source; +        double targetDepth = child._nodeGenes[target]._depth; +        double sourceDepth = 0.0; + +        if (source >= child._inputs) { +            sourceDepth = child._nodeGenes[source]._depth; +        } + +        double   depth    = (targetDepth + sourceDepth) / 2.0; +        NodeType function = getRandNodeType(); + +        Innovation innov = {0, source, target, depth, function}; +        auto       iter  = find(_innovations.begin(), _innovations.end(), innov); +        size_t     newID = 0; + +        if (iter != _innovations.end()) { +            newID = iter->_number; +        } else { +            newID = _innovations.size() + _basicInnovs; +            _innovations.emplace_back(newID, source, target, depth, function); +        } + +        child._nodeGenes[newID]                                = {depth, function}; +        child._nodeGenes[newID]._linkGenes[source]             = {0.0}; +        child._nodeGenes[target]._linkGenes[newID]             = {0.0}; +        child._nodeGenes[target]._linkGenes[source]._isEnabled = false; + +        return true; +    } + +    return false; +} + +void +Population::assignToSpecie(Organism& org) +{ +    bool included = false; + +    for (auto i = _species.begin(), end = _species.end(); i != end; ++i) { +        if (i->empty()) { +            continue; +        } + +        double genDistance = computeDistance((*i)[0]->_genome, org._genome); + +        if (genDistance < _distanceThreshold) { +            included    = true; +            org._specie = distance(_species.begin(), i); +            i->emplace_back(&org); +            break; +        } +    } + +    if (!included) { +        org._specie = _species.size(); +        _species.emplace_back(1, &org); +    } +} + +void +Population::organizeSpecies() +{ +    _species.clear(); + +    for (auto& i : _allOrganisms) { +        assignToSpecie(i); +    } + +    if (_species.size() < _prms._targetSpeciesCount && _distanceThreshold > _prms._distanceThresholdShift) { +        _distanceThreshold -= _prms._distanceThresholdShift; +    } else if (_species.size() > _prms._targetSpeciesCount) { +        _distanceThreshold += _prms._distanceThresholdShift; +    } +} + + +double +Population::computeDistance(const Genome& g1, const Genome& g2) const +{ +    class LinkPair { +    public: +        const Genome::NodeGene::LinkGene* _l1 = nullptr; +        const Genome::NodeGene::LinkGene* _l2 = nullptr; +    }; + +    using LinkPairs = Map<size_t, LinkPair>; + +    class GenePair { +    public: +        const Genome::NodeGene* _g1 = nullptr; +        const Genome::NodeGene* _g2 = nullptr; +        LinkPairs _links; +    }; + +    using GenePairs = Map<size_t, GenePair>; + +    auto alignGenes = [](GenePairs& gPairs, const Genome& g1, const Genome& g2) { +        for (auto& i : g1._nodeGenes) { +            gPairs[i.first]._g1 = &i.second; + +            for (auto& j : i.second._linkGenes) { +                gPairs[i.first]._links[j.first]._l1 = &j.second; +            } +        } + +        for (auto& i : g2._nodeGenes) { +            gPairs[i.first]._g2 = &i.second; + +            for (auto& j : i.second._linkGenes) { +                gPairs[i.first]._links[j.first]._l2 = &j.second; +            } +        } +    }; + +    GenePairs gPairs; +    alignGenes(gPairs, g1, g2); + +    double g1Size           = 0.0; +    double g2Size           = 0.0; +    double disjointGenes    = 0.0; +    double linkGenePairs    = 0.0; +    double weightDifference = 0.0; + +    for (auto& i : gPairs) { +        if (i.second._g1 && i.second._g2) { +            ++g1Size; +            ++g2Size; + +            for (auto& j : i.second._links) { +                if (j.second._l1 && j.second._l2) { +                    ++g1Size; +                    ++g2Size; + +                    ++linkGenePairs; +                    weightDifference += fabs(j.second._l1->_weight - j.second._l2->_weight); +                } else if (j.second._l1) { +                    ++g1Size; +                    ++disjointGenes; +                } else { +                    ++g2Size; +                    ++disjointGenes; +                } +            } +        } else if (i.second._g1) { +            double geneSize = static_cast<double>(1 + i.second._links.size()); +            g1Size         += geneSize; +            disjointGenes  += geneSize; +        } else { +            double geneSize = static_cast<double>(1 + i.second._links.size()); +            g2Size         += geneSize; +            disjointGenes  += geneSize; +        } +    } + +    double normalize      = g1Size > g2Size ? g1Size : g2Size; +    double disjointFactor = (_prms._c1Disjoint * disjointGenes) / normalize; +    double weightFactor   = 0.0; + +    if (linkGenePairs != 0.0) { +        weightFactor  = (_prms._c3WeightDifference * weightDifference) / linkGenePairs; +    } + +    return disjointFactor + weightFactor; +} + +size_t +Population::getRandSeed() const +{ +    return chrono::system_clock::now().time_since_epoch().count(); +} + +size_t +Population::getRandSize(size_t low, size_t hi) +{ +    return IntDist(low, hi)(_randGen); +} + +double +Population::getRandReal(double low, double hi) +{ +    return RealDist(low, hi)(_randGen); +} + +double +Population::getRandWeight() +{ +    return _weightSelector(_randGen); +} + +double +Population::getWeightDeviation() +{ +    return _weightDeviator(_randGen); +} + +NodeType +Population::getRandNodeType() +{ +    return static_cast<NodeType>(_nodeTypeSelector(_randGen)); +} + +bool +Population::getChance(double ratio) +{ +    return _chanceSelector(_randGen) < ratio; +} diff --git a/src/QuadTree.cpp b/src/QuadTree.cpp new file mode 100644 index 0000000..d6686ff --- /dev/null +++ b/src/QuadTree.cpp @@ -0,0 +1,55 @@ +#include <HyperNeat/QuadTree.hpp> + +using namespace std; +using namespace hyperneat; + +QuadTree::QuadTree(double segment, double x, double y) +    : _segment(segment), _x(x), _y(y) +{} + +double +QuadTree::getSegment() const +{ +    return _segment; +} + +double +QuadTree::getX() const +{ +    return _x; +} + +double +QuadTree::getY() const +{ +    return _y; +} + +void +QuadTree::subdivide(Function<bool(QuadTree*)> subdivider) +{ +    if (subdivider(this)) { +        double newSeg = _segment / 2.0; +        _children.resize(4); +        _children[0] = {newSeg, _x - newSeg, _y - newSeg}; +        _children[1] = {newSeg, _x + newSeg, _y - newSeg}; +        _children[2] = {newSeg, _x - newSeg, _y + newSeg}; +        _children[3] = {newSeg, _x + newSeg, _y + newSeg}; + +        for (auto &i : _children) { +            i.subdivide(subdivider); +        } +    } +} + +void +QuadTree::traverse(Function<void(const QuadTree*)> traverser) const +{ +    if (!_children.empty()) { +        for (auto &i : _children) { +            i.traverse(traverser); +        } +    } else { +        traverser(this); +    } +} diff --git a/src/Utils/LoadFile.cpp b/src/Utils/LoadFile.cpp new file mode 100644 index 0000000..3849f76 --- /dev/null +++ b/src/Utils/LoadFile.cpp @@ -0,0 +1,280 @@ +#include <HyperNeat/Population.hpp> +#include <HyperNeat/NoveltyMetric.hpp> +#include <HyperNeat/NeuralNetPrms.hpp> +#include <HyperNeat/Utils/LoadFile.hpp> + +using namespace std; +using namespace hyperneat; + +LoadFile::LoadFile(Istream& stream) +    : _stream(stream) +{ +    _stream.setf(ios::boolalpha); +} + +void +LoadFile::loadPopulation(Population& population) +{ +    size_t  speciesCnt       = 0; +    size_t  innovationsCount = 0; +    ssize_t lastReplacement  = 0; +    ssize_t lastMother       = 0; +    ssize_t lastFather       = 0; +    bool    hasNoveltyMetric = false; +    bool    hasNeuralNets    = false; +    auto&   prms             = population._prms; + +    nextPrm() >> population._populationLock; +    nextPrm() >> population._lockedOrganisms; +    nextPrm() >> population._frozenOrganisms; +    nextPrm() >> innovationsCount; +    nextPrm() >> population._basicInnovs; +    nextPrm() >> lastReplacement; +    nextPrm() >> lastMother; +    nextPrm() >> lastFather; +    nextPrm() >> population._replacements; +    nextPrm() >> population._distanceThreshold; +    nextPrm() >> population._oldOrganisms; +    nextPrm() >> population._minOldOrganisms; +    nextPrm() >> hasNoveltyMetric; +    nextPrm() >> population._updates; +    nextPrm() >> speciesCnt; +    nextPrm() >> hasNeuralNets; + +    loadPopulationPrms(prms); + +    if (hasNeuralNets) { +        population._nnPrms = Pointer<NeuralNetPrms>(new NeuralNetPrms); +        loadNeuralNetPrms(*population._nnPrms); +    } + +    population._innovations.resize(innovationsCount); + +    for (auto& i : population._innovations) { +        String nodeStr; + +        nextPrm() >> i._number; +        nextPrm() >> i._source; +        nextPrm() >> i._target; +        nextPrm() >> i._depth; +        nextPrm() >> nodeStr; + +        i._nodeType = stringToNode(nodeStr); +    } + +    population._allOrganisms.resize(prms._popSize, Organism(&population)); +    population._species.resize(speciesCnt); + +    for (auto& i : population._allOrganisms) { +        loadOrganism(i); +    } + +    population._lastReplacement = (lastReplacement == -1 ? nullptr: &population._allOrganisms[lastReplacement]); +    population._lastMother      = (lastMother      == -1 ? nullptr: &population._allOrganisms[lastMother]); +    population._lastFather      = (lastFather      == -1 ? nullptr: &population._allOrganisms[lastFather]); + +    for (auto& i : population._species) { +        size_t specieSize = 0; +        nextPrm() >> specieSize; + +        while (specieSize--) { +            size_t organismIdx = 0; +            nextArrayValue() >> organismIdx; + +            i.emplace_back(&population._allOrganisms[organismIdx]); +        } +    } + +    if (hasNoveltyMetric) { +        NoveltyMetricPrms nmPrms; +        loadNoveltyMetricPrms(nmPrms); + +        population.setNoveltyMetric(nmPrms); +        loadNoveltyMetric(*population._noveltyMetric); +    } + +    if (hasNeuralNets) { +        population.generateAllNeuralNets(); +    } + +    if (prms._seed != 0) { +        population._randGen.seed(prms._seed); +    } else { +        population._randGen.seed(population.getRandSeed()); +    } + +    population._weightDeviator = BellDist(0.0, prms._weightDeviation); +    population._weightSelector = RealDist(-prms._weightRange, prms._weightRange); + +    population._organismsBeingGenerated = 0; +} + +void +LoadFile::loadPopulationPrms(PopulationPrms& prms) +{ +    nextPrm() >> prms._popSize; +    nextPrm() >> prms._cppnInputs; +    nextPrm() >> prms._cppnOutputs; +    nextPrm() >> prms._seed; +    nextPrm() >> prms._weightRange; +    nextPrm() >> prms._c1Disjoint; +    nextPrm() >> prms._c3WeightDifference; +    nextPrm() >> prms._initialDistanceThreshold; +    nextPrm() >> prms._distanceThresholdShift; +    nextPrm() >> prms._sexualReproductionRate; +    nextPrm() >> prms._weightMutationRate; +    nextPrm() >> prms._weightDeviation; +    nextPrm() >> prms._interspeciesMatingRate; +    nextPrm() >> prms._geneDisablingRatio; +    nextPrm() >> prms._linkMutationRate; +    nextPrm() >> prms._nodeMutationRate; +    nextPrm() >> prms._targetSpeciesCount; +    nextPrm() >> prms._eligibilityRatio; +    nextPrm() >> prms._minimumLifetime; +    nextPrm() >> prms._replBeforeReorganization; +} + +void +LoadFile::loadNeuralNetPrms(NeuralNetPrms& prms) +{ +    size_t inputs  = 0; +    size_t outputs = 0; + +    nextPrm() >> prms._testGridLevel; +    nextPrm() >> prms._maxQuadTreeLevel; +    nextPrm() >> prms._minQuadTreeLevel; +    nextPrm() >> prms._bandPruningThreshold; +    nextPrm() >> prms._varianceThreshold; +    nextPrm() >> prms._divisionThreshold; +    nextPrm() >> prms._iterations; +    nextPrm() >> inputs; +    nextPrm() >> outputs; + +    prms._inputMap.resize(inputs); +    prms._outputMap.resize(outputs); + +    for (auto& i : prms._inputMap) { +        nextArrayValue() >> i._x; +        nextArrayValue() >> i._y; +    } + +    for (auto& i : prms._outputMap) { +        nextArrayValue() >> i._x; +        nextArrayValue() >> i._y; +    } +} + +void +LoadFile::loadNoveltyMetric(NoveltyMetric& noveltyMetric) +{ +    for (auto& i : noveltyMetric._behaviors) { +        nextPrm() >> i._criteriaReached; +        nextPrm() >> i._noveltyScore; +        nextPrm() >> i._toBeArchived; + +        for (auto& j : i._characterization) { +            nextArrayValue() >> j; +        } +    } + +    size_t archiveSize = 0; +    nextPrm() >> archiveSize; +    noveltyMetric._archive.resize(archiveSize); + +    for (auto& i : noveltyMetric._archive) { +        i.resize(noveltyMetric._prms._characterizationSize, 0.0); + +        for (auto& j : i) { +            nextArrayValue() >> j; +        } +    } +} + +void +LoadFile::loadNoveltyMetricPrms(NoveltyMetricPrms& noveltyMetricPrms) +{ +    nextPrm() >> noveltyMetricPrms._noveltyThreshold; +    nextPrm() >> noveltyMetricPrms._referenceOrganisms; +    nextPrm() >> noveltyMetricPrms._characterizationSize; +    nextPrm() >> noveltyMetricPrms._criteriaReachedByDefault; +} + +void +LoadFile::loadOrganism(Organism& organism) +{ +    nextPrm() >> organism._index; +    nextPrm() >> organism._fitness; +    nextPrm() >> organism._isLocked; +    nextPrm() >> organism._isFrozen; +    nextPrm() >> organism._specie; +    nextPrm() >> organism._lifetime; + +    loadGenome(organism._genome); +} + +void +LoadFile::loadGenome(Genome& genome) +{ +    size_t nodes = 0; + +    nextPrm() >> genome._inputs; +    nextPrm() >> nodes; + +    while (nodes--) { +        String nodeType; +        size_t links = 0; +        size_t innov = 0; + +        nextPrm() >> innov; +        auto& nodeGene = genome._nodeGenes[innov]; + +        nextPrm() >> nodeGene._depth; +        nextPrm() >> nodeType; +        nodeGene._nodeType = stringToNode(nodeType); + +        nextPrm() >> links; + +        while (links--) { +            size_t source = 0; + +            nextPrm() >> source; +            auto& linkGene = nodeGene._linkGenes[source]; + +            nextPrm() >> linkGene._weight; +            nextPrm() >> linkGene._isEnabled; +        } +    } +} + +Istream& +LoadFile::nextPrm(bool arrayVal) +{ +    for (;;) { +        char ch = static_cast<char>(_stream.peek()); + +        if (ch == '#') { +            _stream.ignore(numeric_limits<streamsize>::max(), '\n'); +        } else { +            if (!arrayVal) { +                _stream.ignore(); + +                if (ch == '=') { +                    return _stream; +                } +            } else { +                if (string("-0123456789").find(ch) != string::npos) { +                    return _stream; +                } + +                _stream.ignore(); +            } +        } +    } +} + + +Istream& +LoadFile::nextArrayValue() +{ +    return nextPrm(true); +} diff --git a/src/Utils/NodeTypes.cpp b/src/Utils/NodeTypes.cpp new file mode 100644 index 0000000..b11b079 --- /dev/null +++ b/src/Utils/NodeTypes.cpp @@ -0,0 +1,41 @@ +#include <HyperNeat/Utils/NodeTypes.hpp> + +namespace hyperneat +{ +    String +    nodeToString(NodeType type) +    { +        switch (type) { +            case NodeType::SIGMOID: +                return "\"sigmoid\""; + +            case NodeType::GAUSSIAN: +                return "\"gaussian\""; + +            case NodeType::SINE: +                return "\"sine\""; + +            case NodeType::ABSOLUTE: +                return "\"absolute\""; + +            default: +                return "\"nullType\""; +        } +    } + +    NodeType +    stringToNode(const String& str) +    { +        if (str == "\"sigmoid\"") { +            return NodeType::SIGMOID; +        } else if (str == "\"gaussian\"") { +            return NodeType::GAUSSIAN; +        } else if (str == "\"sine\"") { +            return NodeType::SINE; +        } else if (str == "\"absolute\"") { +            return NodeType::ABSOLUTE; +        } else { +            return NodeType::NULL_TYPE; +        } +    } +} diff --git a/src/Utils/Point.cpp b/src/Utils/Point.cpp new file mode 100644 index 0000000..7dd9610 --- /dev/null +++ b/src/Utils/Point.cpp @@ -0,0 +1,33 @@ +#include <cmath> +#include <HyperNeat/Utils/Point.hpp> + +using namespace std; +using namespace hyperneat; + +Point::Point(double x, double y) +    : _x(x), _y(y) +{} + +double +Point::distance(const Point& other) const +{ +    double x = _x - other._x; +    double y = _y - other._y; + +    return sqrt(x * x + y * y); +} + +bool +Point::operator==(const Point& other) const{ +    return (_x == other._x) && (_y == other._y); +} + +bool +Point::operator<(const Point& other) const +{ +    if (_x == other._x) { +        return _y < other._y; +    } else { +        return _x < other._x; +    } +} diff --git a/src/Utils/SaveFile.cpp b/src/Utils/SaveFile.cpp new file mode 100644 index 0000000..8c471f6 --- /dev/null +++ b/src/Utils/SaveFile.cpp @@ -0,0 +1,249 @@ +#include <HyperNeat/Population.hpp> +#include <HyperNeat/NoveltyMetric.hpp> +#include <HyperNeat/NeuralNetPrms.hpp> +#include <HyperNeat/Utils/SaveFile.hpp> + +using namespace std; +using namespace hyperneat; + +SaveFile::SaveFile(Ostream& stream) +    : _stream(stream) +{ +    _stream.setf(ios::boolalpha); +    _stream.precision(numeric_limits<double>::digits10); +} + +void +SaveFile::savePopulation(Population& population, bool shuttedDown, size_t tabs, const String& prefix) +{ +    print(tabs) << "# hyperneat::Population data:"                                                           << newl(); +    print(tabs) << "# -------------------------------------------------------------------------------------" << newl(); +    print(tabs) << "# DO NOT erase or change the order of any entry! Data is read back ENTRY by ENTRY."      << newl(2); + +    ssize_t lastReplacement = (population.getLastReplacement() ? population.getLastReplacement()->getIndex() : -1); +    ssize_t lastMother      = (population.getLastMother() ? population.getLastMother()->getIndex() : -1); +    ssize_t lastFather      = (population.getLastFather() ? population.getLastFather()->getIndex() : -1); + +    print(tabs) << "[" << prefix << "population]"                                                    << newl(); +    print(tabs + 1) << "populationLock    = " << (shuttedDown ? false : population.isLocked())       << newl(); +    print(tabs + 1) << "lockedOrganisms   = " << (shuttedDown ? 0 : population.getLockedOrganisms()) << newl(); +    print(tabs + 1) << "frozenOrganisms   = " << (shuttedDown ? 0 : population.getFrozenOrganisms()) << newl(); +    print(tabs + 1) << "innovationsCount  = " << population.getInnovationsCount()                    << newl(); +    print(tabs + 1) << "basicInnovations  = " << population.getBasicInnovationsCount()               << newl(); +    print(tabs + 1) << "lastReplacement   = " << lastReplacement                                     << newl(); +    print(tabs + 1) << "lastMother        = " << lastMother                                          << newl(); +    print(tabs + 1) << "lastFather        = " << lastFather                                          << newl(); +    print(tabs + 1) << "replacements      = " << population.getReplacements()                        << newl(); +    print(tabs + 1) << "distanceThreshold = " << population.getDistanceThreshold()                   << newl(); +    print(tabs + 1) << "oldOrganisms      = " << (shuttedDown ? 0 : population.getOldOrganisms())    << newl(); +    print(tabs + 1) << "minOldOrganisms   = " << population.getMinimumOldOrganisms()                 << newl(); +    print(tabs + 1) << "noveltyMetric     = " << population.isNoveltyMetricSet()                     << newl(); +    print(tabs + 1) << "updates           = " << population.getUpdates()                             << newl(); +    print(tabs + 1) << "species           = " << population.getSpecies().size()                      << newl(); +    print(tabs + 1) << "withNeuralNets    = " << population.hasNeuralNets()                          << newl(2); + +    savePopulationPrms(population.getPopulationPrms(), tabs + 1, prefix + "population."); + +    if (population.hasNeuralNets()) { +        print() << newl(); +        saveNeuralNetPrms(population.getNeuralNetPrms(), tabs + 1, prefix + "population."); +    } + +    for (auto& i : population.getInnovations()) { +        print()                                                       << newl(); +        print(tabs + 1) << "[[" + prefix + "population.innovation]]"  << newl(); +        print(tabs + 2) << "number   = " << i._number                 << newl(); +        print(tabs + 2) << "source   = " << i._source                 << newl(); +        print(tabs + 2) << "target   = " << i._target                 << newl(); +        print(tabs + 2) << "depth    = " << i._depth                  << newl(); +        print(tabs + 2) << "function = " << nodeToString(i._nodeType) << newl(); +    } + +    for (auto& i : population.getAllOrganisms()) { +        print() << newl(); +        saveOrganism(i, shuttedDown, tabs + 1, prefix + "population."); +    } + +    for (auto& i : population.getSpecies()) { +        print() << newl(); +        print(tabs + 1) << "[[" + prefix + "population.specie]]" << newl(); +        print(tabs + 2) << "size    = " << i.size()              << newl(); +        print(tabs + 2) << "members = ["                         << newl(); + +        for (auto& j : i) { +            print(tabs + 3) << j->getIndex() << "," << newl(); +        } + +        print(tabs + 2) << "]" << newl(); +    } + +    if (population.isNoveltyMetricSet()) { +        print() << newl(); +        saveNoveltyMetric(population.getNoveltyMetric(), shuttedDown, tabs + 1, prefix + "population."); +    } +} + +void +SaveFile::savePopulationPrms(const PopulationPrms& prms, size_t tabs, const String& prefix) +{ +    print(tabs) << "[" << prefix << "parameters]"                                      << newl(); +    print(tabs + 1) << "popSize                  = " << prms._popSize                  << newl(); +    print(tabs + 1) << "cppnInputs               = " << prms._cppnInputs               << newl(); +    print(tabs + 1) << "cppnOutputs              = " << prms._cppnOutputs              << newl(); +    print(tabs + 1) << "seed                     = " << prms._seed                     << newl(); +    print(tabs + 1) << "weightRange              = " << prms._weightRange              << newl(); +    print(tabs + 1) << "disjointCoeff            = " << prms._c1Disjoint               << newl(); +    print(tabs + 1) << "weightDifferenceCoeff    = " << prms._c3WeightDifference       << newl(); +    print(tabs + 1) << "initialDistanceThreshold = " << prms._initialDistanceThreshold << newl(); +    print(tabs + 1) << "distanceThresholdShift   = " << prms._distanceThresholdShift   << newl(); +    print(tabs + 1) << "sexualReproductionRate   = " << prms._sexualReproductionRate   << newl(); +    print(tabs + 1) << "weightMutationRate       = " << prms._weightMutationRate       << newl(); +    print(tabs + 1) << "weightDeviation          = " << prms._weightDeviation          << newl(); +    print(tabs + 1) << "interspeciesMatingRate   = " << prms._interspeciesMatingRate   << newl(); +    print(tabs + 1) << "geneDisablingRatio       = " << prms._geneDisablingRatio       << newl(); +    print(tabs + 1) << "linkMutationRate         = " << prms._linkMutationRate         << newl(); +    print(tabs + 1) << "nodeMutationRate         = " << prms._nodeMutationRate         << newl(); +    print(tabs + 1) << "targetSpeciesCount       = " << prms._targetSpeciesCount       << newl(); +    print(tabs + 1) << "eligibilityRatio         = " << prms._eligibilityRatio         << newl(); +    print(tabs + 1) << "minimumLifetime          = " << prms._minimumLifetime          << newl(); +    print(tabs + 1) << "replBeforeReorganization = " << prms._replBeforeReorganization << newl(); +} + +void +SaveFile::saveNeuralNetPrms(const NeuralNetPrms& prms, size_t tabs, const String& prefix) +{ +    print(tabs) << "[" << prefix << "neuralNetParameters]"                     << newl(); +    print(tabs + 1) << "testGridLevel        = " << prms._testGridLevel        << newl(); +    print(tabs + 1) << "maxQuadTreeLevel     = " << prms._maxQuadTreeLevel     << newl(); +    print(tabs + 1) << "minQuadTreeLevel     = " << prms._minQuadTreeLevel     << newl(); +    print(tabs + 1) << "bandPruningThreshold = " << prms._bandPruningThreshold << newl(); +    print(tabs + 1) << "varianceThreshold    = " << prms._varianceThreshold    << newl(); +    print(tabs + 1) << "divisionThreshold    = " << prms._divisionThreshold    << newl(); +    print(tabs + 1) << "iterations           = " << prms._iterations           << newl(); +    print(tabs + 1) << "inputs               = " << prms._inputMap.size()      << newl(); +    print(tabs + 1) << "outputs              = " << prms._outputMap.size()     << newl(2); +    print(tabs + 1) << "inputMap = ["                                          << newl(); + +    for (auto& i : prms._inputMap) { +        print(tabs + 2) << "[" << i._x << ", " << i._y << "]," << newl(); +    } + +    print(tabs + 1) << "]"             << newl(2); +    print(tabs + 1) << "outputMap = [" << newl(); + +    for (auto& i : prms._outputMap) { +        print(tabs + 2) << "[" << i._x << ", " << i._y << "]," << newl(); +    } + +    print(tabs + 1) << "]" << newl(); +} + +void +SaveFile::saveOrganism(const Organism& organism, bool shuttedDown, size_t tabs, const String& prefix) +{ +    print(tabs) << "[[" << prefix << "organism]]" << newl(); + +    if (organism.isChampion()) { +        print(tabs + 1) << "# Current champion." << newl(2); +    } + +    print(tabs + 1) << "index    = " << organism.getIndex()                         << newl(); +    print(tabs + 1) << "fitness  = " << (shuttedDown ? 0 : organism._fitness)       << newl(); +    print(tabs + 1) << "isLocked = " << (shuttedDown ? false : organism.isLocked()) << newl(); +    print(tabs + 1) << "isFrozen = " << (shuttedDown ? false : organism.isFrozen()) << newl(); +    print(tabs + 1) << "specie   = " << organism.getSpecie()                        << newl(); +    print(tabs + 1) << "lifetime = " << (shuttedDown ? 0 : organism.getLifetime())  << newl(2); + +    saveGenome(organism.getGenome(), tabs + 1, prefix + "organism."); + +    // If shutted down, save Neural Net +} + +void +SaveFile::saveGenome(const Genome& genome, size_t tabs, const String& prefix) +{ +    print(tabs) << "[" << prefix << "genome]"                     << newl(); +    print(tabs + 1) << "inputs = "    << genome._inputs           << newl(); +    print(tabs + 1) << "nodes  = "    << genome._nodeGenes.size() << newl(); + +    for (auto& i : genome._nodeGenes) { +        print()                                                                << newl(); +        print(tabs + 1) << "[[" << prefix << "genome.nodeGene]]"               << newl(); +        print(tabs + 2) << "innovation = " << i.first                          << newl(); +        print(tabs + 2) << "depth      = " << i.second._depth                  << newl(); +        print(tabs + 2) << "function   = " << nodeToString(i.second._nodeType) << newl(); +        print(tabs + 2) << "links      = " << i.second._linkGenes.size()       << newl(); + +        for (auto& j : i.second._linkGenes) { +            print()                                                           << newl(); +            print(tabs + 2) << "[[" << prefix << "genome.nodeGene.linkGene]]" << newl(); +            print(tabs + 3) << "source    = " << j.first                      << newl(); +            print(tabs + 3) << "weight    = " << j.second._weight             << newl(); +            print(tabs + 3) << "isEnabled = " << j.second._isEnabled          << newl(); +        } +    } +} + +void +SaveFile::saveNoveltyMetric(const NoveltyMetric& noveltyMetric, bool shuttedDown, size_t tabs, const String& prefix) +{ +    print(tabs) << "[" << prefix << "noveltyMetric]" << newl(); +    saveNoveltyMetricPrms(noveltyMetric.getPrms(), tabs + 1, prefix + "noveltyMetric."); + +    bool critDef = noveltyMetric.getPrms()._criteriaReachedByDefault; + +    for (auto& i : noveltyMetric.getBehaviors()) { +        print()                                                                                   << newl(); +        print(tabs + 1) << "[[" << prefix << "noveltyMetric.behavior]]"                           << newl(); +        print(tabs + 2) << "criteriaReached  = " << (shuttedDown ? critDef : i._criteriaReached)  << newl(); +        print(tabs + 2) << "noveltyScore     = " << (shuttedDown ? 0 : i.getNoveltyScore())       << newl(); +        print(tabs + 2) << "toBeArchived     = " << (shuttedDown ? false : i.isToBeArchived())    << newl(); +        print(tabs + 2) << "characterization = ["                                                 << newl(); + +        for (auto& j : i.getCharacterization()) { +            print(tabs + 3) << j << "," << newl(); +        } + +        print(tabs + 2) << "]" << newl(); +    } + +    print()                                                                        << newl(); +    print(tabs + 1) << "[" << prefix << "noveltyMetric.archive]"                   << newl(); +    print(tabs + 2) << "size              = " << noveltyMetric.getArchive().size() << newl(); +    print(tabs + 2) << "characterizations = ["                                     << newl(); + +    for (auto& i : noveltyMetric.getArchive()) { +        print(tabs + 3) << "[" << newl(); + +        for (auto& j : i) { +            print(tabs + 4) << j << "," << newl(); +        } + +        print(tabs + 3) << "]," << newl(); +    } + +    print(tabs + 2) << "]" << newl(); +} + +void +SaveFile::saveNoveltyMetricPrms(const NoveltyMetricPrms& noveltyMetricPrms, size_t tabs, const String& prefix) +{ +    print(tabs) << "[" << prefix << "parameters]" << newl(); +    print(tabs + 1) << "noveltyThreshold         = " << noveltyMetricPrms._noveltyThreshold         << newl(); +    print(tabs + 1) << "referenceOrganisms       = " << noveltyMetricPrms._referenceOrganisms       << newl(); +    print(tabs + 1) << "characterizationSize     = " << noveltyMetricPrms._characterizationSize     << newl(); +    print(tabs + 1) << "criteriaReachedByDefault = " << noveltyMetricPrms._criteriaReachedByDefault << newl(); +} + +Ostream& +SaveFile::print(size_t tabs) +{ +    _stream << String(tabs * 4, ' '); +    return _stream; +} + +String +SaveFile::newl(size_t lines) +{ +    return String(lines, '\n'); +} diff --git a/src/Utils/ValuePoint.cpp b/src/Utils/ValuePoint.cpp new file mode 100644 index 0000000..d9cdc64 --- /dev/null +++ b/src/Utils/ValuePoint.cpp @@ -0,0 +1,7 @@ +#include <HyperNeat/Utils/ValuePoint.hpp> + +using namespace hyperneat; + +ValuePoint::ValuePoint(double x, double y, double value, double segment) +    : Point(x, y), _value(value), _segment(segment) +{} diff --git a/todolist.txt b/todolist.txt new file mode 100644 index 0000000..2071772 --- /dev/null +++ b/todolist.txt @@ -0,0 +1,44 @@ +FOR VERSION 0.1 Beta: + ✔ Test [minimal criteria = above average fitness] on NeuroRacers @done (14-04-05 03:47) + ✔ Serialize loaded and saved files in TOML @done (14-04-05 03:48) + ✔ Cppn functions should be Sine, Gaussian, Sigmoid and Absolute @done (14-04-05 18:44) + ✔ Add Population::setMinimumLifetime() @done (14-04-05 19:18) + ✔ Add NeuralNet::getAverageActivation() @done (14-04-05 19:53) + ✔ Place NeuralNet inside Organism class @done (14-04-11 03:08) + ✔ Load/Save system links to a iostream object instead of fstream @done (14-05-09 19:14) + ☐ Test cereal library (branch) + ☐ Load/Save system for NNets (Add Save Sim to Guppies) + ☐ Plugins: +   ☐ CPPN explorer +   ☐ NeuralNet Monitor +   ☐ Population Monitor + ☐ Create HyperGuppies + ☐ Code Doxygen documentation + ☐ Make tutorial + ☐ Release hyperneat:: 0.1 Beta + +FOR VERSION 1.0: + ☐ Test recursive CPPNs + ☐ addOrganism() / removeOrganism() / Change some parameters (Add Feature to Guppies) + ☐ Create functional copy & move operators (for CPPNs, NNets and Populations) + ☐ Create simple exception handling (for all public methods) + ☐ Create Brain class (apply on Guppies) + ☐ Allow non-realtime updating (NEAT instead of rtNEAT) + ☐ Test Population::update() as separate thread + ☐ Update documentation and tutorial + + +___________________ +Archive: + ✔ Find nice way to organize #includes @done (13-09-05 15:03) @project(FOR VERSION 0.1 Beta) + ✔ DEBUG!!! - Done ??? @done (13-10-06 23:53) @project(FOR VERSION 0.1 Beta) + ✔ Fix NeuralNet::create() @done (13-10-09 17:38) @project(FOR VERSION 0.1 Beta) + ✔ Make everything HyperThreaded again @done (13-10-11 04:41) @project(FOR VERSION 0.1 Beta) + ✔ Eliminate Population::getAllNeuralNets() @done (13-10-10 23:02) @project(FOR VERSION 0.1 Beta) + ✔ Recent update flag on Population @done (13-10-11 04:00) @project(FOR VERSION 0.1 Beta) + ✔ Make Neuron::Type @done (13-10-11 05:22) @project(FOR VERSION 0.1 Beta) + ✔ Test Genome::NodeGene matching system (Save & Load) @done (13-10-28 01:37) @project(FOR VERSION 0.1 Beta) + ✔ Include distance on Node Search @done (13-11-06 04:22) @project(FOR VERSION 0.1 Beta) + ✔ Revise Integer data types @done (13-11-09 23:52) @project(FOR VERSION 0.1 Beta) + ✔ Include a pointSetter() function as parameter to Population::update() function @done (13-11-10 00:20) @project(FOR VERSION 0.1 Beta) + ✔ Implement "Minimal Criteria Novelty Search" (test on NeuroRacers) @done (13-11-21 01:54) @project(FOR VERSION 0.1 Beta)  | 
