From 7a3e4098c87bccf84d2238b2b9cbede536e42dd1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 11 Mar 2024 22:47:29 +0100 Subject: [PATCH] Library: some first thoughts regarding random number generation Relying on random numbers for verification and measurements is known to be problematic. At some point we are bound to control the seed values -- and in the actual application usage we want to record sequence seeding in the event log. Some initial thoughts regarding this intricate topic. * a low-ceremony drop-in replacement for rand() is required * we want the ability to pick-up and control each and every usage eventually * however, some usages explicitly require true randomness * the ability to use separate streams of random-number generation is desirable --- src/common/option.hpp | 1 + src/lib/del-stash.hpp | 1 + src/lib/error-exception.cpp | 1 + src/lib/error.hpp | 2 +- src/lib/format-string.hpp | 1 + src/lib/integral.hpp | 43 +++++++++++ src/lib/random.cpp | 38 ++++++++++ src/lib/random.hpp | 96 ++++++++++++++++++++++++ src/lib/rational.hpp | 3 - src/lib/stat/csv.hpp | 10 +-- src/lib/stat/data.hpp | 12 +-- src/vault/gear/job.h | 1 + tests/16calculation.tests | 5 ++ tests/library/random-test.cpp | 71 ++++++++++++++++++ tests/library/rational-test.cpp | 1 + wiki/thinkPad.ichthyo.mm | 125 ++++++++++++++++++++++++++++++++ 16 files changed, 397 insertions(+), 14 deletions(-) create mode 100644 src/lib/integral.hpp create mode 100644 src/lib/random.cpp create mode 100644 src/lib/random.hpp create mode 100644 tests/library/random-test.cpp diff --git a/src/common/option.hpp b/src/common/option.hpp index 432a41821..a03a7688a 100644 --- a/src/common/option.hpp +++ b/src/common/option.hpp @@ -46,6 +46,7 @@ #ifndef LUMIERA_OPTION_H #define LUMIERA_OPTION_H +#include "lib/nocopy.hpp" #include "lib/cmdline.hpp" #include "lib/format-cout.hpp" diff --git a/src/lib/del-stash.hpp b/src/lib/del-stash.hpp index fac9523e1..39e274aab 100644 --- a/src/lib/del-stash.hpp +++ b/src/lib/del-stash.hpp @@ -45,6 +45,7 @@ #include "lib/error.hpp" +#include "lib/symbol.hpp" #include "lib/nocopy.hpp" #include diff --git a/src/lib/error-exception.cpp b/src/lib/error-exception.cpp index 3320dcd06..ee3a88472 100644 --- a/src/lib/error-exception.cpp +++ b/src/lib/error-exception.cpp @@ -33,6 +33,7 @@ #include "lib/error.hpp" +#include "include/lifecycle.h" #include "lib/meta/util.hpp" #include "lib/util.hpp" diff --git a/src/lib/error.hpp b/src/lib/error.hpp index 44b797f59..745f33e34 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -42,7 +42,7 @@ #define _STDBOOL_H // prevent from including stdbool.h #include "include/logging.h" -#include "include/lifecycle.h" +#include "lib/hash-standard.hpp" #include "lib/error.h" #include diff --git a/src/lib/format-string.hpp b/src/lib/format-string.hpp index 7e602ccee..7e265ed77 100644 --- a/src/lib/format-string.hpp +++ b/src/lib/format-string.hpp @@ -108,6 +108,7 @@ #define UTIL_FORMAT_STRING_H #include "lib/error.hpp" +#include "lib/symbol.hpp" #include "lib/nocopy.hpp" #include "lib/meta/util.hpp" #include "lib/meta/size-trait.hpp" diff --git a/src/lib/integral.hpp b/src/lib/integral.hpp new file mode 100644 index 000000000..51c819e33 --- /dev/null +++ b/src/lib/integral.hpp @@ -0,0 +1,43 @@ +/* + INTEGRAL.hpp - there is nothing like one + + Copyright (C) Lumiera.org + 2024, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file integral.h + ** Inclusion for common place integral types and constants. + */ + + + +#ifndef LIB_INTEGRAL_H +#define LIB_INTEGRAL_H + +#include +#include +#include + +/* === minimal common place === */ +using uchar = unsigned char; +using uint = unsigned int; + + + +#endif /*LIB_INTEGRAL_H*/ diff --git a/src/lib/random.cpp b/src/lib/random.cpp new file mode 100644 index 000000000..3bf43e948 --- /dev/null +++ b/src/lib/random.cpp @@ -0,0 +1,38 @@ +/* + random.cpp - storage and implementation for random number framework + + Copyright (C) Lumiera.org + 2024, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +/** @file random.cpp + ** Implementation details and common storage for random number generation. + */ + + +//#include "error.hpp" +#include "lib/random.hpp" +//#include "lib/util.hpp" + +//#include + + +namespace lib { + +} // namespace lib diff --git a/src/lib/random.hpp b/src/lib/random.hpp new file mode 100644 index 000000000..a931921ab --- /dev/null +++ b/src/lib/random.hpp @@ -0,0 +1,96 @@ +/* + RANDOM.hpp - support for random number generation with controlled seed + + Copyright (C) Lumiera.org + 2024, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file random.hpp + ** Generating (pseudo) random numbers with controlled seed. + ** As an extension on top of the [C++ random number framework] to integral arithmetics, rational numbers can be defined + ** [C++ random number framework]: https://en.cppreference.com/w/cpp/numeric/random + ** @see Random_test + */ + + +#ifndef LIB_RANDOM_H +#define LIB_RANDOM_H + + +#include "lib/integral.hpp" +#include "lib/nocopy.hpp" + +#include + + +namespace lib { + + /** Establishes a seed point for any instance or performance. */ + class SeedNucleus; + + /** + * Access point to a selection of random number sources. + * For each kind of performance or usage, a common execution scheme + * is established to initiate generated number sequences, allowing + * for seemingly random yet reproducible behaviour — or for actually + * contingent behaviour when necessary. Client code should rely on + * [Dependency-Injection](\ref lib::Depend) or the static accessors. + */ + template + class RandomSequencer + : util::NonCopyable + { + std::uniform_int_distribution uniformI_; + std::uniform_int_distribution uniformU_; + std::uniform_real_distribution uniformD_; + + GEN generator_; + + /** Random instances are created as part of an execution scheme */ + RandomSequencer(SeedNucleus&); + friend class SeedNucleus; + + public: + int i32() { return uniformI_(generator_); } + uint64_t u64() { return uniformU_(generator_); } + double uni() { return uniformD_(generator_); } + }; + + /** + * PRNG engine to use by default: 64bit mersenne twister. + */ + using Random = RandomSequencer; + + + /** a global default RandomSequencer for mundane purposes */ + extern Random defaultGen; + + /** a global RandomSequencer seeded with real entropy */ + extern Random entropyGen; + + + /* ===== convenience accessors ===== */ + + inline int rani() { return defaultGen.i32(); } + inline uint64_t ranu() { return defaultGen.u64(); } + inline double rado() { return defaultGen.uni(); } + + +} // namespace lib +#endif /*LIB_RANDOM_H*/ diff --git a/src/lib/rational.hpp b/src/lib/rational.hpp index 0c94b7d3b..955017e2b 100644 --- a/src/lib/rational.hpp +++ b/src/lib/rational.hpp @@ -82,9 +82,6 @@ namespace util { using boost::rational_cast; using std::abs; - // these are neither standard C++ nor POSIX, yet pretty much common place... - using uchar = unsigned char; - using uint = unsigned int; inline bool diff --git a/src/lib/stat/csv.hpp b/src/lib/stat/csv.hpp index 291f96494..2457525c4 100644 --- a/src/lib/stat/csv.hpp +++ b/src/lib/stat/csv.hpp @@ -141,12 +141,12 @@ namespace stat { explicit operator bool() const { - return isValid (); + return isValid(); } string operator*() const { - if (not isValid ()) fail(); + if (not isValid()) fail(); auto& mat = *curr_; return mat[2].matched? mat[2] : mat[1]; @@ -196,12 +196,12 @@ namespace stat { throw error::Invalid{_Fmt{"Garbage after last field. Line:%s|↯|%s"} % line_.substr(0,pos_) % line_.substr(pos_)}; else - if (pos_ != curr_->position()) + if (pos_ != size_t(curr_->position())) throw error::Invalid{_Fmt{"Garbage before field(%d):%s|↯|%s"} % (field_+1) % line_.substr(0,pos_) % line_.substr(pos_)}; - else - throw error::Invalid{"CSV parse floundered. Line:"+toString(line_)}; + + throw error::Invalid{_Fmt{"CSV parse floundered. Line:%s"} % line_}; } }; diff --git a/src/lib/stat/data.hpp b/src/lib/stat/data.hpp index 30bbdf0fd..65dcfbf13 100644 --- a/src/lib/stat/data.hpp +++ b/src/lib/stat/data.hpp @@ -439,11 +439,13 @@ namespace stat{ ,[&](auto& col) { if (not csv) - if (csv.isParseFail()) - csv.fail(); - else - throw error::Invalid{_Fmt{"Insufficient data; only %d fields, %d expected. Line:%s"} - % csv.getParsedFieldCnt() % columnCnt % line}; + { + if (csv.isParseFail()) + csv.fail(); + else + throw error::Invalid{_Fmt{"Insufficient data; only %d fields, %d expected. Line:%s"} + % csv.getParsedFieldCnt() % columnCnt % line}; + } using Value = typename std::remove_reference::type::ValueType; col.get() = parseAs(*csv); diff --git a/src/vault/gear/job.h b/src/vault/gear/job.h index dde40cad4..c7767de4c 100644 --- a/src/vault/gear/job.h +++ b/src/vault/gear/job.h @@ -193,6 +193,7 @@ typedef lumiera_jobDescriptor* LumieraJobDescriptor; #ifdef __cplusplus /* ============== C++ Interface ================= */ +#include "lib/nocopy.hpp" #include diff --git a/tests/16calculation.tests b/tests/16calculation.tests index ffaaba490..8b3d37dad 100644 --- a/tests/16calculation.tests +++ b/tests/16calculation.tests @@ -10,3 +10,8 @@ END PLANNED "Statistic and Regression" Statistic_test << END return: 0 END + + +PLANNED "Random numbers and Seed" Random_test << END +return: 0 +END diff --git a/tests/library/random-test.cpp b/tests/library/random-test.cpp new file mode 100644 index 000000000..1c57e328d --- /dev/null +++ b/tests/library/random-test.cpp @@ -0,0 +1,71 @@ +/* + Random(Test) - verify framework for controlled random number generation + + Copyright (C) Lumiera.org + 2024, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + +/** @file random-test.cpp + ** unit test \ref Random_test + */ + + + +#include "lib/test/run.hpp" +#include "lib/rational.hpp" +#include "lib/test/diagnostic-output.hpp"/////////////////////////TODO + + +#include +#include + +using std::array; + + +namespace util { +namespace test { + + + /***************************************************************************//** + * @test demonstrate simple access to random number generation, as well as + * the setup of controlled random number sequences. + * @see random.hpp + */ + class Random_test : public Test + { + + virtual void + run (Arg) + { + simpleUsage(); + } + + + /** + * @test demonstrate usage of default random number generators + */ + void + simpleUsage() + { + } + }; + + LAUNCHER (Random_test, "unit common"); + + +}} // namespace util::test diff --git a/tests/library/rational-test.cpp b/tests/library/rational-test.cpp index 9a1460398..0ada52d48 100644 --- a/tests/library/rational-test.cpp +++ b/tests/library/rational-test.cpp @@ -28,6 +28,7 @@ #include "lib/error.hpp" #include "lib/test/run.hpp" +#include "lib/integral.hpp" #include "lib/format-cout.hpp" #include "lib/rational.hpp" diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index ccd0fe350..b905af191 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -57242,6 +57242,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -118998,6 +119060,69 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +