From a81f9401a8caba11913dcdf36c31fe59a1328a71 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Tue, 28 Jan 2020 22:16:17 -0500 Subject: [PATCH 01/42] Updated notes for control block in DataMap. --- source/data/DataMap.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/data/DataMap.h b/source/data/DataMap.h index 7318b0f93a..0fcf2162e9 100644 --- a/source/data/DataMap.h +++ b/source/data/DataMap.h @@ -38,13 +38,15 @@ * 1. The memory is a POINTER not an instance. This would allow entries to behave like * references, potentially eliminating the need to copy larger data structures into the * memory image. - * 2. The memory is a LOG of values, not a single value. This allows for quick identification + * 2. The entry has a non-trivial (or user-provided) COPY/MOVE CONSTRUCTOR or DESTRUCTOR + * 3. The entry has a function to call for a Get instead of a value in memory. The space + * reserved is used for the function pointer (incompatible with bit 1...) + * 4. The entry has a function to call when it is set. Effectively this can implement SIGNAL + * monitoring it that should be notified whenever it changes. The signal itself would need + * to be stored elsewhere (presumably in the memory image, but possibly in the layout.) + * 5. The memory is a LOG of values, not a single value. This allows for quick identification * of when something special needs to be done. - * 3. The entry has a SIGNAL monitoring it that should be notified whenever it changes. The - * signal itself would need to be stored elsewhere (presumably in the memory image, but - * possibly in the layout.) - * 4. The entry has a non-trivial (or user-provided) COPY/MOVE CONSTRUCTOR or DESTRUCTOR - * 5-8. Limited type information (16 types that can be handled more effectively?) + * 6-8. Limited type information (8 types that can be handled more effectively?) * * - We should be able to keep a series of values, not just a single one. This can be done with * a series of new functions: From e0cb3a70c29c4f078c580db83594685d2fe74d35 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 3 Feb 2020 23:07:24 -0500 Subject: [PATCH 02/42] Added a to_quoted_list function to take a set of strings, quote them, and list in English. --- source/tools/string_utils.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/tools/string_utils.h b/source/tools/string_utils.h index 46e250a5c0..c61f602766 100644 --- a/source/tools/string_utils.h +++ b/source/tools/string_utils.h @@ -910,6 +910,13 @@ namespace emp { return to_string(open_quote, str, close_quote); }); } + + /// Take a vector of strings, put them in quotes, and then transform it into an English list. + static inline std::string to_quoted_list(const string_vec_t & in_strings, + const std::string quote="'") { + return to_english_list(quote_strings(in_strings, quote)); + } + } #endif From dd12c6b9b7575a7a5b4cb4edcb82b57604fbc63d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 11 Feb 2020 15:18:48 -0500 Subject: [PATCH 03/42] Test GetFilename --- tests/test_data.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_data.cc b/tests/test_data.cc index 07c06a8b1b..f9ef3992fe 100644 --- a/tests/test_data.cc +++ b/tests/test_data.cc @@ -342,6 +342,8 @@ TEST_CASE("Test DataFile", "[data]") { emp::DataFile dfile("test_file.dat"); + REQUIRE(dfile.GetFilename() == "test_file.dat"); + emp::DataMonitor data_fracs; emp::DataMonitor data_squares; emp::DataMonitor data_cubes; From 7deae9c5a9ba2c4ac446d3894abff176f65f6e97 Mon Sep 17 00:00:00 2001 From: Emily Dolson Date: Thu, 13 Feb 2020 14:51:40 -0500 Subject: [PATCH 04/42] Make check for synchronous world more robust --- source/Evolve/World.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Evolve/World.h b/source/Evolve/World.h index c169faee6f..c8cf468e5a 100644 --- a/source/Evolve/World.h +++ b/source/Evolve/World.h @@ -1191,7 +1191,7 @@ namespace emp { // 2. If synchronous generations (i.e, pops[1] is not empty), move next population into // place as the current popoulation. - if (pops[1].size()) { + if (IsSynchronous()) { // Trigger signals for orgs in next pop before they are moved into the active pop. for (size_t i = 0; i < pops[1].size(); i++) { if (!pops[1][i]) continue; From 79aeb6ce5ea0e90738ff35a061fe916653d20a78 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 16 Feb 2020 22:37:34 -0500 Subject: [PATCH 05/42] Added Concat() and Append() to vector_utils.h --- source/tools/vector_utils.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/tools/vector_utils.h b/source/tools/vector_utils.h index 051ed70ac4..a0daf1ad07 100644 --- a/source/tools/vector_utils.h +++ b/source/tools/vector_utils.h @@ -18,6 +18,29 @@ namespace emp { + /// Base case for Append; we just have a single vector with nothing to append. + template + emp::vector & Append(emp::vector & base) { + return base; + } + + /// Append one or more vectors on to the end of an existing vector. + template + emp::vector & Append(emp::vector & base, const V1 & v1, const Vs &... vs) { + base.insert(base.end(), v1.begin(), v1.end()); + Append(base, vs...); + return base; + } + + + /// Concatonate two or more vectors together, creating a new vector. + template + emp::vector Concat(const emp::vector & v1, const Vs &... vs) { + emp::vector out_v = v1; + Append(out_v, vs...); + return out_v; + } + /// Return the first position of a value in a vector (or -1 if none exists) template int FindValue(const emp::vector & v, const T & val, size_t start_pos=0) { From 18db9a265186f6218fa323ada4570d0609c347f6 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 16 Feb 2020 22:37:54 -0500 Subject: [PATCH 06/42] Added example of usage of Concat. --- examples/tools/vector_utils.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/tools/vector_utils.cc b/examples/tools/vector_utils.cc index bde674dd5f..ef9a837563 100644 --- a/examples/tools/vector_utils.cc +++ b/examples/tools/vector_utils.cc @@ -1,5 +1,5 @@ // This file is part of Empirical, https://github.com/devosoft/Empirical -// Copyright (C) Michigan State University, 2017. +// Copyright (C) Michigan State University, 2017-2020. // Released under the MIT Software license; see doc/LICENSE // // @@ -11,6 +11,18 @@ int main() { + emp::vector v1 = { "a", "b", "cde" }; + emp::vector v2 = { "f", "g", "hij" }; + emp::vector v3 = { "klm", "n", "op" }; + emp::vector v4 = { "qrstuv", "wxy", "z" }; + + auto all = emp::Concat(v1, v2, v3, v4); + + std::cout << "Words: "; + for (const auto & w : all) { + std::cout << w << " "; + } + std::cout << std::endl; emp::vector v = { 14, 13, 1, 2, 3, 4, 22, 5, 6, 7, 8, 9, 10, 12 }; From c39baf639cf34368d2cb4e6ca85291fe847ee923 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Wed, 19 Feb 2020 00:40:37 -0500 Subject: [PATCH 07/42] Marked slugify() as inline to prevent unused function warning. --- source/tools/string_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tools/string_utils.h b/source/tools/string_utils.h index c61f602766..43bc73ea6c 100644 --- a/source/tools/string_utils.h +++ b/source/tools/string_utils.h @@ -579,7 +579,7 @@ namespace emp { } /// Make a string safe(r) - static std::string slugify(const std::string & in_string) { + static inline std::string slugify(const std::string & in_string) { //TODO handle complicated unicode strings std::string res = to_lower(in_string); remove_punctuation(res); From 1255d7796337f46f510a94b64e99cef5959893f5 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Wed, 19 Feb 2020 00:41:17 -0500 Subject: [PATCH 08/42] Setup vector Append() to accept either individual elements or containers of elements. --- source/tools/vector_utils.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/source/tools/vector_utils.h b/source/tools/vector_utils.h index a0daf1ad07..66fb9bdc21 100644 --- a/source/tools/vector_utils.h +++ b/source/tools/vector_utils.h @@ -1,7 +1,7 @@ /** * @note This file is part of Empirical, https://github.com/devosoft/Empirical * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md - * @date 2017-2018 + * @date 2017-2020. * * @file vector_utils.h * @brief A set of simple functions to manipulate emp::vector @@ -27,9 +27,18 @@ namespace emp { /// Append one or more vectors on to the end of an existing vector. template emp::vector & Append(emp::vector & base, const V1 & v1, const Vs &... vs) { - base.insert(base.end(), v1.begin(), v1.end()); - Append(base, vs...); - return base; + // If the next entry is a single element, push it on the back. + if constexpr (std::is_convertible()) { + base.push_back(v1); + } + + // Otherwise assume we have a container and append all of it. + else { + base.insert(base.end(), v1.begin(), v1.end()); + } + + // Recurse. + return Append(base, vs...); } From 1b66a947719416b69928f6d7cfd39b448acba3e7 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 14:09:04 -0500 Subject: [PATCH 09/42] Starting to build a config tool to cycle through all combinations of settings. --- source/config/SettingCombos.h | 97 +++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 source/config/SettingCombos.h diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h new file mode 100644 index 0000000000..d7c665c181 --- /dev/null +++ b/source/config/SettingCombos.h @@ -0,0 +1,97 @@ +/** + * @note This file is part of Empirical, https://github.com/devosoft/Empirical + * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md + * @date 2020 + * + * @file SettingCombos.h + * @brief A tool for exploring all parameter combinations + * @note Status: PLANNING + */ + +#ifndef EMP_SETTING_COMBOS_H +#define EMP_SETTING_COMBOS_H + +#include +#include +#include + +#include "base/Ptr.h" +#include "base/vector.h" + +namespace emp { + + class SettingCombos { + private: + struct SettingBase { + virtual size_t GetSize() const = 0; ///< How many values are available? + virtual std::string AsString() const = 0; ///< All values, as a single string. + virtual std::string AsString(size_t) const = 0; ///< A specified value as a string. + }; + + template + struct SettingInfo : public SettingBase { + emp::vector values; + + size_t GetSize() const override { return values.size(); } + std::string AsString() const override { + std::stringstream ss; + for (size_t i; i < values.size(); i++) { + if (i) ss << ','; + ss << value[i]; + } + return ss.str(); + } + std::string AsString(size_t id) const override { + return emp::to_string(values[id]); + } + }; + + using set_ptr_t = emp::Ptr; + + emp::vector settings; ///< Order to be varied. + std::unordered_map setting_map; ///< Settings by name. + + emp::vector cur_combo; ///< Which settings are we currently using? + + public: + SettingCombos() = default; + + void Reset() { for (size_t & x : cur_combo) x = 0; } + + template + void AddSetting(const std::string & name) { + emp_assert(!emp::Has(setting_map, name)); + set_ptr_t new_ptr = emp::NewPtr>; + settings.push_back(new_ptr); + setting_map[name] = new_ptr; + cur_combo.push_back(0); + } + + /// Determine how many unique combinations there currently are. + size_t CountCombos() { + size_t result = 1; + for (set_ptr_t ptr : settings) result *= ptr; + return result; + } + + /// Set the next combination of settings to be active. Return true if successful + /// or false if we ran through all combinations and reset. + bool NextCombo() { + for (size_t i = 0; i < cur_combo.size(); i++) { + cur_combo[i]++; + + // Check if this new combo is valid. + if (cur_combo[i] < settings[i]->GetSize()) return true; + + // Since it's not, prepare to move on to the next one. + cur_combo[i] = 0; + } + + // No valid combo found. + return false; + } + }; + +} + +#endif From 279aa8ce58c12136dcf830fc7d63720804ac8bc6 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 21:50:15 -0500 Subject: [PATCH 10/42] Added ability to add values to the SettingCombos. --- source/config/SettingCombos.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index d7c665c181..af596b22b6 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -67,6 +67,21 @@ namespace emp { cur_combo.push_back(0); } + template + void AddValue(const std::string & name, T && val) { + emp_assert(emp::Has(setting_map, name)); + emp::Ptr> ptr = setting_map[name].Cast>(); + ptr->values.emplace_back(std::forward(val)); + } + + template + void AddValues(const std::string & name, T1 && val1, Ts &&... vals) { + emp_assert(emp::Has(setting_map, name)); + emp::Ptr> ptr = setting_map[name].Cast>(); + ptr->values.emplace_back(std::forward(val1)); + ptr->values.emplace_back(std::forward(vals))...; + } + /// Determine how many unique combinations there currently are. size_t CountCombos() { size_t result = 1; From 6484700891d5f77ac1f7e7a2a349fdea4824f1e3 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 22:00:52 -0500 Subject: [PATCH 11/42] Added a GetValue() to SettingCombos. --- source/config/SettingCombos.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index af596b22b6..762cd12c4a 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -23,6 +23,8 @@ namespace emp { class SettingCombos { private: struct SettingBase { + size_t id; ///< Unique ID/position for this setting. + virtual size_t GetSize() const = 0; ///< How many values are available? virtual std::string AsString() const = 0; ///< All values, as a single string. virtual std::string AsString(size_t) const = 0; ///< A specified value as a string. @@ -58,10 +60,19 @@ namespace emp { void Reset() { for (size_t & x : cur_combo) x = 0; } + template + const T & GetValue(const std::string & name) const { + emp_assert(emp::Has(setting_map, name)); + emp::Ptr> ptr = setting_map[name].Cast>(); + size_t id = cur_combos[ptr->GetID()]; + return ptr->values[id]; + } + template void AddSetting(const std::string & name) { emp_assert(!emp::Has(setting_map, name)); set_ptr_t new_ptr = emp::NewPtr>; + new_ptr->id = settings.size(); settings.push_back(new_ptr); setting_map[name] = new_ptr; cur_combo.push_back(0); From 416b05a285b088c0d6c861877602403e21283991 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 22:05:19 -0500 Subject: [PATCH 12/42] Added a destructor to SettingCombos. --- source/config/SettingCombos.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 762cd12c4a..899552037a 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -58,6 +58,10 @@ namespace emp { public: SettingCombos() = default; + ~SettingCombos() { + for (auto ptr : settings) ptr.Delete(); + } + void Reset() { for (size_t & x : cur_combo) x = 0; } template From 018c1264139a272d115aa65f87479f247c04a37a Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 22:29:28 -0500 Subject: [PATCH 13/42] Lots of fixes to make SettingCombos.h compile. --- source/config/SettingCombos.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 899552037a..8063cb1c07 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -17,6 +17,8 @@ #include "base/Ptr.h" #include "base/vector.h" +#include "tools/string_utils.h" +#include "tools/vector_utils.h" namespace emp { @@ -39,7 +41,7 @@ namespace emp { std::stringstream ss; for (size_t i; i < values.size(); i++) { if (i) ss << ','; - ss << value[i]; + ss << values[i]; } return ss.str(); } @@ -51,7 +53,7 @@ namespace emp { using set_ptr_t = emp::Ptr; emp::vector settings; ///< Order to be varied. - std::unordered_map setting_map; ///< Settings by name. + std::unordered_map setting_map; ///< Settings by name. emp::vector cur_combo; ///< Which settings are we currently using? @@ -67,8 +69,9 @@ namespace emp { template const T & GetValue(const std::string & name) const { emp_assert(emp::Has(setting_map, name)); - emp::Ptr> ptr = setting_map[name].Cast>(); - size_t id = cur_combos[ptr->GetID()]; + emp::Ptr base_ptr = setting_map.find(name); + emp::Ptr> ptr = base_ptr.Cast>(); + size_t id = cur_combo[ptr->GetID()]; return ptr->values[id]; } @@ -85,16 +88,15 @@ namespace emp { template void AddValue(const std::string & name, T && val) { emp_assert(emp::Has(setting_map, name)); - emp::Ptr> ptr = setting_map[name].Cast>(); + emp::Ptr> ptr = setting_map[name].DynamicCast>(); ptr->values.emplace_back(std::forward(val)); } template - void AddValues(const std::string & name, T1 && val1, Ts &&... vals) { + void SetValues(const std::string & name, T1 && val1, Ts &&... vals) { emp_assert(emp::Has(setting_map, name)); - emp::Ptr> ptr = setting_map[name].Cast>(); - ptr->values.emplace_back(std::forward(val1)); - ptr->values.emplace_back(std::forward(vals))...; + emp::Ptr> ptr = setting_map[name].DynamicCast>(); + emp::Append(ptr->values, std::forward(val1), std::forward(vals)...); } /// Determine how many unique combinations there currently are. From ea550309f1224f54a10b8cc374b6edad36d8f565 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 23:35:27 -0500 Subject: [PATCH 14/42] More cleanup on SettingCombos.h --- source/config/SettingCombos.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 8063cb1c07..20f8d54f0d 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -27,6 +27,7 @@ namespace emp { struct SettingBase { size_t id; ///< Unique ID/position for this setting. + virtual ~SettingBase() { } virtual size_t GetSize() const = 0; ///< How many values are available? virtual std::string AsString() const = 0; ///< All values, as a single string. virtual std::string AsString(size_t) const = 0; ///< A specified value as a string. @@ -39,7 +40,7 @@ namespace emp { size_t GetSize() const override { return values.size(); } std::string AsString() const override { std::stringstream ss; - for (size_t i; i < values.size(); i++) { + for (size_t i=0; i < values.size(); i++) { if (i) ss << ','; ss << values[i]; } @@ -76,13 +77,14 @@ namespace emp { } template - void AddSetting(const std::string & name) { + emp::vector & AddSetting(const std::string & name) { emp_assert(!emp::Has(setting_map, name)); - set_ptr_t new_ptr = emp::NewPtr>; + emp::Ptr> new_ptr = emp::NewPtr>(); new_ptr->id = settings.size(); settings.push_back(new_ptr); setting_map[name] = new_ptr; cur_combo.push_back(0); + return new_ptr->values; } template From a3f867c3ebeedce00e0a84421ff10e6f75bf7641 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 23:36:26 -0500 Subject: [PATCH 15/42] Initial example file for SettingCombos. --- examples/config/SettingCombos.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 examples/config/SettingCombos.cc diff --git a/examples/config/SettingCombos.cc b/examples/config/SettingCombos.cc new file mode 100644 index 0000000000..990edb04d2 --- /dev/null +++ b/examples/config/SettingCombos.cc @@ -0,0 +1,18 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE +// +// +// Some examples code for using emp::SettingCombos + +#include +#include "config/SettingCombos.h" + +#define PRINT(X) std::cout << #X " = " << X << std::endl + +int main() +{ + emp::SettingCombos config_set; + + config_set.AddSetting("int1") = { 1, 2, 3, 4 }; +} From d1af57f5b0e2ab3a1ea0194c6bac47a168bcadc7 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 23:37:15 -0500 Subject: [PATCH 16/42] Added SettingCombos example to Makefile. --- examples/config/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/config/Makefile b/examples/config/Makefile index 24be135c5c..987bd48127 100644 --- a/examples/config/Makefile +++ b/examples/config/Makefile @@ -19,7 +19,7 @@ CFLAGS_web_debug := $(CFLAGS_all) $(OFLAGS_web_debug) --js-library ../../web/lib CFLAGS_web_opt := $(CFLAGS_all) $(OFLAGS_web_opt) --js-library ../../web/library_emp.js -s EXPORTED_FUNCTIONS="['_main', '_empCppCallback']" -s NO_EXIT_RUNTIME=1 #CFLAGS_web := $(CFLAGS_all) $(OFLAGS_web) --js-library ../../web/library_emp.js -s EXPORTED_FUNCTIONS="['_main', '_empCppCallback']" -s DISABLE_EXCEPTION_CATCHING=1 -s NO_EXIT_RUNTIME=1 -TARGETS := config namespaces +TARGETS := config namespaces SettingCombos default: native From e39dc66cb9953b6c4e07391403a4ae7cbd5a9a1c Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 23:47:57 -0500 Subject: [PATCH 17/42] Added SettingCombos::CurString() for getting current combination. --- source/config/SettingCombos.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 20f8d54f0d..d0a641a2ac 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -110,7 +110,7 @@ namespace emp { /// Set the next combination of settings to be active. Return true if successful /// or false if we ran through all combinations and reset. - bool NextCombo() { + bool Next() { for (size_t i = 0; i < cur_combo.size(); i++) { cur_combo[i]++; @@ -124,6 +124,16 @@ namespace emp { // No valid combo found. return false; } + + std::string CurString() const { + std::string out_str; + for (size_t i = 0; i < cur_combo.size(); i++) { + if (i) out_str += ","; + out_str += settings[i]->AsString(cur_combo[i]); + } + return out_str; + } + }; } From 0f43283a56733a463861b4156b4c11270c9a4195 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 20 Feb 2020 23:48:18 -0500 Subject: [PATCH 18/42] Fleshed out SettingCombos example to actually use it. --- examples/config/SettingCombos.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/config/SettingCombos.cc b/examples/config/SettingCombos.cc index 990edb04d2..131266c363 100644 --- a/examples/config/SettingCombos.cc +++ b/examples/config/SettingCombos.cc @@ -15,4 +15,11 @@ int main() emp::SettingCombos config_set; config_set.AddSetting("int1") = { 1, 2, 3, 4 }; + config_set.AddSetting("string") = { "a", "b", "cde" }; + config_set.AddSetting("int2") = { 5 }; + config_set.AddSetting("double") = { 1.1, 2.2 }; + + do { + std::cout << config_set.CurString() << std::endl; + } while (config_set.Next()); } From 9bbe8209493a0538248b330367feec9abe807615 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Fri, 21 Feb 2020 09:23:16 -0500 Subject: [PATCH 19/42] Added SettingCombos::Values() to directly access value vector. --- source/config/SettingCombos.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index d0a641a2ac..2f0b9f5e58 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -87,6 +87,13 @@ namespace emp { return new_ptr->values; } + template + emp::vector & Values(const std::string & name) { + emp_assert(emp::Has(setting_map, name)); + emp::Ptr> ptr = setting_map[name].DynamicCast>(); + return ptr->values; + } + template void AddValue(const std::string & name, T && val) { emp_assert(emp::Has(setting_map, name)); From be7c4a4b28d40948e89991a83e16ae6579042839 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sat, 22 Feb 2020 10:19:59 -0500 Subject: [PATCH 20/42] Added documentation for all functions. --- source/config/SettingCombos.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 2f0b9f5e58..79dbb8f1a9 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -5,7 +5,7 @@ * * @file SettingCombos.h * @brief A tool for exploring all parameter combinations - * @note Status: PLANNING + * @note Status: ALPHA */ #ifndef EMP_SETTING_COMBOS_H @@ -22,6 +22,9 @@ namespace emp { + /// Class to take a set of value for each "setting" and then step through all combinations of + /// those values for a factorial analysis. + class SettingCombos { private: struct SettingBase { @@ -65,8 +68,10 @@ namespace emp { for (auto ptr : settings) ptr.Delete(); } + /// Start over stepping through all combinations of parameter values. void Reset() { for (size_t & x : cur_combo) x = 0; } + /// Get the current value of a specified setting. template const T & GetValue(const std::string & name) const { emp_assert(emp::Has(setting_map, name)); @@ -76,6 +81,11 @@ namespace emp { return ptr->values[id]; } + /// Add a new setting of a specified type. Returns the (initially empty) vector of values + /// to allow easy setting. + /// Example: + /// combos.AddSetting("pop_size") = {100,200,400,800}; + template emp::vector & AddSetting(const std::string & name) { emp_assert(!emp::Has(setting_map, name)); @@ -87,6 +97,7 @@ namespace emp { return new_ptr->values; } + /// Access ALL values for a specified setting, to be modified freely. template emp::vector & Values(const std::string & name) { emp_assert(emp::Has(setting_map, name)); @@ -94,6 +105,7 @@ namespace emp { return ptr->values; } + /// Add a single new value to the specified setting. template void AddValue(const std::string & name, T && val) { emp_assert(emp::Has(setting_map, name)); @@ -101,6 +113,7 @@ namespace emp { ptr->values.emplace_back(std::forward(val)); } + /// Set all values for the specified setting. template void SetValues(const std::string & name, T1 && val1, Ts &&... vals) { emp_assert(emp::Has(setting_map, name)); @@ -132,6 +145,7 @@ namespace emp { return false; } + /// Convert all of the current values into a comma-separated string. std::string CurString() const { std::string out_str; for (size_t i = 0; i < cur_combo.size(); i++) { From 3e1a876a83ba092fcedcecebe22f527326e26c70 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 22 Feb 2020 16:43:10 -0500 Subject: [PATCH 21/42] Implmeent and test GetNumBytes accessor --- source/tools/BitSet.h | 3 +++ tests/test_tools.cc | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/source/tools/BitSet.h b/source/tools/BitSet.h index 6aa462f282..0e39f9cff8 100644 --- a/source/tools/BitSet.h +++ b/source/tools/BitSet.h @@ -526,6 +526,9 @@ namespace emp { /// How many bits are in this BitSet? constexpr static size_t GetSize() { return NUM_BITS; } + /// How many bytes are in this BitSet? + constexpr static size_t GetNumBytes() { return NUM_BYTES; } + /// Retrieve the bit as a specified index. bool Get(size_t index) const { emp_assert(index >= 0 && index < NUM_BITS); diff --git a/tests/test_tools.cc b/tests/test_tools.cc index 167e3d5984..72bdc5b173 100644 --- a/tests/test_tools.cc +++ b/tests/test_tools.cc @@ -410,6 +410,27 @@ template class emp::BitSet<5>; TEST_CASE("Test BitSet", "[tools]") { + // test BitSet GetSize, GetNumBytes + { + REQUIRE(emp::BitSet<2>{}.GetSize() == 2); + REQUIRE(emp::BitSet<2>{}.GetNumBytes() == 1); + + REQUIRE(emp::BitSet<7>{}.GetSize() == 7); + REQUIRE(emp::BitSet<7>{}.GetNumBytes() == 1); + + REQUIRE(emp::BitSet<8>{}.GetSize() == 8); + REQUIRE(emp::BitSet<8>{}.GetNumBytes() == 1); + + REQUIRE(emp::BitSet<9>{}.GetSize() == 9); + REQUIRE(emp::BitSet<9>{}.GetNumBytes() == 2); + + REQUIRE(emp::BitSet<16>{}.GetSize() == 16); + REQUIRE(emp::BitSet<16>{}.GetNumBytes() == 2); + + REQUIRE(emp::BitSet<24>{}.GetSize() == 24); + REQUIRE(emp::BitSet<24>{}.GetNumBytes() == 3); + } + // test BitSet reverse { From cc7e1a01823f0fda8080c3c07a1f0a82b4e87e7e Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 22 Feb 2020 16:43:56 -0500 Subject: [PATCH 22/42] Add a cryptographic hash metric This requires linking with -lcrypto -lssl to *use* the metric, but everything should compile fine without linking when the metric isn't actually instantiated/used. --- source/tools/matchbin_metrics.h | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/source/tools/matchbin_metrics.h b/source/tools/matchbin_metrics.h index 7427df97bb..91ef52bedc 100644 --- a/source/tools/matchbin_metrics.h +++ b/source/tools/matchbin_metrics.h @@ -26,6 +26,8 @@ #include #include +#include + #include "tools/Binomial.h" #include "../base/assert.h" @@ -106,6 +108,53 @@ namespace emp { }; + /// Generate an arbitrary, but consistent, match score between 0 and 1 + template + struct CryptoHashMetric: public BaseMetric, emp::BitSet> { + + using query_t = emp::BitSet; + using tag_t = emp::BitSet; + + size_t dim() const override { return 1; } + + size_t width() const override { return Width; } + + std::string name() const override { + return emp::to_string(Width) + "-bit " + base(); + } + + std::string base() const override { return "Hash Metric"; } + + // adapted from https://www.uncg.edu/cmp/faculty/srtate/580.f11/sha1examples.php + double operator()(const query_t& a, const tag_t& b) const override { + + std::array data; + + size_t i = 0; + for (size_t j = 0; j < a.GetNumBytes(); ++j) data[i++] = a.GetByte(j); + for (size_t j = 0; j < b.GetNumBytes(); ++j) data[i++] = b.GetByte(j); + + SHA_CTX shactx; + std::array digest; + + SHA1_Init(&shactx); + SHA1_Update(&shactx, data.data(), data.size()); + SHA1_Final(digest.data(), &shactx); + + const std::string hashme{ + reinterpret_cast(digest.data()), + digest.size() + }; + + return ( + static_cast(std::hash{}(hashme)) + / std::numeric_limits::max() + ); + + } + + }; + /// Metric gives the absolute difference between two integers struct AbsDiffMetric : public BaseMetric { From 7caeaebee2e95133d332640311e91114604fe6d9 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 22 Feb 2020 16:52:30 -0500 Subject: [PATCH 23/42] Document compile-time linking requirement --- source/tools/matchbin_metrics.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/tools/matchbin_metrics.h b/source/tools/matchbin_metrics.h index 91ef52bedc..68a2c42799 100644 --- a/source/tools/matchbin_metrics.h +++ b/source/tools/matchbin_metrics.h @@ -109,6 +109,7 @@ namespace emp { }; /// Generate an arbitrary, but consistent, match score between 0 and 1 + /// Be sure to link against -lcrypto and -lssl template struct CryptoHashMetric: public BaseMetric, emp::BitSet> { From e5356fe096ff3c8bf85deedf77c1d19704cfbb01 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 22 Feb 2020 17:01:21 -0500 Subject: [PATCH 24/42] Stylistic tweak --- source/tools/matchbin_metrics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tools/matchbin_metrics.h b/source/tools/matchbin_metrics.h index 68a2c42799..9918965884 100644 --- a/source/tools/matchbin_metrics.h +++ b/source/tools/matchbin_metrics.h @@ -129,7 +129,7 @@ namespace emp { // adapted from https://www.uncg.edu/cmp/faculty/srtate/580.f11/sha1examples.php double operator()(const query_t& a, const tag_t& b) const override { - std::array data; + std::array data; size_t i = 0; for (size_t j = 0; j < a.GetNumBytes(); ++j) data[i++] = a.GetByte(j); From 147b52fc7e648a30365783f114ba88ba905b5fc6 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sat, 22 Feb 2020 23:55:16 -0500 Subject: [PATCH 25/42] Added argument processing to SettingCombos. --- source/config/SettingCombos.h | 72 +++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 79dbb8f1a9..81f978f1dc 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -15,10 +15,10 @@ #include #include -#include "base/Ptr.h" -#include "base/vector.h" -#include "tools/string_utils.h" -#include "tools/vector_utils.h" +#include "../base/Ptr.h" +#include "../base/vector.h" +#include "../tools/string_utils.h" +#include "../tools/vector_utils.h" namespace emp { @@ -29,17 +29,32 @@ namespace emp { private: struct SettingBase { size_t id; ///< Unique ID/position for this setting. + std::string name; + std::string desc; + std::string flag; + std::string option; + SettingBase(const std::string & _name, const std::string & _desc, const std::string & _flag) + : name(_name), desc(_desc), flag(_flag), option(emp::to_string("--",_name)) { } virtual ~SettingBase() { } - virtual size_t GetSize() const = 0; ///< How many values are available? - virtual std::string AsString() const = 0; ///< All values, as a single string. - virtual std::string AsString(size_t) const = 0; ///< A specified value as a string. + + virtual size_t GetSize() const = 0; ///< How many values are available? + virtual std::string AsString() const = 0; ///< All values, as a single string. + virtual std::string AsString(size_t) const = 0; ///< A specified value as a string. + virtual void FromString(const std::string &) = 0; ///< Convert string to range of settings. + + bool IsMatch(const std::string & test_option) const { + return test_option == flag || test_option == option; + } }; template struct SettingInfo : public SettingBase { emp::vector values; + SettingInfo(const std::string & _name, const std::string & _desc, const std::string & _flag) + : SettingBase(_name, _desc, _flag) { } + size_t GetSize() const override { return values.size(); } std::string AsString() const override { std::stringstream ss; @@ -52,6 +67,10 @@ namespace emp { std::string AsString(size_t id) const override { return emp::to_string(values[id]); } + + void FromString(const std::string & input) override { + values = emp::from_strings(emp::slice(input, ',')); + } }; using set_ptr_t = emp::Ptr; @@ -75,7 +94,7 @@ namespace emp { template const T & GetValue(const std::string & name) const { emp_assert(emp::Has(setting_map, name)); - emp::Ptr base_ptr = setting_map.find(name); + emp::Ptr base_ptr = setting_map.find(name)->second; emp::Ptr> ptr = base_ptr.Cast>(); size_t id = cur_combo[ptr->GetID()]; return ptr->values[id]; @@ -85,11 +104,13 @@ namespace emp { /// to allow easy setting. /// Example: /// combos.AddSetting("pop_size") = {100,200,400,800}; - + template - emp::vector & AddSetting(const std::string & name) { + emp::vector & AddSetting(const std::string & name, + const std::string & desc="", + const std::string & option_flag="") { emp_assert(!emp::Has(setting_map, name)); - emp::Ptr> new_ptr = emp::NewPtr>(); + emp::Ptr> new_ptr = emp::NewPtr>(name, desc, option_flag); new_ptr->id = settings.size(); settings.push_back(new_ptr); setting_map[name] = new_ptr; @@ -155,6 +176,35 @@ namespace emp { return out_str; } + /// Scan through all settings for a match option and return ID. + size_t FindOptionMatch(const std::string & option_name) { + for (const auto & setting : settings) { + if (setting->IsMatch(option_name)) return setting->id; + } + return (size_t) -1; + } + + /// Take an input set of config options, process them, and return set of unpressed ones. + emp::vector ProcessOptions(const emp::vector & args) { + emp::vector out_args; + + for (size_t i = 0; i < args.size(); i++) { + size_t id = FindOptionMatch(args[i]); + if (id < settings.size()) { + if (++i >= args.size()) { + std::cout << "ERROR: Must provide args to use!\n"; + // @CAO Need to signal error... + return args; + } + settings[id]->FromString(args[i]); + } + + // Otherwise this argument will go unused; send it back. + else out_args.push_back(args[i]); + } + + return out_args; + } }; } From 267d3267269c98208feb34b219c2926d2cb2e342 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 00:39:05 -0500 Subject: [PATCH 26/42] Added a GetHeaders() function to SettingCombos. --- source/config/SettingCombos.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 81f978f1dc..778864dfdc 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -166,6 +166,16 @@ namespace emp { return false; } + /// Get the set of headers used for the CSV file. + std::string GetHeaders() { + std::string out_string; + for (size_t i = 0; i < settings.size(); i++) { + if (i) out_string += ","; + out_string += settings[i]->name; + } + return out_string; + } + /// Convert all of the current values into a comma-separated string. std::string CurString() const { std::string out_str; From abe26213696a3058131d4c9de0e432bd9a237a5b Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 17:50:30 -0500 Subject: [PATCH 27/42] Added a bool representation that won't trip up vector. --- source/tools/Bool.h | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 source/tools/Bool.h diff --git a/source/tools/Bool.h b/source/tools/Bool.h new file mode 100644 index 0000000000..8f1113a3ce --- /dev/null +++ b/source/tools/Bool.h @@ -0,0 +1,57 @@ +/** + * @note This file is part of Empirical, https://github.com/devosoft/Empirical + * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md + * @date 2020 + * + * @file Bool.h + * @brief A bool representation that doesn't trip up std::vector + * @note Status: ALPHA + * + */ + + +#ifndef EMP_BOOL_H +#define EMP_BOOL_H + +#include + +#include "../base/assert.h" + +namespace emp { + + /// @brief A simple replacement for bool type that doesn't trip up std::vector + + class Bool { + private: + bool value; + + public: + Bool(const Bool & b) : value(b.value) { } + Bool & operator=(bool b) { value = b; return *this; } + + /// Conversion of this proxy to Boolean (as an rvalue) + operator bool() const { return value; } + + /// Compound assignement operators using Bool as lvalue. + Bool & operator &=(bool b) { value &= b; return *this; } + Bool & operator |=(bool b) { value |= b; return *this; } + Bool & operator ^=(bool b) { value ^= b; return *this; } + Bool & operator +=(bool b) { value += b; return *this; } + Bool & operator -=(bool b) { value -= b; return *this; } + Bool & operator *=(bool b) { value *= b; return *this; } + Bool & operator /=(bool b) { emp_assert(b == true); value /= b; return *this; } + }; + +} + +namespace std { + + /// Setup operator<< to work with ostream (must be in std to work) + inline std::ostream & operator<<(std::ostream & out, const emp::Bool & b) { + out << (bool) b; + return out; + } + +} + +#endif From c756eb1ebb8b60856739ef146d214a4549e838a4 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 18:01:32 -0500 Subject: [PATCH 28/42] Cleanup on emp::Bool to reduce warnings + work better with bool and istream. --- source/tools/Bool.h | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/source/tools/Bool.h b/source/tools/Bool.h index 8f1113a3ce..7b6cb4ddf6 100644 --- a/source/tools/Bool.h +++ b/source/tools/Bool.h @@ -26,26 +26,37 @@ namespace emp { bool value; public: - Bool(const Bool & b) : value(b.value) { } + // Bool(const Bool & b) : value(b.value) { } + Bool(bool b=false) : value(b) { } Bool & operator=(bool b) { value = b; return *this; } /// Conversion of this proxy to Boolean (as an rvalue) operator bool() const { return value; } + // Conversion to a bool reference. + bool & Value() { return value; } + bool Value() const { return value; } + /// Compound assignement operators using Bool as lvalue. Bool & operator &=(bool b) { value &= b; return *this; } Bool & operator |=(bool b) { value |= b; return *this; } Bool & operator ^=(bool b) { value ^= b; return *this; } Bool & operator +=(bool b) { value += b; return *this; } Bool & operator -=(bool b) { value -= b; return *this; } - Bool & operator *=(bool b) { value *= b; return *this; } - Bool & operator /=(bool b) { emp_assert(b == true); value /= b; return *this; } + Bool & operator *=(bool b) { value = value && b; return *this; } + Bool & operator /=(bool b) { emp_assert(b == true); return *this; } }; } namespace std { + /// Setup operator<< to work with ostream (must be in std to work) + inline std::istream & operator>>(std::istream & out, const emp::Bool & b) { + out >> b.Value(); + return out; + } + /// Setup operator<< to work with ostream (must be in std to work) inline std::ostream & operator<<(std::ostream & out, const emp::Bool & b) { out << (bool) b; From 040c9bc0b79caa1af68e468823ae501a509a6e22 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 18:02:30 -0500 Subject: [PATCH 29/42] Minor fixes on SettingCombos for GetValue() to work. --- source/config/SettingCombos.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/config/SettingCombos.h b/source/config/SettingCombos.h index 778864dfdc..c0cc542706 100644 --- a/source/config/SettingCombos.h +++ b/source/config/SettingCombos.h @@ -18,6 +18,7 @@ #include "../base/Ptr.h" #include "../base/vector.h" #include "../tools/string_utils.h" +#include "../tools/map_utils.h" #include "../tools/vector_utils.h" namespace emp { @@ -93,10 +94,10 @@ namespace emp { /// Get the current value of a specified setting. template const T & GetValue(const std::string & name) const { - emp_assert(emp::Has(setting_map, name)); + emp_assert(emp::Has(setting_map, name), name); emp::Ptr base_ptr = setting_map.find(name)->second; emp::Ptr> ptr = base_ptr.Cast>(); - size_t id = cur_combo[ptr->GetID()]; + size_t id = cur_combo[ptr->id]; return ptr->values[id]; } From 19dba7c965b8978f75c97a7485c343887776755e Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 21:56:15 -0500 Subject: [PATCH 30/42] Setup Binomial to have a base Distribution class. --- source/tools/Binomial.h | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/source/tools/Binomial.h b/source/tools/Binomial.h index 97e933f4b2..2cfca73873 100644 --- a/source/tools/Binomial.h +++ b/source/tools/Binomial.h @@ -1,7 +1,7 @@ /** * @note This file is part of Empirical, https://github.com/devosoft/Empirical * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md - * @date 2018 + * @date 2018-2020. * * @file Binomial.h * @brief A heavy-weight binomial distribution that can quickly generate random values. @@ -19,11 +19,24 @@ namespace emp { - class Binomial { - private: + class Distribution { + protected: UnorderedIndexMap weights; + + public: + size_t GetSize() const { return weights.GetSize(); } + double GetTotalProb() const { return weights.GetWeight(); } + double operator[](size_t id) const { return weights.GetWeight(id); } + + size_t PickRandom(Random & random) const { + return weights.Index( random.GetDouble(GetTotalProb()) ); + } + }; + + class Binomial : public Distribution { public: - Binomial(double p, size_t N) : weights(N+1) { + Binomial(double p, size_t N) { + weights.Resize(N+1); // p^k * (1-p)^(N-k) * N!/k!(N-k)! // Loop through all of the results and calculate their probabilities. @@ -39,12 +52,6 @@ namespace emp { } } - double GetTotalProb() const { return weights.GetWeight(); } - double operator[](size_t id) const { return weights.GetWeight(id); } - - size_t PickRandom(Random & random) const { - return weights.Index( random.GetDouble(GetTotalProb()) ); - } }; } From 261b3a783f08a607590cfaf9378a4eeb3422becb Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 21:57:42 -0500 Subject: [PATCH 31/42] Scale up Binomial example so that it runs 10 million times. --- examples/tools/Binomial.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/tools/Binomial.cc b/examples/tools/Binomial.cc index c6d9169580..7b4c6739b1 100644 --- a/examples/tools/Binomial.cc +++ b/examples/tools/Binomial.cc @@ -1,5 +1,5 @@ // This file is part of Empirical, https://github.com/devosoft/Empirical -// Copyright (C) Michigan State University, 2018. +// Copyright (C) Michigan State University, 2018-2020. // Released under the MIT Software license; see doc/LICENSE // // @@ -27,4 +27,17 @@ int main() std::cout << " " << bi1000.PickRandom(random); } std::cout << std::endl; + + // And total some more random picks (to take a bit of time). + size_t total = 0; + const size_t test_count = 10000000; + + for (size_t i = 0; i < test_count; i++) { + total += bi1000.PickRandom(random); + } + + std::cout << "Average of " << test_count << " = " + << (((double) total) / (double) test_count) + << std::endl; + } From bbe357533857385817f7d68d020aaee1724c50f2 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 22:58:27 -0500 Subject: [PATCH 32/42] Added a NegativeBinomial distribution. --- source/tools/Binomial.h | 43 +++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/source/tools/Binomial.h b/source/tools/Binomial.h index 2cfca73873..11997dda59 100644 --- a/source/tools/Binomial.h +++ b/source/tools/Binomial.h @@ -3,16 +3,14 @@ * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md * @date 2018-2020. * - * @file Binomial.h - * @brief A heavy-weight binomial distribution that can quickly generate random values. + * @file Distribution.h + * @brief A set of pre-calculated discrete distributions that can quickly generate random values. * @note Status: ALPHA * - * @todo Consider converting this class to a more generic Distribution class - * (though technically it will only work with discrete distributions.) */ -#ifndef EMP_BINOMIAL_H -#define EMP_BINOMIAL_H +#ifndef EMP_DISTRIBUTION_H +#define EMP_DISTRIBUTION_H #include "Random.h" #include "UnorderedIndexMap.h" @@ -33,6 +31,7 @@ namespace emp { } }; + /// How many successes with p probability and N attempts? class Binomial : public Distribution { public: Binomial(double p, size_t N) { @@ -54,6 +53,38 @@ namespace emp { }; + /// How many attemtps to reach N successes, assumming p probability per attempt? + class NegativeBinomial : public Distribution { + public: + NegativeBinomial(double p, size_t N) { + emp_assert(p > 0.0 && p <= 1.0, p); + emp_assert(N > 0, N); + + // Track the probability of each number of successes at each point in time. + emp::vector cur_probs(N, 0.0); + cur_probs[0] = 1.0; // Initially we start with zero successes. + double found_probs = 0.0; // Tally the total probability found so far. + double q = 1.0 - p; // Probability of failure. + + emp::vector outcome_probs(1, 0.0); + + while (found_probs < 0.999999 || cur_probs[N-1] > 0.0000000001) { + double next_prob = cur_probs[N-1] * p; // Probability of being one short + new success! + outcome_probs.push_back(next_prob); + found_probs += next_prob; + + // Update all of the other probabilities. + for (size_t i = N-1; i > 0; i--) { + cur_probs[i] = cur_probs[i] * q + cur_probs[i-1] * p; + } + cur_probs[0] = cur_probs[0] * q; + } + + weights.Adjust(outcome_probs); + } + + }; + } #endif From b0a0c4a75997fd65767c3756818ff3de9800216f Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 23:07:02 -0500 Subject: [PATCH 33/42] Renamed Binomial.h to Distribution.h --- examples/tools/{Binomial.cc => Distribution.cc} | 0 source/tools/{Binomial.h => Distribution.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename examples/tools/{Binomial.cc => Distribution.cc} (100%) rename source/tools/{Binomial.h => Distribution.h} (100%) diff --git a/examples/tools/Binomial.cc b/examples/tools/Distribution.cc similarity index 100% rename from examples/tools/Binomial.cc rename to examples/tools/Distribution.cc diff --git a/source/tools/Binomial.h b/source/tools/Distribution.h similarity index 100% rename from source/tools/Binomial.h rename to source/tools/Distribution.h From eb2c849c0c5603782137a2e1ec9e0c2ad7616c9b Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 23:07:36 -0500 Subject: [PATCH 34/42] Added example of NegativeBinomial distribution to Distribution.cc --- examples/tools/Distribution.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/tools/Distribution.cc b/examples/tools/Distribution.cc index 7b4c6739b1..908f5889d5 100644 --- a/examples/tools/Distribution.cc +++ b/examples/tools/Distribution.cc @@ -3,11 +3,11 @@ // Released under the MIT Software license; see doc/LICENSE // // -// Some examples code for using emp::Binomial +// Some examples code for using emp::Distribution are derived classes. #include #include "tools/Random.h" -#include "tools/Binomial.h" +#include "tools/Distribution.h" int main() { @@ -40,4 +40,17 @@ int main() << (((double) total) / (double) test_count) << std::endl; + + //emp::NegativeBinomial nbi10(0.5, 2); + emp::NegativeBinomial nbi10(0.3, 10); + + std::cout << "\n-- Negative Binomial--\n"; + + std::cout << "size = " << nbi10.GetSize() << std::endl + << "total_prob = " << nbi10.GetTotalProb() << std::endl; + + // for (size_t i = 0; i < 10; i++) { + for (size_t i = 9; i < 40; i++) { + std::cout << "nbi10[" << i << "] = " << nbi10[i] << "\n"; + } } From 9ecffc625daf140e6017133fbf492acecd248411 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 23:13:42 -0500 Subject: [PATCH 35/42] Updated Binomial.cc example to Distribution.cc --- examples/tools/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tools/Makefile b/examples/tools/Makefile index 59260a1919..4bbebd236d 100644 --- a/examples/tools/Makefile +++ b/examples/tools/Makefile @@ -20,7 +20,7 @@ CFLAGS_web_debug := $(CFLAGS_all) $(OFLAGS_web_debug) --js-library ../../source/ CFLAGS_web_opt := $(CFLAGS_all) $(OFLAGS_web_opt) --js-library ../../source/web/library_emp.js -s EXPORTED_FUNCTIONS="['_main', '_empCppCallback']" -s NO_EXIT_RUNTIME=1 #CFLAGS_web := $(CFLAGS_all) $(OFLAGS_web) --js-library ../../source/web/library_emp.js -s EXPORTED_FUNCTIONS="['_main', '_empCppCallback']" -s DISABLE_EXCEPTION_CATCHING=1 -s NO_EXIT_RUNTIME=1 -TARGETS := AnyFunction attrs Binomial BitSet BitVector Cache combos const ContiguousStream DFA File flex_function GenericFunction IndexMap info_theory Lexer lexer_utils math memo_function NFA ra_set Random Range RegEx StringMap tuple_utils TypeMap TypeTracker valsort_map vector_utils +TARGETS := AnyFunction attrs BitSet BitVector Cache combos const ContiguousStream Distribution DFA File flex_function GenericFunction IndexMap info_theory Lexer lexer_utils math memo_function NFA ra_set Random Range RegEx StringMap tuple_utils TypeMap TypeTracker valsort_map vector_utils TOOLS := ../../source/tools TOOL_DEPEND := ../../source/base/assert.h From 68b7190b54ebd92723a42ce0cc1382dc5920e7b5 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 23:14:18 -0500 Subject: [PATCH 36/42] Updated Binomial.h to Distribution.h in unit tests. --- tests/test_tools.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tools.cc b/tests/test_tools.cc index 167e3d5984..8ecbd63c84 100644 --- a/tests/test_tools.cc +++ b/tests/test_tools.cc @@ -29,11 +29,11 @@ #include "data/DataNode.h" -#include "tools/Binomial.h" #include "tools/BitMatrix.h" #include "tools/BitSet.h" #include "tools/BitVector.h" #include "tools/ContiguousStream.h" +#include "tools/Distribution.h" #include "tools/DFA.h" #include "tools/DynamicString.h" #include "tools/FunctionSet.h" From 3777351448c7b1520be0316d3ed95802333fc313 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 23 Feb 2020 23:22:51 -0500 Subject: [PATCH 37/42] Adjusted Binomial.h to Distribution.h in various files... --- source/tools/BitSet.h | 2 +- source/tools/Random.h | 8 ++++---- source/tools/matchbin_metrics.h | 4 ++-- source/tools/matchbin_regulators.h | 4 ++-- source/tools/matchbin_selectors.h | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/tools/BitSet.h b/source/tools/BitSet.h index 53974742be..eee2d0cd03 100644 --- a/source/tools/BitSet.h +++ b/source/tools/BitSet.h @@ -414,7 +414,7 @@ namespace emp { /// Mutate bits, return how many mutations were performed size_t Mutate( Random & random, - const size_t num_muts, // hint: use tools/Binomial.h with this part + const size_t num_muts, // @CAO: use tools/Binomial in Distribution.h with this part? const size_t min_idx=0 // draw this from a distribution to make some // bits more volatile than others ) { diff --git a/source/tools/Random.h b/source/tools/Random.h index 9fabcc9ecb..6e8e7fe946 100644 --- a/source/tools/Random.h +++ b/source/tools/Random.h @@ -1,7 +1,7 @@ /** * @note This file is part of Empirical, https://github.com/devosoft/Empirical * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md - * @date 2015-2019 + * @date 2015-2020. * * @file Random.h * @brief A versatile and non-patterned pseudo-random-number generator. @@ -379,7 +379,7 @@ namespace emp { * * This function is exact, but slow. * @see Random::GetApproxRandBinomial - * @see emp::Binomial in source/tools/Binomial.h + * @see emp::Binomial in source/tools/Distribution.h **/ inline uint32_t GetFullRandBinomial(const double n, const double p) { // Exact emp_assert(p >= 0.0 && p <= 1.0, p); @@ -400,7 +400,7 @@ namespace emp { * exact interface. * * @see Random::GetFullRandBinomial - * @see emp::Binomial in source/tools/Binomial.h + * @see emp::Binomial in source/tools/Distribution.h **/ inline uint32_t GetApproxRandBinomial(const double n, const double p) { // Approx emp_assert(p >= 0.0 && p <= 1.0, p); @@ -430,7 +430,7 @@ namespace emp { * * @see Random::GetFullRandBinomial * @see Random::GetApproxRandBinomial - * @see emp::Binomial in source/tools/Binomial.h + * @see emp::Binomial in source/tools/Distribution.h **/ inline uint32_t GetRandBinomial(const double n, const double p) { diff --git a/source/tools/matchbin_metrics.h b/source/tools/matchbin_metrics.h index 7427df97bb..3c9c3ed06a 100644 --- a/source/tools/matchbin_metrics.h +++ b/source/tools/matchbin_metrics.h @@ -1,7 +1,7 @@ /** * @note This file is part of Empirical, https://github.com/devosoft/Empirical * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md - * @date 2019 + * @date 2019-2020. * * @file matchbin_metrics.h * @brief Metric structs that can be plugged into MatchBin. @@ -26,7 +26,7 @@ #include #include -#include "tools/Binomial.h" +#include "tools/Distribution.h" #include "../base/assert.h" #include "../base/array.h" diff --git a/source/tools/matchbin_regulators.h b/source/tools/matchbin_regulators.h index fdfa3cab8f..bcd71f9cc5 100644 --- a/source/tools/matchbin_regulators.h +++ b/source/tools/matchbin_regulators.h @@ -1,7 +1,7 @@ /** * @note This file is part of Empirical, https://github.com/devosoft/Empirical * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md - * @date 2019 + * @date 2019-2020. * * @file matchbin_regulators.h * @brief Regulator structs that can be plugged into MatchBin. @@ -25,7 +25,7 @@ #include #include -#include "tools/Binomial.h" +#include "tools/Distribution.h" #include "../base/assert.h" #include "../base/array.h" diff --git a/source/tools/matchbin_selectors.h b/source/tools/matchbin_selectors.h index e744663b68..86b3cdd161 100644 --- a/source/tools/matchbin_selectors.h +++ b/source/tools/matchbin_selectors.h @@ -1,7 +1,7 @@ /** * @note This file is part of Empirical, https://github.com/devosoft/Empirical * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md - * @date 2019 + * @date 2019-2020. * * @file matchbin_selectors.h * @brief Selector structs that can be plugged into MatchBin. @@ -25,7 +25,7 @@ #include #include -#include "tools/Binomial.h" +#include "tools/Distribution.h" #include "../base/assert.h" #include "../base/array.h" From f84021936dc2a398ab54969b50712a1170ea060a Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 24 Feb 2020 07:18:51 -0500 Subject: [PATCH 38/42] Store distribution paramaters; only change a distribution if parameters actually change. --- source/tools/Distribution.h | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/source/tools/Distribution.h b/source/tools/Distribution.h index 11997dda59..12e4ac40d7 100644 --- a/source/tools/Distribution.h +++ b/source/tools/Distribution.h @@ -33,8 +33,22 @@ namespace emp { /// How many successes with p probability and N attempts? class Binomial : public Distribution { + private: + double p = 0.0; + size_t N = 0; + public: - Binomial(double p, size_t N) { + Binomial(double _p, size_t _N) { Setup(_p, _N); } + + double GetP() { return p; } + double GetN() { return N; } + + void Setup(double _p, size_t _N) { + // If we're not changing these values, it's already setup! + if (p == _p && N == _N) return; + + p = _p; + N = _N; weights.Resize(N+1); // p^k * (1-p)^(N-k) * N!/k!(N-k)! @@ -55,8 +69,22 @@ namespace emp { /// How many attemtps to reach N successes, assumming p probability per attempt? class NegativeBinomial : public Distribution { + private: + double p = 0.0; + size_t N = 0; + public: - NegativeBinomial(double p, size_t N) { + NegativeBinomial(double _p, size_t _N) { Setup(_p, _N); } + + double GetP() { return p; } + double GetN() { return N; } + + void Setup(double _p, size_t _N) { + // If we're not changing these values, it's already setup! + if (p == _p && N == _N) return; + + p = _p; + N = _N; emp_assert(p > 0.0 && p <= 1.0, p); emp_assert(N > 0, N); From 09421c28eb7c31ab0308cd2fae306aa822106de9 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 25 Feb 2020 15:12:50 -0500 Subject: [PATCH 39/42] Nix spawn core in SignalGP constructor Closes #270 --- source/hardware/EventDrivenGP.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/hardware/EventDrivenGP.h b/source/hardware/EventDrivenGP.h index 8a781d3461..8ba45de00b 100644 --- a/source/hardware/EventDrivenGP.h +++ b/source/hardware/EventDrivenGP.h @@ -807,8 +807,6 @@ namespace emp { // Add all available cores to inactive. for (size_t i = 0; i < inactive_cores.size(); ++i) inactive_cores[i] = (inactive_cores.size() - 1) - i; - // Spin up main core (will spin up on function ID = 0). - SpawnCore(0, memory_t(), true); } From 53c9c3ef074f1811deb2620eaa4dbf90364fb0e3 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 25 Feb 2020 18:53:04 -0500 Subject: [PATCH 40/42] Track constructor SpawnCore nix in tests --- tests/test_hardware.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_hardware.cc b/tests/test_hardware.cc index 214823d496..83ab968e77 100644 --- a/tests/test_hardware.cc +++ b/tests/test_hardware.cc @@ -43,6 +43,10 @@ TEST_CASE("Test SignalGP ('EventDrivenGP.h')", "[hardware]") hardware_t hw1(&inst_lib, &event_lib, &random); hardware_t hw2(&inst_lib, &event_lib, &random); + // Spin up main cores (used to be handled in constructor) + hw1.SpawnCore(0); + hw2.SpawnCore(0); + // Configure the hardware. hw1.SetMinBindThresh(HW_MIN_SIM_THRESH); hw1.SetMaxCores(HW_MAX_THREADS); @@ -492,6 +496,7 @@ TEST_CASE("Test SignalGP ('EventDrivenGP.h') utility: GenRandSignalGPProgram", " // We'll use some SignalGP hardware to test randomly generated programs. event_lib_t event_lib; hardware_t hw(&inst_lib, &event_lib, &random); + hw.SpawnCore(0); // Spin up main cores (used to be handled in constructor) hw.SetMinBindThresh(HW_MIN_SIM_THRESH); hw.SetMaxCores(HW_MAX_THREADS); hw.SetMaxCallDepth(HW_MAX_CALL_DEPTH); @@ -721,6 +726,7 @@ TEST_CASE("Test SignalGP ('EventDrivenGP.h') utility: SignalGP MatchBin Cache", // Let's make two SignalGP virtual hardwares: 2 with 16-bit tags hardware_t hw1(&inst_lib, &event_lib, &random); + hw1.SpawnCore(0); // Spin up main cores (used to be handled in constructor) REQUIRE(hw1.GetMatchBin().Size() == 0); From b1f88da92680bc60416b7f1e37b59209794828ed Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 25 Feb 2020 18:54:58 -0500 Subject: [PATCH 41/42] Track constructor Spawn Core nix in examples --- examples/hardware/SignalGP.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/hardware/SignalGP.cc b/examples/hardware/SignalGP.cc index e61b98ef69..96994eff1f 100644 --- a/examples/hardware/SignalGP.cc +++ b/examples/hardware/SignalGP.cc @@ -71,6 +71,10 @@ int main() { hardware_t hw16_1(&inst_lib, &event_lib, &random); hardware_t hw16_2(&inst_lib, &event_lib, &random); + // Spin up main cores (used to be handled in constructor) + hw16_1.SpawnCore(0); + hw16_2.SpawnCore(0); + // Configure the hardware. hw16_1.SetMinBindThresh(HW_MIN_SIM_THRESH); hw16_1.SetMaxCores(HW_MAX_THREADS); @@ -149,7 +153,7 @@ int main() { // What about an instruction to allow the two SignalGP hardwares to communicate? // This time we'll use a lambda to specify how the instruction should work. - inst_lib.AddInst("MsgFriend", [](hardware_t & hw, const inst_t & inst) { + inst_lib.AddInst("MsgFriend", []( & hw, const inst_t & inst) { // Trigger a Msg event using the hardware that executed this instruction where the event's data is // the output memory of the sender. hw.TriggerEvent("Msg", inst.affinity, hw.GetCurState().output_mem); From b4e78e34195ad71aad12daa72c1fd5a45f5229e4 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 25 Feb 2020 20:05:30 -0500 Subject: [PATCH 42/42] Reverse dumb typo --- examples/hardware/SignalGP.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hardware/SignalGP.cc b/examples/hardware/SignalGP.cc index 96994eff1f..b1f2cad7cf 100644 --- a/examples/hardware/SignalGP.cc +++ b/examples/hardware/SignalGP.cc @@ -153,7 +153,7 @@ int main() { // What about an instruction to allow the two SignalGP hardwares to communicate? // This time we'll use a lambda to specify how the instruction should work. - inst_lib.AddInst("MsgFriend", []( & hw, const inst_t & inst) { + inst_lib.AddInst("MsgFriend", [](hardware_t & hw, const inst_t & inst) { // Trigger a Msg event using the hardware that executed this instruction where the event's data is // the output memory of the sender. hw.TriggerEvent("Msg", inst.affinity, hw.GetCurState().output_mem);