Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ AllowAllParametersOfDeclarationOnNextLine: false
BinPackArguments: false
BinPackParameters: false
IncludeBlocks: Merge
ColumnLimit: 120
ColumnLimit: 80
IndentWidth: 2
PointerAlignment: Left
AllowShortFunctionsOnASingleLine: Empty
...
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
build*/
_bld*/
.vscode/*
.ccls-cache/
compile_commands.json
.dir-locals.el
Expand Down
23 changes: 17 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.23)
project(EvolutionNet)

option(BUILD_EXAMPLES "Build Examples" OFF)
option(BUILD_TESTS "Build Tests" OFF)

add_library(${PROJECT_NAME} INTERFACE)
#########################
set(${PROJECT_NAME}_srcs
include/${PROJECT_NAME}/ConnectionGene.hpp
include/${PROJECT_NAME}/EvolutionNet.hpp
include/${PROJECT_NAME}/FlatMap.hpp
include/${PROJECT_NAME}/FlatSet.hpp
include/${PROJECT_NAME}/Genome.hpp
include/${PROJECT_NAME}/Network.hpp
include/${PROJECT_NAME}/Population.hpp
include/${PROJECT_NAME}/Random.hpp
include/${PROJECT_NAME}/Types.hpp
)
add_library(${PROJECT_NAME} INTERFACE ${${PROJECT_NAME}_srcs})
target_sources(${PROJECT_NAME} INTERFACE FILE_SET header_files TYPE HEADERS FILES ${${PROJECT_NAME}_srcs})
source_group("" FILES ${${PROJECT_NAME}_srcs})
target_include_directories(${PROJECT_NAME} INTERFACE include/)
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17)

#########################
if(${BUILD_EXAMPLES})
add_subdirectory(${PROJECT_SOURCE_DIR}/examples)
endif()

if(${BUILD_TESTS})
add_subdirectory(${PROJECT_SOURCE_DIR}/tests)
endif()
15 changes: 10 additions & 5 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
add_executable(${PROJECT_NAME}_example_xor_minimal xor_minimal.cpp)
target_link_libraries(${PROJECT_NAME}_example_xor_minimal PRIVATE ${PROJECT_NAME})

add_executable(${PROJECT_NAME}_example_xor_advanced xor_advanced.cpp)
target_link_libraries(${PROJECT_NAME}_example_xor_advanced PRIVATE ${PROJECT_NAME})
set(xor_advanced_srcs xor_advanced.cpp)
set(xor_minimal_srcs xor_minimal.cpp)
####################
add_executable(xor_advanced_example ${xor_advanced_srcs})
target_link_libraries(xor_advanced_example PRIVATE ${PROJECT_NAME})
source_group("" FILES ${xor_advanced_srcs})
####################
add_executable(xor_minimal_example ${xor_minimal_srcs})
target_link_libraries(xor_minimal_example PRIVATE ${PROJECT_NAME})
source_group("" FILES ${xor_minimal_srcs})
5 changes: 4 additions & 1 deletion include/EvolutionNet/ConnectionGene.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ class ConnectionGene final {
ConnectionGene(const ConnectionGene&) = default;

//! \brief Construct the aggregation.
inline ConnectionGene(const NodeId from, const NodeId to, const float weight, const bool enabled) noexcept;
inline ConnectionGene(const NodeId from,
const NodeId to,
const float weight,
const bool enabled) noexcept;

//! \return the weight of the link.
inline float getWeight() const noexcept;
Expand Down
65 changes: 44 additions & 21 deletions include/EvolutionNet/EvolutionNet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include <type_traits>

namespace EvolutionNet {

// clang-format off
/*! \class EvolutionNet
* \brief This class represents the main interface of this library.
* Some of the network features are set at compile time with template logic.
Expand All @@ -40,6 +40,7 @@ namespace EvolutionNet {
* net.evolve(); // Evolve in the next generation and loop!
* }
*/
// clang-format on
template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
class EvolutionNet {
public:
Expand All @@ -51,10 +52,12 @@ class EvolutionNet {

/*! \brief Initialize the Evolution Net.
* You need to call this function before any other operation.
* Here you can set the size of the population and the random seed used internally.
* \note `populationSize` must be greater than zero, otherwise Undefined Behavior.
* Here you can set the size of the population and the random seed used
* internally. \note `populationSize` must be greater than zero, otherwise
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we able to keep indentation for doxygen comments?

  • Indentation should be aligned with the first line
  • \command should be prefixed by newline

* Undefined Behavior.
*/
void initialize(const std::size_t populationSize, const SeedT rndSeed = DefaultSeed);
void initialize(const std::size_t populationSize,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why is breaking line?

const SeedT rndSeed = DefaultSeed);

//! \return all the networks (size of the population).
inline std::vector<NetworkT>& getNetworks() noexcept;
Expand All @@ -68,19 +71,23 @@ class EvolutionNet {
template <typename Fn>
inline void evaluateAll(Fn&& fn);

//! \return the best fitness score for this current generation. Call this only after ending evaluation.
//! \return the best fitness score for this current generation. Call this only
//! after ending evaluation.
inline FitnessScore getBestFitness() const noexcept;

//! \return the best network accordinlying with the max fitness score. Call this only after ending evaluation.
//! \return the best network accordinlying with the max fitness score. Call
//! this only after ending evaluation.
inline const NetworkT& getBestNetwork() const noexcept;
inline NetworkT* getBestNetworkMutable() noexcept;

/*! \brief Evolve the population.
* Call this only after ending evaluation, thus, fitness for each network has been set.
* Call this only after ending evaluation, thus, fitness for each network has
* been set.
*/
inline void evolve();

//! \return the size of the population. This is constant (does not change during evolution).
//! \return the size of the population. This is constant (does not change
//! during evolution).
inline std::size_t getPopulationSize() const noexcept;

//! \return the generation counter. First generation stats from 0.
Expand All @@ -91,7 +98,9 @@ class EvolutionNet {
struct IsValidEvaluationFunction : std::false_type {};

template <typename Fn>
struct IsValidEvaluationFunction<Fn, std::void_t<decltype(std::declval<Fn>()(std::declval<NetworkT*>()))>>
struct IsValidEvaluationFunction<
Fn,
std::void_t<decltype(std::declval<Fn>()(std::declval<NetworkT*>()))>>
: std::true_type {};

RndEngine rndEngine_;
Expand All @@ -104,8 +113,9 @@ class EvolutionNet {
};

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::initialize(const std::size_t populationSize,
const SeedT rndSeed) {
void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::initialize(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer having first argument on the same line. we can adjust the clang format I guess

const std::size_t populationSize,
const SeedT rndSeed) {
assert(populationSize > 0);

rndEngine_.seed(rndSeed);
Expand All @@ -120,23 +130,27 @@ void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::initialize(const std:
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
inline std::vector<typename EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::NetworkT>&
inline std::vector<
typename EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::NetworkT>&
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getNetworks() noexcept {
return networks_;
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
inline typename EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::NetworkT&
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getNetworkNth(const std::size_t i) noexcept {
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getNetworkNth(
const std::size_t i) noexcept {
assert(i < networks_.size());
return networks_[i];
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
template <typename Fn>
inline void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::evaluateAll(Fn&& fn) {
inline void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::evaluateAll(
Fn&& fn) {
static_assert(IsValidEvaluationFunction<Fn>::value,
"Fn is not a valid evaluation function. It should be something like `void(*)(Network*)`");
"Fn is not a valid evaluation function. It should be something "
"like `void(*)(Network*)`");

const std::size_t numNetworks = networks_.size();
FitnessScore fitness, fitnessMax;
Expand All @@ -163,21 +177,25 @@ inline void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::evaluateAll(Fn
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
FitnessScore EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getBestFitness() const noexcept {
FitnessScore
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getBestFitness()
const noexcept {
assert(bestNetwork_ != nullptr);
return bestNetwork_->getFitness();
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
const typename EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::NetworkT&
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getBestNetwork() const noexcept {
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getBestNetwork()
const noexcept {
assert(bestNetwork_ != nullptr);
return *bestNetwork_;
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
typename EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::NetworkT*
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getBestNetworkMutable() noexcept {
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::
getBestNetworkMutable() noexcept {
assert(bestNetwork_ != nullptr);
return bestNetwork_;
}
Expand All @@ -192,17 +210,22 @@ inline void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::evolve() {
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
inline std::size_t EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getPopulationSize() const noexcept {
inline std::size_t
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getPopulationSize()
const noexcept {
return population_.getPopulationSize();
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
inline std::size_t EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getCounterGeneration() const noexcept {
inline std::size_t
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::getCounterGeneration()
const noexcept {
return counterGeneration_;
}

template <int NumInput, int NumOutput, bool Bias, typename ParamConfig>
inline void EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::computeNetworks() {
inline void
EvolutionNet<NumInput, NumOutput, Bias, ParamConfig>::computeNetworks() {
const std::size_t popSize = population_.getPopulationSize();
assert(networks_.size() == popSize);

Expand Down
39 changes: 28 additions & 11 deletions include/EvolutionNet/FlatMap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ class FlatMap {
inline Value& nthValue(const std::size_t nth) noexcept;

/*! \return the vector containing all values.
* \note The order of values is not sorted! They are sorted by order of insertion.
* \note The order of values is not sorted! They are sorted by order of
* insertion.
*/
inline const std::vector<Value>& valuesVector() const noexcept;
inline std::vector<Value>& valuesVector() noexcept;
Expand All @@ -77,7 +78,8 @@ class FlatMap {

template <typename Key, typename Value>
template <typename... Args>
inline Value* FlatMap<Key, Value>::insert(const Key key, Args&&... args) noexcept {
inline Value* FlatMap<Key, Value>::insert(const Key key,
Args&&... args) noexcept {
assert(this->operator[](key) == nullptr);

keys_.emplace_back(key, values_.size());
Expand All @@ -86,8 +88,10 @@ inline Value* FlatMap<Key, Value>::insert(const Key key, Args&&... args) noexcep
KeyIndex* beg = keys_.data();
KeyIndex* end = beg + keys_.size();
KeyIndex* last = end - 1;
KeyIndex* bound =
std::lower_bound(beg, last, key, [](const KeyIndex& el, const Key& key) noexcept { return el.first < key; });
KeyIndex* bound = std::lower_bound(
beg, last, key, [](const KeyIndex& el, const Key& key) noexcept {
return el.first < key;
});
std::rotate(bound, last, end);

assert(std::is_sorted(keys_.cbegin(), keys_.cend()));
Expand All @@ -99,18 +103,29 @@ inline Value* FlatMap<Key, Value>::insert(const Key key, Args&&... args) noexcep

template <typename Key, typename Value>
inline Value* FlatMap<Key, Value>::operator[](const Key key) noexcept {
const auto finder = std::lower_bound(
keys_.begin(), keys_.end(), key, [](const KeyIndex& el, const Key& key) noexcept { return el.first < key; });
const auto finder =
std::lower_bound(keys_.begin(),
keys_.end(),
key,
[](const KeyIndex& el, const Key& key) noexcept {
return el.first < key;
});
if (finder != keys_.end() && finder->first == key) {
return &(values_[finder->second]);
}
return nullptr;
}

template <typename Key, typename Value>
inline const Value* FlatMap<Key, Value>::operator[](const Key key) const noexcept {
const auto finder = std::lower_bound(
keys_.cbegin(), keys_.cend(), key, [](const KeyIndex& el, const Key& key) noexcept { return el.first < key; });
inline const Value* FlatMap<Key, Value>::operator[](
const Key key) const noexcept {
const auto finder =
std::lower_bound(keys_.cbegin(),
keys_.cend(),
key,
[](const KeyIndex& el, const Key& key) noexcept {
return el.first < key;
});
if (finder != keys_.cend() && finder->first == key) {
return &(values_[finder->second]);
}
Expand Down Expand Up @@ -141,7 +156,8 @@ inline Key FlatMap<Key, Value>::nthKey(const std::size_t nth) const noexcept {
}

template <typename Key, typename Value>
inline const Value& FlatMap<Key, Value>::nthValue(const std::size_t nth) const noexcept {
inline const Value& FlatMap<Key, Value>::nthValue(
const std::size_t nth) const noexcept {
assert(nth < keys_.size());
assert(keys_.size() == values_.size());
assert(keys_[nth].second < values_.size());
Expand All @@ -157,7 +173,8 @@ inline Value& FlatMap<Key, Value>::nthValue(const std::size_t nth) noexcept {
}

template <typename Key, typename Value>
inline const std::vector<Value>& FlatMap<Key, Value>::valuesVector() const noexcept {
inline const std::vector<Value>& FlatMap<Key, Value>::valuesVector()
const noexcept {
return values_;
}

Expand Down
5 changes: 3 additions & 2 deletions include/EvolutionNet/FlatSet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ class FlatSet {
inline bool empty() const noexcept;

/*! \brief Insert a new element in the container.
* The new element will be inserted in a "sorted way" (the container will keep elements sorted)
* \note The element must not already exist in the container. Otherwise undefined behavior!
* The new element will be inserted in a "sorted way" (the container will
* keep elements sorted) \note The element must not already exist in the
* container. Otherwise undefined behavior!
*/
inline void insert(T value);

Expand Down
Loading