Library: now using controlled seed and replaced rand (closes #1378)

After augmenting our `lib/random.hpp` abstraction framework to add the necessary flexibility,
a common seeding scheme was ''built into the Test-Runner.''
 * all tests relying on some kind of randomness should invoke `seedRand()`
 * this draws a seed from the `entropyGen` — which is also documented in the log
 * individual tests can now be launched with `--seed` to force a dedicated seed
 * moreover, tests should build a coherent structure of linked generators,
   especially when running concurrently. The existing tests were adapted accordingly

All usages of `rand()` in the code base were investigated and replaced
by suitable calls to our abstraction framework; the code base is thus
isolated from the actual implementation, simplifying further adaptation.
This commit is contained in:
Fischlurch 2024-11-17 19:45:41 +01:00
parent 693ba32c8e
commit a20e233ca0
19 changed files with 508 additions and 207 deletions

View file

@ -45,6 +45,13 @@
namespace lib { namespace lib {
namespace {
inline uint constexpr
_iBOUND()
{
return 1u+uint(std::numeric_limits<int>::max());
}
}
/** Establishes a seed point for any instance or performance. */ /** Establishes a seed point for any instance or performance. */
class SeedNucleus class SeedNucleus
@ -64,26 +71,31 @@ namespace lib {
*/ */
template<class GEN> template<class GEN>
class RandomSequencer class RandomSequencer
: util::NonCopyable
{ {
std::uniform_int_distribution<int> uniformI_;
std::uniform_int_distribution<uint64_t> uniformU_;
std::uniform_real_distribution<double> uniformD_;
GEN generator_; GEN generator_;
public: public:
/** Random instances are created as part of an execution scheme */ /** Build new generator, drawing seed from a virtual seed source */
RandomSequencer (SeedNucleus&); RandomSequencer (SeedNucleus&);
int i32() { return uniformI_(generator_); } /** Build new generator, drawing a seed from given parent generator */
uint64_t u64() { return uniformU_(generator_); } template<class G>
double uni() { return uniformD_(generator_); } RandomSequencer (RandomSequencer<G>&);
friend int rani(uint); // default copy operations (can copy and assign a state)
friend double ranRange(double,double);
friend double ranNormal(double,double);
friend HashVal ranHash(); int i(uint bound =_iBOUND()); ///< drop-in replacement for `rand() % bound`
int i32(); ///< random number from _full integer range_ (incl. negative values)
uint64_t u64(); ///< random 64bit number from full range.
double uni(); ///< random double drawn from interval `[0.0 ... 1.0[`
double range (double start, double bound); ///< random double from designated interval (upper bound excluded)
double normal(double mean=0.0, double stdev=1.0); ///< normal distribution (gaussian)
HashVal hash(); ///< _non-zero_ hash value from full 64bit range
/** generic adapter: draw next number to use the given distribution */
template<class DIST>
auto distribute(DIST);
/** inject controlled randomisation */ /** inject controlled randomisation */
void reseed (SeedNucleus&); void reseed (SeedNucleus&);
@ -110,8 +122,9 @@ namespace lib {
}; };
/** /**
* PRNG engine to use by default: 64bit mersenne twister. * PRNG engine to use by default: 64bit Mersenne twister.
*/ */
using Random = RandomSequencer<std::mt19937_64>; using Random = RandomSequencer<std::mt19937_64>;
@ -123,41 +136,34 @@ namespace lib {
extern Random entropyGen; extern Random entropyGen;
/* ===== convenience accessors ===== */ /* ===== convenience accessors ===== */
/** @return a random integer ∈ [0 ... bound[ */ /** @return a random integer ∈ [0 ... bound[ */
inline int inline int
rani (uint bound =1u<<31) rani (uint bound =_iBOUND())
{ {
if (!bound) ++bound; return defaultGen.i(bound);
--bound;
uint upper{std::numeric_limits<int>::max()};
upper = bound < upper? bound : upper;
std::uniform_int_distribution<int> dist(0, upper);
return dist (defaultGen.generator_);
} }
/** @return a random double ∈ [start ... bound[ */ /** @return a random double ∈ [start ... bound[ */
inline double inline double
ranRange (double start, double bound) ranRange (double start, double bound)
{ {
std::uniform_real_distribution<double> dist{start,bound}; return defaultGen.range (start, bound);
return dist (defaultGen.generator_);
} }
inline double inline double
ranNormal(double mean =0.0, double stdev =1.0) ranNormal(double mean =0.0, double stdev =1.0)
{ {
std::normal_distribution<double> dist{mean,stdev}; return defaultGen.normal (mean, stdev);
return dist (defaultGen.generator_);
} }
/** @return a random *non-zero* HashVal */ /** @return a random *non-zero* HashVal */
inline lib::HashVal inline lib::HashVal
ranHash() ranHash()
{ {
static std::uniform_int_distribution<lib::HashVal> dist{lib::HashVal(1)}; return defaultGen.hash();
return dist (defaultGen.generator_);
} }
@ -169,15 +175,20 @@ namespace lib {
/* ===== Implementation details ===== */ /* ===== Implementation details ===== */
template<class GEN> template<class GEN>
inline inline
RandomSequencer<GEN>::RandomSequencer (SeedNucleus& nucleus) RandomSequencer<GEN>::RandomSequencer (SeedNucleus& nucleus)
: uniformI_{0} : generator_{nucleus.getSeed()}
, uniformU_{0} { }
, uniformD_{}
, generator_{nucleus.getSeed()} template<class GEN>
template<class G>
inline
RandomSequencer<GEN>::RandomSequencer (RandomSequencer<G>& parent)
: generator_{RandomSequencer<GEN>::Seed{parent}.getSeed()}
{ } { }
@ -189,5 +200,115 @@ namespace lib {
} }
template<class GEN>
template<class DIST>
inline auto
RandomSequencer<GEN>::distribute (DIST distribution)
{
return distribution (generator_);
}
/** @param bound upper bound (exclusive!) */
template<class GEN>
inline int
RandomSequencer<GEN>::i (uint bound)
{
if (!bound) bound=1;
--bound;
uint upper{std::numeric_limits<int>::max()};
upper = bound < upper? bound : upper;
return distribute (std::uniform_int_distribution<int> (0, upper));
}
template<class GEN>
inline int
RandomSequencer<GEN>::i32()
{
return distribute (std::uniform_int_distribution<int> {std::numeric_limits<int>::min()
,std::numeric_limits<int>::max()});
}
template<class GEN>
inline uint64_t
RandomSequencer<GEN>::u64()
{
return distribute (std::uniform_int_distribution<uint64_t> {std::numeric_limits<uint64_t>::min()
,std::numeric_limits<uint64_t>::max()});
}
template<class GEN>
inline double
RandomSequencer<GEN>::uni()
{
return range (0.0, 1.0);
}
template<class GEN>
inline double
RandomSequencer<GEN>::range (double start, double bound)
{
return distribute (std::uniform_real_distribution<double>{start,bound});
}
template<class GEN>
inline double
RandomSequencer<GEN>::normal (double mean, double stdev)
{
return distribute (std::normal_distribution<double>{mean,stdev});
}
template<class GEN>
inline HashVal
RandomSequencer<GEN>::hash()
{
return distribute (std::uniform_int_distribution<lib::HashVal>{lib::HashVal(1)});
}
/**
* Adapter to protect against data corruption caused by concurrent access.
* Random number generators in general are _not thread safe;_ when used from
* several threads concurrently, it is not a question _if_, but only a question
* _when_ the internal state will become corrupted, leading to degraded and biased
* distributions of produced numbers. For some usage scenarios however, ignoring
* this fact and still using a single generator from several threads may be acceptable,
* if the quality of the distribution actually does not matter and only some diffusion
* of numbers is required (e.g. adding a random sleep interval). But there is a catch:
* whenever the value range of generated numbers is less than the total range of the used
* data representation, then corruption of the internal state may lead to producing numbers
* outside the defined range. This adapter can be used to safeguard against this scenario.
* @remark typically using a 64bit generator on a 64bit platform is inherently safe, yet
* using a 32bit generator may rely on 64bit values internally, and then this problem
* may be triggered. See RandomConcurrent_test with the 32bit Mersenne twister as demo.
*/
template<class GEN>
class CappedGen
: public GEN
{
public:
using GEN::GEN;
typename GEN::result_type
operator()()
{
if constexpr (GEN::max() < std::numeric_limits<typename GEN::result_type>::max())
return GEN::operator()() % (GEN::max()+1);
else
return GEN::operator()();
}
};
template<class GEN>
auto
buildCappedSubSequence (RandomSequencer<GEN>& src)
{
typename RandomSequencer<GEN>::Seed seedChain(src);
RandomSequencer<CappedGen<GEN>> subSeq{seedChain};
return subSeq;
}
} // namespace lib } // namespace lib
#endif /*LIB_RANDOM_H*/ #endif /*LIB_RANDOM_H*/

View file

@ -83,7 +83,7 @@ namespace microbenchmark {
wrap (FUN&& fun) wrap (FUN&& fun)
{ {
return [functor=std::forward<FUN>(fun)] return [functor=std::forward<FUN>(fun)]
(size_t) (size_t) mutable
{ {
functor(); functor();
return size_t(1); return size_t(1);
@ -101,7 +101,7 @@ namespace microbenchmark {
wrap (FUN&& fun) wrap (FUN&& fun)
{ {
return [functor=std::forward<FUN>(fun)] return [functor=std::forward<FUN>(fun)]
(size_t i) (size_t i) mutable
{ {
return size_t(functor(i)); return size_t(functor(i));
}; };
@ -117,7 +117,7 @@ namespace microbenchmark {
wrap (FUN&& fun) wrap (FUN&& fun)
{ {
return [functor=std::forward<FUN>(fun)] return [functor=std::forward<FUN>(fun)]
(size_t) (size_t) mutable
{ {
return size_t(functor()); return size_t(functor());
}; };
@ -133,7 +133,7 @@ namespace microbenchmark {
wrap (FUN&& fun) wrap (FUN&& fun)
{ {
return [functor=std::forward<FUN>(fun)] return [functor=std::forward<FUN>(fun)]
(size_t i) (size_t i) mutable
{ {
functor(i); functor(i);
return size_t(1); return size_t(1);

View file

@ -165,9 +165,10 @@ namespace test{
struct Thread struct Thread
: lib::ThreadJoinable<> : lib::ThreadJoinable<>
{ {
Thread(Subject const& testSubject, size_t loopCnt, SyncBarrier& testStart) Thread(Subject const& subject, size_t loopCnt, SyncBarrier& testStart)
: ThreadJoinable{"Micro-Benchmark" : ThreadJoinable{"Micro-Benchmark"
,[=, &testStart]() // local copy of the test-subject-Functor ,[this,loopCnt, testSubject=subject, &testStart]
() mutable // local (mutable) copy of the test-subject-Functor
{ {
testStart.sync(); // block until all threads are ready testStart.sync(); // block until all threads are ready
auto start = steady_clock::now(); auto start = steady_clock::now();

View file

@ -17,6 +17,6 @@ return: 0
END END
TEST "Concurrent PRNG access" RandomConcurrent_test << END TEST "Concurrent PRNG access" RandomConcurrent_test quick << END
return: 0 return: 0
END END

View file

@ -187,6 +187,7 @@ namespace test{
uint64_t consumerSum = 0; uint64_t consumerSum = 0;
SyncBarrier& trigger_; SyncBarrier& trigger_;
Random rand_;
void void
countConsumerCall (uint increment) countConsumerCall (uint increment)
@ -198,13 +199,13 @@ namespace test{
Worker(CallQueue& queue, SyncBarrier& commonTrigger) Worker(CallQueue& queue, SyncBarrier& commonTrigger)
: ThreadJoinable{"CallQueue_test: concurrent dispatch" : ThreadJoinable{"CallQueue_test: concurrent dispatch"
, [&]() { , [&]() {
uint cnt = rand() % MAX_RAND_STEPS; //////////////////////////////OOO brauche rani auf lokalem Generator! uint cnt = rand_.i(MAX_RAND_STEPS);
uint delay = rand() % MAX_RAND_DELAY; uint delay = rand_.i(MAX_RAND_DELAY);
trigger_.sync(); // block until all threads are ready trigger_.sync(); // block until all threads are ready
for (uint i=0; i<cnt; ++i) for (uint i=0; i<cnt; ++i)
{ {
uint increment = rand() % MAX_RAND_INCMT; uint increment = rand_.i(MAX_RAND_INCMT);
queue.feed ([=]() { countConsumerCall(increment); }); queue.feed ([=]() { countConsumerCall(increment); });
producerSum += increment; producerSum += increment;
usleep (delay); usleep (delay);
@ -212,6 +213,7 @@ namespace test{
} // and thus belonging to some random other thread } // and thus belonging to some random other thread
}} }}
, trigger_{commonTrigger} , trigger_{commonTrigger}
, rand_{defaultGen}
{ } { }
}; };
@ -227,7 +229,7 @@ namespace test{
void void
verify_ThreadSafety() verify_ThreadSafety()
{ {
////////////////////////////////////////////////OOO seedRandom() seedRand();
CallQueue queue; CallQueue queue;
SyncBarrier trigger{NUM_OF_THREADS + 1}; SyncBarrier trigger{NUM_OF_THREADS + 1};

View file

@ -57,7 +57,7 @@ namespace test{
Sub() Sub()
: TestTargetObj(created++) : TestTargetObj(created++)
,instanceID_(rand() % MAX_ID) ,instanceID_(rani(MAX_ID))
{ } { }
virtual operator string() const virtual operator string() const

View file

@ -162,6 +162,7 @@ namespace test{
void void
verify_heavilyParallelUsage() verify_heavilyParallelUsage()
{ {
seedRand();
auto verifyResult = [](VecI sequence) auto verifyResult = [](VecI sequence)
{ {
uint prev = 0; uint prev = 0;
@ -183,28 +184,21 @@ namespace test{
} }
/** build a call stack within separate thread and capture diagnostics */ /**
* Build a call stack within separate thread and capture diagnostics.
* The actual test operation produces a descending number sequence,
* and only odd values will be captured into the diagnostic stack-
*/
struct TestThread struct TestThread
: ThreadJoinable<VecI> : ThreadJoinable<VecI>
{ {
TestThread() TestThread()
: ThreadJoinable("test context stack" : ThreadJoinable{"test context stack"
,&verifyDiagnosticStack) ,[seed = 1+rani(MAX_RAND)]
{ return descend (seed); }}
{ } { }
}; };
/** the actual test operation running in a separate thread
* produces a descending number sequence, and only odd values
* will be captured into the diagnostic stack
*/
static VecI
verifyDiagnosticStack()
{
uint seed (1 + rand() % MAX_RAND); /////////////////////////OOO brauche rani() auf lokalem Generator
return descend (seed);
}
static VecI static VecI
descend (uint current) descend (uint current)
{ {

View file

@ -47,6 +47,7 @@
#include "lib/random.hpp" #include "lib/random.hpp"
#include "lib/util.hpp" #include "lib/util.hpp"
#include <cstdlib>
#include <utility> #include <utility>
#include <array> #include <array>
@ -183,9 +184,11 @@ namespace test{
TypedCounter testCounter; TypedCounter testCounter;
auto testSubject = [&, i = rani(MAX_INDEX)] auto testSubject = [&
(size_t) -> size_t ,gen = makeRandGen()]
(size_t) mutable -> size_t
{ {
uint i = gen.i(MAX_INDEX);
operators[i](testCounter); operators[i](testCounter);
return 1; return 1;
}; };

View file

@ -58,7 +58,7 @@
** Astute readers might have noticed, that the test fixture is sloppy with respect to proper ** Astute readers might have noticed, that the test fixture is sloppy with respect to proper
** locking and synchronisation. Rather, some explicit sleep commands are interspersed in a way ** locking and synchronisation. Rather, some explicit sleep commands are interspersed in a way
** tuned to work satisfactory in practice. This whole approach can only work, because each ** tuned to work satisfactory in practice. This whole approach can only work, because each
** Posix locking call actually requires the runtime system to issue a read/write barrier, ** POSIX locking call actually requires the runtime system to issue a read/write barrier,
** which are known to have global effects on the relevant platforms (x86 and x86_64). ** which are known to have global effects on the relevant platforms (x86 and x86_64).
** And because the production relevant code in SteamDispatcher uses sufficient (in fact ** And because the production relevant code in SteamDispatcher uses sufficient (in fact
** even excessive) locking, the state variables of the test fixture are properly synced ** even excessive) locking, the state variables of the test fixture are properly synced
@ -324,6 +324,7 @@ namespace test {
void void
perform_massivelyParallel (Arg args_for_stresstest) perform_massivelyParallel (Arg args_for_stresstest)
{ {
seedRand();
maybeOverride (NUM_THREADS_DEFAULT, args_for_stresstest, 1); maybeOverride (NUM_THREADS_DEFAULT, args_for_stresstest, 1);
maybeOverride (NUM_INVOC_PER_THRED, args_for_stresstest, 2); maybeOverride (NUM_INVOC_PER_THRED, args_for_stresstest, 2);
maybeOverride (MAX_RAND_DELAY_us, args_for_stresstest, 3); maybeOverride (MAX_RAND_DELAY_us, args_for_stresstest, 3);
@ -336,6 +337,7 @@ namespace test {
SyncBarrier& barrier_; SyncBarrier& barrier_;
FamilyMember<InvocationProducer> id_; FamilyMember<InvocationProducer> id_;
vector<string> cmdIDs_; vector<string> cmdIDs_;
lib::Random random_;
lib::ThreadJoinable<void> thread_; lib::ThreadJoinable<void> thread_;
@ -350,6 +352,7 @@ namespace test {
public: public:
InvocationProducer (SyncBarrier& trigger) InvocationProducer (SyncBarrier& trigger)
: barrier_{trigger} : barrier_{trigger}
, random_{defaultGen}
, thread_{"producer", [&]{ fabricateCommands(); }} , thread_{"producer", [&]{ fabricateCommands(); }}
{ } { }
@ -381,11 +384,11 @@ namespace test {
SessionCommand::facade().trigger (msg.idi.getSym(), msg.data.get<Rec>()); SessionCommand::facade().trigger (msg.idi.getSym(), msg.data.get<Rec>());
} }
static void void
__randomDelay() __randomDelay()
{ {
if (not MAX_RAND_DELAY_us) return; if (not MAX_RAND_DELAY_us) return;
sleep_for (microseconds (1 + rand() % MAX_RAND_DELAY_us)); // random delay varying in steps of 1µs sleep_for (microseconds (1 + random_.i(MAX_RAND_DELAY_us))); // random delay varying in steps of 1µs
} }
}; };

View file

@ -230,7 +230,7 @@ namespace test{
public: public:
Special() Special()
: Probe<555>() : Probe<555>()
, secret_('a' + (rand() % (1+'z'-'a'))) , secret_('a' + rani('z'-'a' +1))
{ {
checksum += secret_; checksum += secret_;
} }

View file

@ -222,8 +222,11 @@ namespace test{
watch.expectThreads(CONCURR) watch.expectThreads(CONCURR)
.expectIncidents(10000); .expectIncidents(10000);
auto act = [&]{ // two nested activities with random delay auto act = [&
uint delay = 100 + rand() % 800; ,gen = makeRandGen()]// local random generator per thread
() mutable
{ // two nested activities with random delay
uint delay = 100 + gen.i(800);
watch.markEnter(); watch.markEnter();
sleep_for (microseconds(delay)); sleep_for (microseconds(delay));
watch.markEnter(2); watch.markEnter(2);

View file

@ -40,9 +40,6 @@
#include <deque> #include <deque>
#include <tuple> #include <tuple>
//#include <array>
//using util::isLimited;
//using std::array;
using std::tuple; using std::tuple;
using std::deque; using std::deque;
using util::_Fmt; using util::_Fmt;
@ -66,13 +63,62 @@ namespace test {
{ {
virtual void virtual void
run (Arg) run (Arg arg)
{ {
seedRand(); seedRand();
benchmark_random_gen();
if ("quick" != firstTok (arg))
investigate_concurrentAccess(); investigate_concurrentAccess();
} }
/** @test microbenchmark of various random number generators
* @remark typical values
* - `rand()` (trinomial generator) : 15ns / 10ns (O3)
* - Mersenne twister 64bit : 55ns / 25ns (O3)
* - reading /dev/urandom : 480ns / 470 (O3)
*/
void
benchmark_random_gen()
{
auto do_nothing = []{ /* take it easy */ };
auto mersenne64 = []{ return rani(); };
auto legacy_gen = []{ return rand(); };
std::random_device entropySource{"/dev/urandom"};
auto rly_random = [&]{ return entropySource(); };
_Fmt resultDisplay{"µ-bench(%s)%|45T.| %5.3f µs"};
double d1 = microBenchmark (do_nothing, NUM_INVOKES).first;
cout << resultDisplay % "(empty call)" % d1 <<endl;
double d2 = microBenchmark (mersenne64, NUM_INVOKES).first;
cout << resultDisplay % "Mersenne-64" % d2 <<endl;
double d3 = microBenchmark (legacy_gen, NUM_INVOKES).first;
cout << resultDisplay % "std::rand()" % d3 <<endl;
double d4 = microBenchmark (rly_random, NUM_INVOKES).first;
cout << resultDisplay % "/dev/urandom" % d4 <<endl;
CHECK (d3 < d2 and d2 < d4);
}
/**
* Research setup to investigate concurrent access to a random generator.
* From each test thread, the shared generator instance is invoked a huge number times
* (defined by NUM_INVOKES), thereby computing the mean value and checking for defect
* numbers outside the generator's definition range. This probe cycle is repeated
* several times (defined by NUM_SAMPLES) and the results are collected and evaluated
* afterwards to detect signs of a skewed distribution.
* @tparam GEN a C++ compliant generator type
* @tparam threads number of threads to run in parallel
* @remark Pseudo random number generation as such is not threadsafe, and pressing for
* concurrent access (as done here) will produce a corrupted internal generator
* state sooner or later. Under some circumstances however, theses glitches
* can be ignored, if quality of generated numbers actually does not matter.
*/
template<typename GEN, uint threads> template<typename GEN, uint threads>
struct Experiment struct Experiment
: Sync<> : Sync<>
@ -103,7 +149,7 @@ namespace test {
double percentTilted {0.0}; double percentTilted {0.0};
bool isFailure {false}; bool isFailure {false};
/** run the experiment series */
void void
perform() perform()
{ {
@ -116,7 +162,7 @@ namespace test {
auto r = generator(); auto r = generator();
if (r < GEN::min() or r > GEN::max()) if (r < GEN::min() or r > GEN::max())
++fail; ++fail;
avg += 1.0/N * r;//(r % Engine::max()); avg += 1.0/N * r;
} }
auto error = avg/expect - 1; auto error = avg/expect - 1;
recordRun (error, fail); recordRun (error, fail);
@ -128,7 +174,7 @@ namespace test {
_Fmt resultLine{"%6.3f ‰ : %d %s"}; _Fmt resultLine{"%6.3f ‰ : %d %s"};
for (auto [err,fails] : results) for (auto [err,fails] : results)
{ {
bool isGlitch = fails or fabs(err) >0.003; bool isGlitch = fails or fabs(err) > 3 * 1/sqrt(N); // mean of a sound distribution will remain within bounds
cout << resultLine % (err*1000) cout << resultLine % (err*1000)
% fails % fails
% (fails? "FAIL": isGlitch? " !! ":"") << endl; % (fails? "FAIL": isGlitch? " !! ":"") << endl;
@ -138,8 +184,8 @@ namespace test {
} }
// assess overall results...... // assess overall results......
percentGlitches = 100.0 * glitches/cases; percentGlitches = 100.0 * glitches/cases;
percentTilted = 100.0 * fabs(double(lows)/cases - 0.5)*2; percentTilted = 100.0 * fabs(double(lows)/cases - 0.5)*2; // degree to which mean is biased for one side
isFailure = glitches or percentTilted > 30; isFailure = glitches or percentTilted > 30; // (empirical trigger criterion)
cout << _Fmt{"++-------------++ %s\n" cout << _Fmt{"++-------------++ %s\n"
" Glitches: %5.1f %%\n" " Glitches: %5.1f %%\n"
" Tilted: %5.1f %%\n" " Tilted: %5.1f %%\n"
@ -152,24 +198,33 @@ namespace test {
}; };
/** @test examine behaviour of PRNG under concurrency stress */ /** @test examine behaviour of PRNG under concurrency stress
* - running a 32bit generator single threaded should not trigger alarms
* - while under concurrent pressure several defect numbers should be produced
* - even the 64bit generator will show uneven distribution due to corrupted state
* - the 32bit generator capped to its valid range exhibits skew only occasionally
* @see lib::CappedGen
*/
void void
investigate_concurrentAccess() investigate_concurrentAccess()
{ {
using Mersenne32 = std::mt19937;
using Mersenne64 = std::mt19937_64; using Mersenne64 = std::mt19937_64;
using Mersenne32 = std::mt19937;
using CappedMs32 = CappedGen<Mersenne32>;
Experiment<Mersenne32,1> single32{Mersenne32(defaultGen.uni())}; Experiment<Mersenne32,1> single_mers32{Mersenne32(defaultGen.uni())};
Experiment<Mersenne32,NUM_THREADS> concurr32{Mersenne32(defaultGen.uni())}; Experiment<Mersenne32,NUM_THREADS> concurr_mers32{Mersenne32(defaultGen.uni())};
Experiment<Mersenne64,NUM_THREADS> concurr64{Mersenne64(defaultGen.uni())}; Experiment<Mersenne64,NUM_THREADS> concurr_mers64{Mersenne64(defaultGen.uni())};
Experiment<CappedMs32,NUM_THREADS> concCap_mers32{CappedMs32(defaultGen.uni())};
single32.perform(); single_mers32.perform();
concurr32.perform(); concurr_mers32.perform();
concurr64.perform(); concurr_mers64.perform();
concCap_mers32.perform();
CHECK (not single32.isFailure, "ALARM : single-threaded Mersenne-Twister 32bit produces skewed distribution"); CHECK (not single_mers32.isFailure, "ALARM : single-threaded Mersenne-Twister 32bit produces skewed distribution");
CHECK ( single32.isFailure, "SURPRISE : Mersenne-Twister 32bit encountered NO glitches under concurrent pressure"); CHECK ( concurr_mers32.isFailure, "SURPRISE : Mersenne-Twister 32bit encountered NO glitches under concurrent pressure");
CHECK ( single64.isFailure, "SURPRISE : Mersenne-Twister 64bit encountered NO glitches under concurrent pressure"); CHECK ( concurr_mers64.isFailure, "SURPRISE : Mersenne-Twister 64bit encountered NO glitches under concurrent pressure");
} }
}; };

View file

@ -69,15 +69,16 @@ namespace test {
public: public:
TestThread() TestThread()
: Thread{"Load Test" : Thread{"Load Test"
,[&]() ,[&, ran=lib::Random{seedFromDefaultGen()}]
() mutable
{ //-STAGE-1------------------------------ { //-STAGE-1------------------------------
localSum = rand() % 1000; // generate local value localSum = ran.i(1000); // generate local value
stage1.fetch_add (localSum); // book in local value stage1.fetch_add (localSum); // book in local value
interThread.sync(); // wait for all other threads to have booked in interThread.sync(); // wait for all other threads to have booked in
//-STAGE-2------------------------------ //-STAGE-2------------------------------
uint sync = stage1; // pick up compounded sum from STAGE-1 uint sync = stage1; // pick up compounded sum from STAGE-1
localSum += rand() % 1000; // add further local value for STAGE-2 localSum += ran.i(1000); // add further local value for STAGE-2
stage2.fetch_add (localSum+sync); // book in both local values and synced sum stage2.fetch_add (localSum+sync); // book in both local values and synced sum
afterThread.sync(); // wait for other threads and supervisor afterThread.sync(); // wait for other threads and supervisor
@ -117,6 +118,8 @@ namespace test {
virtual void virtual void
run (Arg) run (Arg)
{ {
seedRand();
// Launch several TestThread
array<TestThread,NUM_THREADS> threads; array<TestThread,NUM_THREADS> threads;
CHECK (0 == finish); CHECK (0 == finish);

View file

@ -63,6 +63,8 @@ namespace test {
virtual void virtual void
run (Arg) run (Arg)
{ {
seedRand();
auto gen = buildCappedSubSequence(defaultGen);
int contended = 0; int contended = 0;
using Threads = lib::ScopedCollection<ThreadJoinable<>>; using Threads = lib::ScopedCollection<ThreadJoinable<>>;
@ -75,7 +77,7 @@ namespace test {
,[&]{ ,[&]{
for (uint i=0; i<NUM_LOOP; ++i) for (uint i=0; i<NUM_LOOP; ++i)
{ {
uint delay = rand() % 10; uint delay = gen.i(10);
usleep (delay); usleep (delay);
{ {
ClassLock<void> guard; ClassLock<void> guard;
@ -87,7 +89,7 @@ namespace test {
}; };
for (auto& thread : threads) for (auto& thread : threads)
thread.join(); // block until thread terminates thread.join(); // block until thread terminates // @suppress("Return value not evaluated")
CHECK (contended == NUM_THREADS * NUM_LOOP, CHECK (contended == NUM_THREADS * NUM_LOOP,
"ALARM: Lock failed, concurrent modification " "ALARM: Lock failed, concurrent modification "

View file

@ -138,6 +138,8 @@ namespace test {
virtual void virtual void
run (Arg) run (Arg)
{ {
seedRand();
attachNewBusTerm(); attachNewBusTerm();
commandInvocation(); commandInvocation();
captureStateMark(); captureStateMark();
@ -669,17 +671,20 @@ namespace test {
: ThreadJoinable{"BusTerm_test: asynchronous diff mutation" : ThreadJoinable{"BusTerm_test: asynchronous diff mutation"
, [=] , [=]
{ {
uint cnt = rand() % MAX_RAND_BORGS; uint cnt = randGen_.i(MAX_RAND_BORGS);
for (uint i=0; i<cnt; ++i) for (uint i=0; i<cnt; ++i)
{ {
uint delay = rand() % MAX_RAND_DELAY; uint delay = randGen_.i(MAX_RAND_DELAY);
uint id = rand() % MAX_RAND_NUMBS; uint id = randGen_.i(MAX_RAND_NUMBS);
usleep (delay); usleep (delay);
scheduleBorg (id); scheduleBorg (id);
notifyGUI (new BorgGenerator{*this, i}); notifyGUI (new BorgGenerator{*this, i});
} }
}} }}
{ } { }
private:
lib::Random randGen_{lib::seedFromDefaultGen()};
}; };

View file

@ -464,7 +464,7 @@ namespace test {
CHECK (3 == wof.size()); CHECK (3 == wof.size());
while (check < 6'000) while (check < 6'000)
sleep_for(10ms); // .....sufficiently long to count way beyond 10'000 sleep_for(15ms); // .....sufficiently long to count way beyond 10'000
CHECK (check > 6'000); CHECK (check > 6'000);
CHECK (1 == wof.size()); CHECK (1 == wof.size());
} }

View file

@ -133,7 +133,7 @@ namespace test {
Extent& extent{*it}; Extent& extent{*it};
CHECK (10 == extent.size()); CHECK (10 == extent.size());
int num = rand() % 1000; int num = rani(1000);
extent[2] = num; extent[2] = num;
CHECK (num == extent[2]); CHECK (num == extent[2]);
@ -173,7 +173,7 @@ namespace test {
struct Probe struct Probe
{ {
short val; short val;
Probe() : val(1 + rand() % 1000) { } Probe() : val(1 + rani(1000)) { }
~Probe() { val = 0; } ~Probe() { val = 0; }
}; };

View file

@ -7178,10 +7178,10 @@ An Activity is //performed// by invoking its {{{activate(now, ctx)}}} function -
In a similar vein, also ''dependency notifications'' need to happen decoupled from the activity chain from which they originate; thus the Post-mechanism is also used for dispatching notifications. Yet notifications are to be treated specially, since they are directed towards a receiver, which in the standard case is a {{{GATE}}}-Activity and will respond by //decrementing its internal latch.// Consequently, notifications will be sent through the ''λ-post'' -- which operationally re-schedules a continuation as a follow-up job. Receiving such a notification may cause the Gate to become opened; in this case the trigger leads to //activation of the chain// hooked behind the Gate, which at some point typically enters into another calculation job. Otherwise, if the latch (in the Gate) is already zero (or the deadline has passed), nothing happens. Thus the implementation of state transition logic ensures the chain behind a Gate can only be //activated once.// In a similar vein, also ''dependency notifications'' need to happen decoupled from the activity chain from which they originate; thus the Post-mechanism is also used for dispatching notifications. Yet notifications are to be treated specially, since they are directed towards a receiver, which in the standard case is a {{{GATE}}}-Activity and will respond by //decrementing its internal latch.// Consequently, notifications will be sent through the ''λ-post'' -- which operationally re-schedules a continuation as a follow-up job. Receiving such a notification may cause the Gate to become opened; in this case the trigger leads to //activation of the chain// hooked behind the Gate, which at some point typically enters into another calculation job. Otherwise, if the latch (in the Gate) is already zero (or the deadline has passed), nothing happens. Thus the implementation of state transition logic ensures the chain behind a Gate can only be //activated once.//
</pre> </pre>
</div> </div>
<div title="RenderProcess" modifier="Ichthyostega" created="200706190705" modified="202410300145" tags="Rendering operational" changecount="12"> <div title="RenderProcess" modifier="Ichthyostega" created="200706190705" modified="202411010046" tags="Rendering operational" changecount="20">
<pre>At a high level, the Render Process is what „runs“ a playback or render. Using the EngineFaçade, the [[Player]] creates a descriptor for such a process, which notably defines a [[»calculation stream«|CalcStream]] for each individual //data feed// to be produced. To actually implement such an //ongoing stream of timed calculations,// a series of data frames must be produced, for which some source data must be loaded and then individual calculations must be scheduled to work on this data and deliver results within a well defined time window for each frame. Thus, on the implementation level, a {{{CalcStream}}} comprises a pipeline to define [[render jobs|RenderJob]], and a self-repeating re-scheduling mechanism to repeatedly plan and dispatch a //chunk of render jobs// to the [[Scheduler]], which cares to invoke the individual jobs in due time. <pre>At a high level, the Render Process is what „runs“ a playback or render. Using the EngineFaçade, the [[Player]] creates a descriptor for such a process, which notably defines a [[»calculation stream«|CalcStream]] for each individual //data feed// to be produced. To actually implement such an //ongoing stream of timed calculations,// a series of data frames must be produced, for which some source data has to be loaded and then individual calculations will be scheduled to work on this data and deliver results within a well defined time window for each frame. Thus, on the implementation level, a {{{CalcStream}}} comprises a pipeline to define [[render jobs|RenderJob]], and a self-repeating re-scheduling mechanism to repeatedly plan and dispatch a //chunk of render jobs// to the [[Scheduler]], which cares to invoke the individual jobs in due time.
This leads to a even more detailed implementation level of the ''render processing''. Within the [[Session]], the user has defined the »edit« or the definition of the media product as an arrangement of media elements placed and arranged into a [[Timeline]]. A repeatedly-running, demand-driven, compiler-like process in Lumiera (known as [[the Builder|Builder]]) consolidates this [[»high-level definition«|HighLevelModel]] into a [[Fixture]] and an directly attached [[network of Render Nodes|LowLevelModel]]. The Fixture hereby defines a [[segment for each part of the timeline|Segmentation]], which can be represented by a single topology of connected render nodes. So each segment spans a time range, quantised into a range of frames -- and the node network attached below this segment is capable of producing media data for each frame within definition range, when given the actual frame number, and some designation of the actual data feed required at that point. Yet it depends on the circumstances what this »data feed« //actually is;// as a rule, anything which can be produced and consumed as compound will be represented as //a single feed.// The typical video will thus comprise a video feed and a stereo sound feed, while another setup may require to deliver individual sound feeds for the left and right channel, or whatever channel layout the sound system has, and it may require two distinct beamer feeds for the two channels of stereoscopic video. However -- as a general rule of architecture -- the Lumiera Render Engine is tasked to perform //all of the processing work,// up to and including all adaptation steps to reach the desired final result. Thus, for rendering into a media container, only a single feed is required, which can be drawn from an encoder node, which in turn consumes several data feeds for its constituents. This leads to a even more detailed description at implementation level of the ''render processing''. Within the [[Session]], the user has defined the »edit« or the definition of the media product as a collection of media elements placed and arranged into a [[Timeline]]. A repeatedly-running, demand-driven, compiler-like process (in Lumiera known as [[the Builder|Builder]]) consolidates this [[»high-level definition«|HighLevelModel]] into a [[Fixture]] and a [[network of Render Nodes|LowLevelModel]] directly attached below. The Fixture hereby defines a [[segment for each part of the timeline|Segmentation]], which can be represented as a distinct and non-changing topology of connected render nodes. So each segment spans a time range, quantised into a range of frames -- and the node network attached below this segment is capable of producing media data for each frame within definition range, when given the actual frame number, and some designation of the actual data feed required at that point. Yet it depends on the circumstances what this »data feed« //actually is;// as a rule, anything which can be produced and consumed as compound will be represented as //a single feed.// The typical video will thus comprise a video feed and a stereo sound feed, while another setup may require to deliver individual sound feeds for the left and right channel, or whatever channel layout the sound system has, and it may require two distinct beamer feeds for the two channels of stereoscopic video. However -- as a general rule of architecture -- the Lumiera Render Engine is tasked to perform //all of the processing work,// up to and including any adaptation step required to reach the desired final result. Thus, for rendering into a media container, only a single feed is required, which can be drawn from an encoder node, which in turn consumes several data feeds for its constituents.
To summarise this break-down of the rendering process defined thus far, the [[Scheduler]] ''invokes'' individual [[frame render jobs|RenderJob]], each of which defines a set of »coordinates«: To summarise this break-down of the rendering process defined thus far, the [[Scheduler]] ''invokes'' individual [[frame render jobs|RenderJob]], each of which defines a set of »coordinates«:
* an ID of the calculation stream allowing to retrieve the output sink * an ID of the calculation stream allowing to retrieve the output sink

View file

@ -17172,9 +17172,7 @@
</node> </node>
<node CREATED="1563020429008" FOLDED="true" ID="ID_8715605" MODIFIED="1678461929265"> <node CREATED="1563020429008" FOLDED="true" ID="ID_8715605" MODIFIED="1678461929265">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
<b>UIStyle</b>: der &#187;<u><font color="#2f297a">StyleManager</font></u>&#171; <b>UIStyle</b>: der &#187;<u><font color="#2f297a">StyleManager</font></u>&#171;
@ -17672,9 +17670,7 @@
<node CREATED="1625069192432" ID="ID_709423265" MODIFIED="1625069203664" TEXT="macht eigentlich exakt was wir brauchen"/> <node CREATED="1625069192432" ID="ID_709423265" MODIFIED="1625069203664" TEXT="macht eigentlich exakt was wir brauchen"/>
<node CREATED="1625069204446" ID="ID_47523093" MODIFIED="1625069786876" TEXT="aber etwas &#xbb;fest verdrahtet&#xab;"> <node CREATED="1625069204446" ID="ID_47523093" MODIFIED="1625069786876" TEXT="aber etwas &#xbb;fest verdrahtet&#xab;">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<ul> <ul>
<li> <li>
@ -18528,9 +18524,7 @@
</node> </node>
<node CREATED="1664028417616" ID="ID_743592439" MODIFIED="1664028542302" TEXT="idealerweise l&#xe4;&#xdf;t sich das jedoch &#xfc;ber den Parent-Container automatisieren"> <node CREATED="1664028417616" ID="ID_743592439" MODIFIED="1664028542302" TEXT="idealerweise l&#xe4;&#xdf;t sich das jedoch &#xfc;ber den Parent-Container automatisieren">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
...unter der Annahme, da&#223; letzlich eine &quot;invalidation&quot; des Widgets gen&#252;gt, lie&#223;e sich das elegant l&#246;sen, indem der Canvas-Container insgesamt &quot;invalidated&quot; wird. ...unter der Annahme, da&#223; letzlich eine &quot;invalidation&quot; des Widgets gen&#252;gt, lie&#223;e sich das elegant l&#246;sen, indem der Canvas-Container insgesamt &quot;invalidated&quot; wird.
@ -18938,9 +18932,7 @@
<font NAME="SansSerif" SIZE="10"/> <font NAME="SansSerif" SIZE="10"/>
<node COLOR="#33565a" CREATED="1664725557464" ID="ID_1964737255" MODIFIED="1664727540443" TEXT="reduce(Name)? &#x27f9; &#x25a3;"> <node COLOR="#33565a" CREATED="1664725557464" ID="ID_1964737255" MODIFIED="1664727540443" TEXT="reduce(Name)? &#x27f9; &#x25a3;">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
BEDINGUNG: &#916;Name &gt; goal BEDINGUNG: &#916;Name &gt; goal
@ -19604,9 +19596,7 @@
</node> </node>
<node CREATED="1665872631421" ID="ID_102284502" MODIFIED="1665872716207" TEXT="f&#xfc;r das lokale pop-up-Men&#xfc;"> <node CREATED="1665872631421" ID="ID_102284502" MODIFIED="1665872716207" TEXT="f&#xfc;r das lokale pop-up-Men&#xfc;">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
...welches u.U. zwar vom ElementBoxWidget aus eingebunden wird, aber eigentlich auf die Inhalts-Ebene delegiert ...welches u.U. zwar vom ElementBoxWidget aus eingebunden wird, aber eigentlich auf die Inhalts-Ebene delegiert
@ -20738,9 +20728,7 @@
<node CREATED="1480725000029" ID="ID_1586514211" MODIFIED="1518487921080" TEXT="wir steigen stets auf Ebene einer Timeline ein"/> <node CREATED="1480725000029" ID="ID_1586514211" MODIFIED="1518487921080" TEXT="wir steigen stets auf Ebene einer Timeline ein"/>
<node CREATED="1480725012731" ID="ID_9332776" MODIFIED="1576282358097"> <node CREATED="1480725012731" ID="ID_9332776" MODIFIED="1576282358097">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
<i>aber:</i>&#160;Binding im Diff-System durchaus m&#246;glich <i>aber:</i>&#160;Binding im Diff-System durchaus m&#246;glich
@ -23084,9 +23072,7 @@
<node CREATED="1480776087027" ID="ID_132590373" MODIFIED="1518487921082" TEXT="leer zulassen"> <node CREATED="1480776087027" ID="ID_132590373" MODIFIED="1518487921082" TEXT="leer zulassen">
<node CREATED="1480778115091" ID="ID_1948130012" MODIFIED="1576282358080" TEXT="das hei&#xdf;t..."> <node CREATED="1480778115091" ID="ID_1948130012" MODIFIED="1576282358080" TEXT="das hei&#xdf;t...">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
die betreffenden Felder sind echt optional. die betreffenden Felder sind echt optional.
@ -43042,9 +43028,7 @@
<icon BUILTIN="info"/> <icon BUILTIN="info"/>
<node CREATED="1670634343385" ID="ID_284249821" MODIFIED="1670634414906" TEXT="detox(changedMetric) macht nix"> <node CREATED="1670634343385" ID="ID_284249821" MODIFIED="1670634414906" TEXT="detox(changedMetric) macht nix">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
da die Metrik ja limitiert wurde und damit per definitionem auch sauber da die Metrik ja limitiert wurde und damit per definitionem auch sauber
@ -44373,9 +44357,7 @@
<node CREATED="1669994645898" ID="ID_448193400" MODIFIED="1669994655184" TEXT="f2 : der limitierende Gegen-Faktor"/> <node CREATED="1669994645898" ID="ID_448193400" MODIFIED="1669994655184" TEXT="f2 : der limitierende Gegen-Faktor"/>
<node CREATED="1669995461568" ID="ID_1761342962" MODIFIED="1669995622760" TEXT="ist ein Kehrwert"> <node CREATED="1669995461568" ID="ID_1761342962" MODIFIED="1669995622760" TEXT="ist ein Kehrwert">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
aus Gr&#252;nden der Symmetrie kann man das gleiche Argument jeweils auch auf den Kehrwert anwenden, deshalb haben wir ja 4 F&#228;lle (bei zwei Eingangs-Faktoren). Man mu&#223; nur ggfs. dann den Kehrwert vom Ergebnis ausgeben. Beispiel: wir nehmen den Z&#228;hler vom ersten Faktor als Quantisierer. Dann ist f1 der Nenner vom ersten Faktor, und mu&#223; daher auch im Ergebnis im Nenner landen, nicht im Z&#228;hler wie beim regul&#228;ren Schema aus Gr&#252;nden der Symmetrie kann man das gleiche Argument jeweils auch auf den Kehrwert anwenden, deshalb haben wir ja 4 F&#228;lle (bei zwei Eingangs-Faktoren). Man mu&#223; nur ggfs. dann den Kehrwert vom Ergebnis ausgeben. Beispiel: wir nehmen den Z&#228;hler vom ersten Faktor als Quantisierer. Dann ist f1 der Nenner vom ersten Faktor, und mu&#223; daher auch im Ergebnis im Nenner landen, nicht im Z&#228;hler wie beim regul&#228;ren Schema
@ -46248,9 +46230,7 @@
<node CREATED="1523019593833" ID="ID_770462134" MODIFIED="1557498707235" TEXT="ausschlie&#xdf;lich an das UI-Toolkit gebunden"/> <node CREATED="1523019593833" ID="ID_770462134" MODIFIED="1557498707235" TEXT="ausschlie&#xdf;lich an das UI-Toolkit gebunden"/>
<node CREATED="1523019635739" ID="ID_883974404" MODIFIED="1576282358018" TEXT="Einzelfall-Wissen vorausgesetzt"> <node CREATED="1523019635739" ID="ID_883974404" MODIFIED="1576282358018" TEXT="Einzelfall-Wissen vorausgesetzt">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
man mu&#223; die Implementierungs-Details <i>jeder einzelnen Komponente</i>&#160;kennen, man mu&#223; die Implementierungs-Details <i>jeder einzelnen Komponente</i>&#160;kennen,
@ -46497,9 +46477,7 @@
</node> </node>
<node CREATED="1448078731130" ID="ID_1682515267" MODIFIED="1576282358016" TEXT="collapse / expand"> <node CREATED="1448078731130" ID="ID_1682515267" MODIFIED="1576282358016" TEXT="collapse / expand">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
daf&#252;r gen&#252;gt der normale Reset daf&#252;r gen&#252;gt der normale Reset
@ -46671,9 +46649,7 @@
</node> </node>
<node CREATED="1541546692289" ID="ID_189279804" MODIFIED="1541546864673"> <node CREATED="1541546692289" ID="ID_189279804" MODIFIED="1541546864673">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
<b>Identit&#228;t</b>&#160;== Bus-ID <b>Identit&#228;t</b>&#160;== Bus-ID
@ -46779,9 +46755,7 @@
<node CREATED="1535639174623" ID="ID_1755607605" MODIFIED="1535639177466" TEXT="Revealer"> <node CREATED="1535639174623" ID="ID_1755607605" MODIFIED="1535639177466" TEXT="Revealer">
<node CREATED="1535639368981" ID="ID_220149026" MODIFIED="1576282358011"> <node CREATED="1535639368981" ID="ID_220149026" MODIFIED="1576282358011">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
<i>nicht</i>&#160;bool-Testbar <i>nicht</i>&#160;bool-Testbar
@ -56486,7 +56460,7 @@
</node> </node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1710518610461" FOLDED="true" ID="ID_629444459" MODIFIED="1710518761306" TEXT="Zufallszahlen-Sequenzen"> <node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1710518610461" ID="ID_629444459" MODIFIED="1731845694904" TEXT="Zufallszahlen-Sequenzen">
<arrowlink COLOR="#ff0029" DESTINATION="ID_552644754" ENDARROW="Default" ENDINCLINATION="-438;679;" ID="Arrow_ID_440516587" STARTARROW="None" STARTINCLINATION="-377;-45;"/> <arrowlink COLOR="#ff0029" DESTINATION="ID_552644754" ENDARROW="Default" ENDINCLINATION="-438;679;" ID="Arrow_ID_440516587" STARTARROW="None" STARTINCLINATION="-377;-45;"/>
<icon BUILTIN="hourglass"/> <icon BUILTIN="hourglass"/>
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
@ -56504,6 +56478,109 @@
</html></richcontent> </html></richcontent>
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
</node> </node>
<node CREATED="1731845750385" ID="ID_810712062" MODIFIED="1731845774415" TEXT="Abstraktions-Framework">
<node CREATED="1731845775617" ID="ID_1139075257" MODIFIED="1731845790075" TEXT="Basis ist &lt;random&gt;"/>
<node CREATED="1731845922430" ID="ID_1112739568" MODIFIED="1731845927401" TEXT="Anforderungen">
<node CREATED="1731845928234" ID="ID_625386997" MODIFIED="1731845944583" TEXT="soll den eigentlichen Grenerator einh&#xfc;llen/verbergen"/>
<node CREATED="1731845951618" ID="ID_1530478572" MODIFIED="1731846319486" TEXT="Laufzeit-Virtualisierung f&#xfc;r die Seed-Quelle (&#xbb;SeedNucleus&#xab;)">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
es soll m&#246;glich seine, eine opaque Quelle zu &#252;bergeben und erst zur Laufzeit / dynamisch bestimmen, woher der Seed stammt; Entscheidung per late-binding, ob echte Entropie zum Einsatz kommt, oder eine reproduzierbare Sequenz oder gar ein fixierter Wert
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#8f8f94" DESTINATION="ID_597020246" ENDARROW="Default" ENDINCLINATION="112;0;" ID="Arrow_ID_138451619" STARTARROW="None" STARTINCLINATION="107;5;"/>
</node>
<node CREATED="1731846140248" ID="ID_1929928174" MODIFIED="1731846150229" TEXT="Generator-Zustand als Instanz dargestellt"/>
<node CREATED="1731846151719" ID="ID_383905336" MODIFIED="1731846161905" TEXT="es soll einen impliziten default-Generator geben"/>
<node CREATED="1731846177732" ID="ID_1575311077" MODIFIED="1731846190342" TEXT="Generatoren sollen als Baukasten-System zusammenpassen">
<node CREATED="1731846205624" ID="ID_450085518" MODIFIED="1731846212709" TEXT="der default-Generator ist nicht speziell"/>
<node CREATED="1731846213343" ID="ID_1947266937" MODIFIED="1731846219986" TEXT="sondern eine convenience-Abk&#xfc;rzung"/>
</node>
</node>
<node CREATED="1731846233220" ID="ID_1589656875" MODIFIED="1731859613091" TEXT="Struktur">
<linktarget COLOR="#653e3f" DESTINATION="ID_1589656875" ENDARROW="Default" ENDINCLINATION="-142;905;" ID="Arrow_ID_1946206737" SOURCE="ID_676955985" STARTARROW="None" STARTINCLINATION="-388;-943;"/>
<node CREATED="1731846236310" ID="ID_1274731527" MODIFIED="1731846258272" TEXT="Basis-Template: RandomSequencer&lt;GEN&gt;">
<node CREATED="1731846283816" ID="ID_597020246" MODIFIED="1731846307669" TEXT="erzeugt aus SeedNucleus">
<linktarget COLOR="#8f8f94" DESTINATION="ID_597020246" ENDARROW="Default" ENDINCLINATION="112;0;" ID="Arrow_ID_138451619" SOURCE="ID_1530478572" STARTARROW="None" STARTINCLINATION="107;5;"/>
</node>
<node CREATED="1731846325776" ID="ID_324402112" MODIFIED="1731846334634" TEXT="alternativ: an bestehenden Generator angekoppelt"/>
<node CREATED="1731846395814" ID="ID_516539220" MODIFIED="1731846401666" TEXT="bietet direkt die Distributionen"/>
<node CREATED="1731857185006" ID="ID_1418948099" MODIFIED="1731857215216" TEXT="ist kopierbar und zuweisbar">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das ist ein Feature; man kann damit einen State speichern
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1731846402711" ID="ID_95043178" MODIFIED="1731846405385" TEXT="Distributionen">
<node CREATED="1731846489994" ID="ID_1252503451" MODIFIED="1731849013246" TEXT="integral">
<node CREATED="1731847162312" ID="ID_1919361587" MODIFIED="1731849022407" TEXT="Problem: Systematik f&#xfc;r die Grenzen">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1731847172007" ID="ID_1895536886" MODIFIED="1731847189328" TEXT="die STL macht beide Grenzen inclusiv">
<node CREATED="1731847666829" ID="ID_1876315451" MODIFIED="1731847672488" TEXT="aber nur f&#xfc;r Int-Distributionen"/>
<node CREATED="1731847673039" ID="ID_1584529207" MODIFIED="1731847681847" TEXT="f&#xfc;r Real-Distributionen ist die Obergrenze exclusiv"/>
</node>
<node CREATED="1731847190884" ID="ID_32994635" MODIFIED="1731847232730" TEXT="das ist &#xfc;berraschend / anders als rand()">
<node CREATED="1731847236786" ID="ID_1776740877" MODIFIED="1731847549026" TEXT="RAND_MAX &#x2261; 2^31 - 1"/>
<node CREATED="1731847551063" ID="ID_535434671" MODIFIED="1731847575965" TEXT="der Modulo-Trick erzeugt ebenfalls eine exclusive Obergrenze"/>
</node>
<node CREATED="1731847746013" ID="ID_1233650660" MODIFIED="1731847764663" TEXT="f&#xfc;r symmetrische und negative Wertbereiche w&#xe4;re das nat&#xfc;rlicher">
<node CREATED="1731847770056" ID="ID_477206568" MODIFIED="1731847788450" TEXT="aber diese treten erfahrungsgem&#xe4;&#xdf; selten auf"/>
<node CREATED="1731847789037" ID="ID_1733989680" MODIFIED="1731847797690" TEXT="wenn aber, sind sie stets verwirrend"/>
</node>
<node CREATED="1731847856612" ID="ID_1280577122" MODIFIED="1731847869366" TEXT="&#x27f9; das impliziert zwei Alternativen">
<node CREATED="1731847870455" ID="ID_1852724066" MODIFIED="1731847886660" TEXT="Untergrenze auf 0 fixieren und daf&#xfc;r die Obergrenze exclusiv"/>
<node CREATED="1731847888080" ID="ID_440496049" MODIFIED="1731847906945" TEXT="beide Grenzen konfigurierbar wie in der STL"/>
</node>
</node>
<node CREATED="1731851659080" ID="ID_527349814" MODIFIED="1731851691975" TEXT="Beschlu&#xdf;">
<node CREATED="1731851693013" ID="ID_1567706947" MODIFIED="1731851703374" TEXT="ich lege den auf int fest"/>
<node CREATED="1731851729695" ID="ID_288388982" MODIFIED="1731851739457" TEXT="[0 ... bound["/>
<node CREATED="1731851755307" ID="ID_670828588" MODIFIED="1731851762654" TEXT="Kurzer Name: i(bound)"/>
</node>
</node>
<node CREATED="1731847925115" ID="ID_1352182688" MODIFIED="1731848031027" TEXT="Design-Problem: Generator nicht zug&#xe4;nglich">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1731847939633" ID="ID_1582419047" MODIFIED="1731847956603" TEXT="ich m&#xf6;chte den (Roh)-Generator einpacken/verbergen"/>
<node CREATED="1731847957263" ID="ID_826907399" MODIFIED="1731847973232" TEXT="die STL geht (wie immer) genau den entgegengesetzten Weg"/>
<node CREATED="1731848012640" ID="ID_765417053" MODIFIED="1731848028489" TEXT="ein Grad an Kombinierbarkeit w&#xe4;re aber w&#xfc;nschenswert"/>
</node>
<node CREATED="1731848096704" ID="ID_322995053" MODIFIED="1731848105884" TEXT="Ausweg: generischer Zugang">
<icon BUILTIN="idea"/>
<node CREATED="1731848107195" ID="ID_969349228" MODIFIED="1731848118742" TEXT="distibute(DIST)">
<node CREATED="1731848122108" ID="ID_1399116407" MODIFIED="1731848139610" TEXT="nimmt ein Standard-Distribution-Object by-value"/>
<node CREATED="1731848140391" ID="ID_1345070881" MODIFIED="1731848166747" TEXT="zieht eine Zufallszahl und speist sie in dieses Objekt ein"/>
</node>
</node>
<node CREATED="1731851768409" ID="ID_64324165" MODIFIED="1731859635648" TEXT="Namen">
<icon BUILTIN="forward"/>
<node COLOR="#435e98" CREATED="1731851774145" ID="ID_357370370" MODIFIED="1731859631999" TEXT="distribute(DIST) : Basis-Impl: beliebige Dist"/>
<node COLOR="#435e98" CREATED="1731851801486" ID="ID_1612337960" MODIFIED="1731859631999" TEXT="i(bound) : drop-in-replacement f&#xfc;r rand()"/>
<node COLOR="#435e98" CREATED="1731851830060" ID="ID_944802289" MODIFIED="1731859631999" TEXT="i32() : voller Int-Bereich (incl. negative Zahlen)"/>
<node COLOR="#435e98" CREATED="1731851845839" ID="ID_1551621955" MODIFIED="1731859631998" TEXT="u64() : voller 64bit unsigned-Bereich"/>
<node COLOR="#435e98" CREATED="1731851888705" ID="ID_1032848952" MODIFIED="1731859631998" TEXT="uni() : uniform range [0 ... 1.0["/>
<node COLOR="#435e98" CREATED="1731851862876" ID="ID_1931647655" MODIFIED="1731859631998" TEXT="range(start, bound) : uniform range (double)"/>
<node COLOR="#435e98" CREATED="1731851915120" ID="ID_673952544" MODIFIED="1731859631997" TEXT="normal(mean, stdev) : Gau&#xdf;"/>
</node>
</node>
<node CREATED="1731851980917" ID="ID_915379812" MODIFIED="1731851987128" TEXT="convenience-free-functions">
<node COLOR="#435e98" CREATED="1731851988079" ID="ID_987128085" MODIFIED="1731859641027" TEXT="rani(bound) &#x27fc; defaultGen.i(bound)"/>
<node COLOR="#435e98" CREATED="1731852026551" ID="ID_122801033" MODIFIED="1731859641028" TEXT="ranRange &#x27fc; defaultGen.range"/>
<node COLOR="#435e98" CREATED="1731852036647" ID="ID_193693602" MODIFIED="1731859641028" TEXT="ranNormal &#x27fc; defaultGen.normal"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1731845842485" ID="ID_31813522" MODIFIED="1731859652771" TEXT="vorl&#xe4;ufige Einrichtung f&#xfc;r Tests....">
<arrowlink COLOR="#1a30c0" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="-284;-1132;" ID="Arrow_ID_1665212260" STARTARROW="None" STARTINCLINATION="-287;22;"/>
<icon BUILTIN="button_ok"/>
</node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1701698319632" ID="ID_883682364" MODIFIED="1701699545121" TEXT="Hash-Berechnung"> <node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1701698319632" ID="ID_883682364" MODIFIED="1701699545121" TEXT="Hash-Berechnung">
@ -57008,9 +57085,10 @@
<node COLOR="#435e98" CREATED="1729979325607" ID="ID_677674501" MODIFIED="1729979344958" TEXT="useFrameTable"/> <node COLOR="#435e98" CREATED="1729979325607" ID="ID_677674501" MODIFIED="1729979344958" TEXT="useFrameTable"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1730904143330" ID="ID_25783469" MODIFIED="1731205578435" TEXT="#1378 controlled random seed for tests"> <node COLOR="#338800" CREATED="1730904143330" ID="ID_25783469" MODIFIED="1731864866245" TEXT="#1378 controlled random seed for tests">
<linktarget COLOR="#c4145f" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" SOURCE="ID_1500320757" STARTARROW="None" STARTINCLINATION="1769;146;"/> <linktarget COLOR="#4514c4" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" SOURCE="ID_1500320757" STARTARROW="None" STARTINCLINATION="1769;146;"/>
<icon BUILTIN="pencil"/> <linktarget COLOR="#1a30c0" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="-284;-1132;" ID="Arrow_ID_1665212260" SOURCE="ID_31813522" STARTARROW="None" STARTINCLINATION="-287;22;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1730931170413" HGAP="34" ID="ID_480480032" MODIFIED="1731119671920" TEXT="diverse Zweifel &lt;random&gt; betreffend" VSHIFT="44"> <node CREATED="1730931170413" HGAP="34" ID="ID_480480032" MODIFIED="1731119671920" TEXT="diverse Zweifel &lt;random&gt; betreffend" VSHIFT="44">
<arrowlink COLOR="#968bb0" DESTINATION="ID_607929754" ENDARROW="Default" ENDINCLINATION="-1401;152;" ID="Arrow_ID_682771755" STARTARROW="None" STARTINCLINATION="-1300;91;"/> <arrowlink COLOR="#968bb0" DESTINATION="ID_607929754" ENDARROW="Default" ENDINCLINATION="-1401;152;" ID="Arrow_ID_682771755" STARTARROW="None" STARTINCLINATION="-1300;91;"/>
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
@ -57279,7 +57357,7 @@
</node> </node>
</node> </node>
</node> </node>
<node CREATED="1731186827432" FOLDED="true" ID="ID_1343084270" MODIFIED="1731447211350" TEXT="nested Helper-Klassen f&#xfc;r Distributionen"> <node CREATED="1731186827432" FOLDED="true" ID="ID_1343084270" MODIFIED="1731844352255" TEXT="nested Helper-Klassen f&#xfc;r Distributionen">
<node CREATED="1731186885784" ID="ID_1137186891" MODIFIED="1731186909601" TEXT="sie bekommen optional einen Generator als ctor-Argument"/> <node CREATED="1731186885784" ID="ID_1137186891" MODIFIED="1731186909601" TEXT="sie bekommen optional einen Generator als ctor-Argument"/>
<node CREATED="1731186910274" ID="ID_1712434077" MODIFIED="1731186920709" TEXT="oder h&#xe4;ngen sich ansonsten an den default-Generator"/> <node CREATED="1731186910274" ID="ID_1712434077" MODIFIED="1731186920709" TEXT="oder h&#xe4;ngen sich ansonsten an den default-Generator"/>
<node CREATED="1731186949918" ID="ID_1074918802" MODIFIED="1731187011177" TEXT="man k&#xf6;nnte das sp&#xe4;ter in ein Generatoren-Framework ausbauen"> <node CREATED="1731186949918" ID="ID_1074918802" MODIFIED="1731187011177" TEXT="man k&#xf6;nnte das sp&#xe4;ter in ein Generatoren-Framework ausbauen">
@ -57350,7 +57428,7 @@
</node> </node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731424663557" ID="ID_1548490877" MODIFIED="1731447240469" TEXT="std::rand() ersetzen"> <node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1731424663557" ID="ID_1548490877" MODIFIED="1731864831498" TEXT="std::rand() ersetzen">
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
<node COLOR="#435e98" CREATED="1731424676911" ID="ID_432733421" MODIFIED="1731447182287" TEXT="was wird ben&#xf6;tigt?"> <node COLOR="#435e98" CREATED="1731424676911" ID="ID_432733421" MODIFIED="1731447182287" TEXT="was wird ben&#xf6;tigt?">
<font NAME="SansSerif" SIZE="12"/> <font NAME="SansSerif" SIZE="12"/>
@ -57437,7 +57515,8 @@
<node COLOR="#5b280f" CREATED="1731434364363" ID="ID_202795829" MODIFIED="1731434407298" TEXT="ranu und runi werden entfernt (zu sonderbar....)"> <node COLOR="#5b280f" CREATED="1731434364363" ID="ID_202795829" MODIFIED="1731434407298" TEXT="ranu und runi werden entfernt (zu sonderbar....)">
<icon BUILTIN="stop-sign"/> <icon BUILTIN="stop-sign"/>
</node> </node>
<node CREATED="1731434034464" ID="ID_676955985" MODIFIED="1731434037208" TEXT="convenience"> <node CREATED="1731434034464" ID="ID_676955985" MODIFIED="1731859620136" TEXT="convenience">
<arrowlink COLOR="#653e3f" DESTINATION="ID_1589656875" ENDARROW="Default" ENDINCLINATION="-142;905;" ID="Arrow_ID_1946206737" STARTARROW="None" STARTINCLINATION="-388;-943;"/>
<node CREATED="1731434572056" ID="ID_1921841184" MODIFIED="1731434593712" TEXT="ranHash() &#x2260; 0"/> <node CREATED="1731434572056" ID="ID_1921841184" MODIFIED="1731434593712" TEXT="ranHash() &#x2260; 0"/>
<node CREATED="1731434043756" ID="ID_1935715464" MODIFIED="1731434328260" TEXT="ranRange(u,o) : double &#x2208; [u ... o[ "/> <node CREATED="1731434043756" ID="ID_1935715464" MODIFIED="1731434328260" TEXT="ranRange(u,o) : double &#x2208; [u ... o[ "/>
<node CREATED="1731434161079" ID="ID_1433291868" MODIFIED="1731434333379" TEXT="ranNormal(&#x3bc; &#x2254;0.0, &#x3c3; &#x2254; 1.0) : Gau&#xdf;"/> <node CREATED="1731434161079" ID="ID_1433291868" MODIFIED="1731434333379" TEXT="ranNormal(&#x3bc; &#x2254;0.0, &#x3c3; &#x2254; 1.0) : Gau&#xdf;"/>
@ -57448,8 +57527,8 @@
</node> </node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1731434498664" ID="ID_33884738" MODIFIED="1731447066871" TEXT="Umstellung"> <node COLOR="#338800" CREATED="1731434498664" ID="ID_33884738" MODIFIED="1731864797092" TEXT="Umstellung">
<icon BUILTIN="pencil"/> <icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1731434503085" ID="ID_779294881" MODIFIED="1731447063509" TEXT="API-Umstellungen"> <node COLOR="#338800" CREATED="1731434503085" ID="ID_779294881" MODIFIED="1731447063509" TEXT="API-Umstellungen">
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
</node> </node>
@ -57462,7 +57541,7 @@
<node COLOR="#338800" CREATED="1731434548714" ID="ID_1401652131" MODIFIED="1731466845015" TEXT="rand() % MAX abl&#xf6;sen in Tests"> <node COLOR="#338800" CREATED="1731434548714" ID="ID_1401652131" MODIFIED="1731466845015" TEXT="rand() % MAX abl&#xf6;sen in Tests">
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
</node> </node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1731466845496" ID="ID_108595980" MODIFIED="1731466860399" TEXT="Tests scheitern nach Umstellung"> <node BACKGROUND_COLOR="#c8c0b6" COLOR="#690f14" CREATED="1731466845496" ID="ID_108595980" MODIFIED="1731864819581" TEXT="Tests scheitern nach Umstellung">
<icon BUILTIN="broken-line"/> <icon BUILTIN="broken-line"/>
<node COLOR="#435e98" CREATED="1731466868785" ID="ID_1204988400" MODIFIED="1731516821863" TEXT="Rational_test"> <node COLOR="#435e98" CREATED="1731466868785" ID="ID_1204988400" MODIFIED="1731516821863" TEXT="Rational_test">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
@ -58018,15 +58097,48 @@
<arrowlink COLOR="#73384b" DESTINATION="ID_1574698883" ENDARROW="Default" ENDINCLINATION="-9;41;" ID="Arrow_ID_1250752825" STARTARROW="None" STARTINCLINATION="34;4;"/> <arrowlink COLOR="#73384b" DESTINATION="ID_1574698883" ENDARROW="Default" ENDINCLINATION="-9;41;" ID="Arrow_ID_1250752825" STARTARROW="None" STARTINCLINATION="34;4;"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731455444796" ID="ID_784243083" MODIFIED="1731455723202" TEXT="Concurrent Tests umstellen"> <node COLOR="#338800" CREATED="1731455444796" ID="ID_784243083" MODIFIED="1731864793958" TEXT="Concurrent Tests umstellen">
<icon BUILTIN="bell"/> <icon BUILTIN="button_ok"/>
<node CREATED="1731728363475" ID="ID_1473702684" MODIFIED="1731728367146" TEXT="problematisch"> <node BACKGROUND_COLOR="#c8c0b6" CREATED="1731728363475" ID="ID_1473702684" MODIFIED="1731864804416" TEXT="problematisch">
<node CREATED="1731455475587" ID="ID_1622000187" MODIFIED="1731455475587" TEXT="CallQueue_test"/> <icon BUILTIN="info"/>
<node CREATED="1731455716786" ID="ID_943344715" MODIFIED="1731455716786" TEXT="DiagnosticContext_test"/> <node COLOR="#338800" CREATED="1731455716786" ID="ID_943344715" MODIFIED="1731864212381" TEXT="DiagnosticContext_test">
<node CREATED="1731458234804" ID="ID_1185469440" MODIFIED="1731458234804" TEXT="SessionCommandFunction_test"/> <icon BUILTIN="button_ok"/>
<node CREATED="1731461928260" ID="ID_396786983" MODIFIED="1731461928260" TEXT="IncidenceCount_test"/> <node COLOR="#435e98" CREATED="1731864232690" ID="ID_409271060" MODIFIED="1731864262374" TEXT="brauche nur einen Zufallswert &#x27f6; in die Closure binden">
<node CREATED="1731464404973" ID="ID_1534599775" MODIFIED="1731464404973" TEXT="SyncBarrier_test"/> <font NAME="SansSerif" SIZE="10"/>
<node CREATED="1731464450346" ID="ID_1959292193" MODIFIED="1731464450346" TEXT="SyncClasslock_test"/> </node>
</node>
<node COLOR="#338800" CREATED="1731455475587" ID="ID_1622000187" MODIFIED="1731860003292" TEXT="CallQueue_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731861101886" HGAP="31" ID="ID_784906746" MODIFIED="1731864290533" TEXT="(Generator-Objekt in jeden Thread)" VSHIFT="2">
<arrowlink DESTINATION="ID_1185469440" ENDARROW="Default" ENDINCLINATION="57;5;" ID="Arrow_ID_403753001" STARTARROW="None" STARTINCLINATION="5;28;"/>
<arrowlink DESTINATION="ID_396786983" ENDARROW="Default" ENDINCLINATION="123;15;" ID="Arrow_ID_609954343" STARTARROW="None" STARTINCLINATION="0;41;"/>
<arrowlink DESTINATION="ID_1534599775" ENDARROW="Default" ENDINCLINATION="115;16;" ID="Arrow_ID_439192060" STARTARROW="None" STARTINCLINATION="12;89;"/>
<arrowlink DESTINATION="ID_444907234" ENDARROW="Default" ENDINCLINATION="43;7;" ID="Arrow_ID_259642088" STARTARROW="None" STARTINCLINATION="-8;32;"/>
<font NAME="SansSerif" SIZE="11"/>
</node>
</node>
<node COLOR="#338800" CREATED="1731465663005" ID="ID_444907234" MODIFIED="1731864283742" TEXT="BusTerm_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_444907234" ENDARROW="Default" ENDINCLINATION="43;7;" ID="Arrow_ID_259642088" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="-8;32;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731458234804" ID="ID_1185469440" MODIFIED="1731864290533" TEXT="SessionCommandFunction_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1185469440" ENDARROW="Default" ENDINCLINATION="57;5;" ID="Arrow_ID_403753001" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="5;28;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731461928260" ID="ID_396786983" MODIFIED="1731863340988" TEXT="IncidenceCount_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_396786983" ENDARROW="Default" ENDINCLINATION="123;15;" ID="Arrow_ID_609954343" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="0;41;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731464404973" ID="ID_1534599775" MODIFIED="1731863360009" TEXT="SyncBarrier_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1534599775" ENDARROW="Default" ENDINCLINATION="115;16;" ID="Arrow_ID_439192060" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="12;89;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731464450346" ID="ID_1959292193" MODIFIED="1731863580125" TEXT="SyncClasslock_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731863556524" HGAP="27" ID="ID_708525528" MODIFIED="1731863570931" TEXT="use shared capped generator" VSHIFT="8">
<font NAME="SansSerif" SIZE="11"/>
</node>
</node>
<node COLOR="#5b280f" CREATED="1731464565589" ID="ID_864840738" MODIFIED="1731464568650" TEXT="SyncLocking_test"> <node COLOR="#5b280f" CREATED="1731464565589" ID="ID_864840738" MODIFIED="1731464568650" TEXT="SyncLocking_test">
<icon BUILTIN="button_cancel"/> <icon BUILTIN="button_cancel"/>
<node COLOR="#435e98" CREATED="1731464569588" HGAP="21" ID="ID_473912166" MODIFIED="1731464596488" TEXT="nein: der ist sauber" VSHIFT="1"> <node COLOR="#435e98" CREATED="1731464569588" HGAP="21" ID="ID_473912166" MODIFIED="1731464596488" TEXT="nein: der ist sauber" VSHIFT="1">
@ -58047,9 +58159,8 @@
<node CREATED="1731464903922" ID="ID_349618800" MODIFIED="1731464903922" TEXT="ThreadWrapperJoin_test"/> <node CREATED="1731464903922" ID="ID_349618800" MODIFIED="1731464903922" TEXT="ThreadWrapperJoin_test"/>
</node> </node>
</node> </node>
<node CREATED="1731465663005" ID="ID_444907234" MODIFIED="1731465663005" TEXT="BusTerm_test"/>
</node> </node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1731728379707" ID="ID_38959317" MODIFIED="1731728399492" TEXT="gibt es &#xfc;berhaupt ein Problem hier?"> <node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1731728379707" ID="ID_38959317" MODIFIED="1731809589226" TEXT="gibt es &#xfc;berhaupt ein Problem hier?">
<icon BUILTIN="help"/> <icon BUILTIN="help"/>
<node CREATED="1731728402020" ID="ID_216802866" MODIFIED="1731728433241" TEXT="theoretisch ist PRNG nicht thread-safe"/> <node CREATED="1731728402020" ID="ID_216802866" MODIFIED="1731728433241" TEXT="theoretisch ist PRNG nicht thread-safe"/>
<node CREATED="1731728433837" ID="ID_975708385" MODIFIED="1731728441330" TEXT="aber ... was kann schon passieren??"/> <node CREATED="1731728433837" ID="ID_975708385" MODIFIED="1731728441330" TEXT="aber ... was kann schon passieren??"/>
@ -58058,9 +58169,7 @@
<node CREATED="1731753438455" ID="ID_518457223" MODIFIED="1731753543440" TEXT="tats&#xe4;chlich auf meiner Maschine ist das unm&#xf6;glich (ulong &#x2261; uint64_t)"/> <node CREATED="1731753438455" ID="ID_518457223" MODIFIED="1731753543440" TEXT="tats&#xe4;chlich auf meiner Maschine ist das unm&#xf6;glich (ulong &#x2261; uint64_t)"/>
<node CREATED="1731753607692" ID="ID_759994737" MODIFIED="1731753666983" TEXT="man k&#xf6;nnte das aber mit der &#xbb;kleinen&#xab; mersenne-Engine mt19937 untersuchen"> <node CREATED="1731753607692" ID="ID_759994737" MODIFIED="1731753666983" TEXT="man k&#xf6;nnte das aber mit der &#xbb;kleinen&#xab; mersenne-Engine mt19937 untersuchen">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
diese verwendet uint_fast32_t, das aber auf meinem System ebenfalls auf unit64_t gemapped ist diese verwendet uint_fast32_t, das aber auf meinem System ebenfalls auf unit64_t gemapped ist
@ -58071,9 +58180,8 @@
<icon BUILTIN="idea"/> <icon BUILTIN="idea"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1731728584572" ID="ID_1568853077" MODIFIED="1731728594906" TEXT="empirisch untersuchen"> <node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1731728584572" FOLDED="true" ID="ID_1568853077" MODIFIED="1731809658435" TEXT="empirisch untersuchen">
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
<icon BUILTIN="pencil"/>
<node CREATED="1731728599474" ID="ID_1952720762" MODIFIED="1731728615563" TEXT="mit allen Cores parallel Zufallszahlen ziehen"/> <node CREATED="1731728599474" ID="ID_1952720762" MODIFIED="1731728615563" TEXT="mit allen Cores parallel Zufallszahlen ziehen"/>
<node CREATED="1731728616535" ID="ID_59784960" MODIFIED="1731728640632" TEXT="einzelne Zahlen pr&#xfc;fen"/> <node CREATED="1731728616535" ID="ID_59784960" MODIFIED="1731728640632" TEXT="einzelne Zahlen pr&#xfc;fen"/>
<node CREATED="1731728641175" ID="ID_177314578" MODIFIED="1731728668212" TEXT="MIttelwert pr&#xfc;fen (bias)"/> <node CREATED="1731728641175" ID="ID_177314578" MODIFIED="1731728668212" TEXT="MIttelwert pr&#xfc;fen (bias)"/>
@ -58109,7 +58217,7 @@
<node CREATED="1731775985924" ID="ID_1953980277" MODIFIED="1731776143208" TEXT="sollte bei einer &#xbb;gesunden&#xab; Verteilung unter 30% liegen"/> <node CREATED="1731775985924" ID="ID_1953980277" MODIFIED="1731776143208" TEXT="sollte bei einer &#xbb;gesunden&#xab; Verteilung unter 30% liegen"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1731776150715" ID="ID_692908068" MODIFIED="1731776206608" TEXT="3. Test mit diversen Varianten &#x27f9; alle Generatoren betroffen"> <node BACKGROUND_COLOR="#e7c745" COLOR="#9b114a" CREATED="1731776150715" ID="ID_692908068" MODIFIED="1731809637025" TEXT="3. Test mit diversen Varianten &#x27f9; alle Generatoren betroffen">
<icon BUILTIN="stop-sign"/> <icon BUILTIN="stop-sign"/>
<node CREATED="1731776233760" ID="ID_47841503" MODIFIED="1731776309786" TEXT="sobald wir concurrent zugreifen, ist die Verteilung gest&#xf6;rt"> <node CREATED="1731776233760" ID="ID_47841503" MODIFIED="1731776309786" TEXT="sobald wir concurrent zugreifen, ist die Verteilung gest&#xf6;rt">
<icon BUILTIN="forward"/> <icon BUILTIN="forward"/>
@ -58127,9 +58235,7 @@
</node> </node>
<node CREATED="1731777433204" ID="ID_1308403781" MODIFIED="1731777549795" TEXT="...die Inzidenz h&#xe4;ngt stark von Umst&#xe4;nden ab"> <node CREATED="1731777433204" ID="ID_1308403781" MODIFIED="1731777549795" TEXT="...die Inzidenz h&#xe4;ngt stark von Umst&#xe4;nden ab">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
schon kleine &#196;nderungen in der Payload-Funktion k&#246;nnen die Inzidenz der Probleme drastisch &#228;ndern; beispielsweise hat das Hinzuf&#252;gen einer Begrenzung per Modulo f&#252;r einen Generator die Inzidenz drastisch erh&#246;ht, f&#252;r einen anderen die Probleme nahezu zum Verschwinden gebracht schon kleine &#196;nderungen in der Payload-Funktion k&#246;nnen die Inzidenz der Probleme drastisch &#228;ndern; beispielsweise hat das Hinzuf&#252;gen einer Begrenzung per Modulo f&#252;r einen Generator die Inzidenz drastisch erh&#246;ht, f&#252;r einen anderen die Probleme nahezu zum Verschwinden gebracht
@ -58147,16 +58253,22 @@
<node CREATED="1731777687774" ID="ID_1782576024" MODIFIED="1731777736651" TEXT="da zudem eine direkte Kollision nicht so h&#xe4;ufig ist, kann man die Thematik u.U. dann ignorieren"/> <node CREATED="1731777687774" ID="ID_1782576024" MODIFIED="1731777736651" TEXT="da zudem eine direkte Kollision nicht so h&#xe4;ufig ist, kann man die Thematik u.U. dann ignorieren"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1731781569046" ID="ID_1384257142" MODIFIED="1731781583030" TEXT="diese Me&#xdf;-Anordnung in einen sch&#xf6;nen Test verpacken...."> <node COLOR="#338800" CREATED="1731781569046" ID="ID_1384257142" MODIFIED="1731809512163" TEXT="diese Me&#xdf;-Anordnung in einen sch&#xf6;nen Test verpacken....">
<icon BUILTIN="pencil"/> <icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1731781586201" ID="ID_239188866" MODIFIED="1731781593281" TEXT="tabellarische Ausgabe"> <node COLOR="#338800" CREATED="1731781586201" ID="ID_239188866" MODIFIED="1731781593281" TEXT="tabellarische Ausgabe">
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
</node> </node>
<node COLOR="#338800" CREATED="1731781594017" ID="ID_951906840" MODIFIED="1731781601504" TEXT="Statistik automatisch bewerten"> <node COLOR="#338800" CREATED="1731781594017" ID="ID_951906840" MODIFIED="1731781601504" TEXT="Statistik automatisch bewerten">
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
</node> </node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731781602363" ID="ID_1537588023" MODIFIED="1731781608615" TEXT="kommentieren / erl&#xe4;utern"> <node COLOR="#338800" CREATED="1731809497409" ID="ID_1000378102" MODIFIED="1731809509830" TEXT="bei der Gelegenheit auch ein Benchmark">
<icon BUILTIN="flag-pink"/> <icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731809518948" ID="ID_1436222406" MODIFIED="1731809569847" TEXT="std::rand: 15ns | 19ns (O3)"/>
<node COLOR="#435e98" CREATED="1731809534065" ID="ID_110429664" MODIFIED="1731809569849" TEXT="mersenne: 45ns | 25ns"/>
<node COLOR="#435e98" CREATED="1731809551526" ID="ID_1283714600" MODIFIED="1731809569849" TEXT="/dev/urandom: 480ns stets"/>
</node>
<node COLOR="#338800" CREATED="1731781602363" ID="ID_1537588023" MODIFIED="1731809510922" TEXT="kommentieren / erl&#xe4;utern">
<icon BUILTIN="button_ok"/>
</node> </node>
</node> </node>
<node CREATED="1731777769395" ID="ID_1256945696" MODIFIED="1731781639135" TEXT="es gibt also drei Ans&#xe4;tze"> <node CREATED="1731777769395" ID="ID_1256945696" MODIFIED="1731781639135" TEXT="es gibt also drei Ans&#xe4;tze">
@ -58172,8 +58284,8 @@
<font ITALIC="true" NAME="SansSerif" SIZE="14"/> <font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731781708768" ID="ID_819976783" MODIFIED="1731781729751" TEXT="Konsequenz &#x27f9; Template bereitstellen"> <node COLOR="#338800" CREATED="1731781708768" ID="ID_819976783" MODIFIED="1731809667057" TEXT="Konsequenz &#x27f9; Template bereitstellen">
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="button_ok"/>
</node> </node>
</node> </node>
<node CREATED="1731777778369" ID="ID_689903625" MODIFIED="1731781689836" TEXT="jedem Thread wirklich seinen eigenen Generator geben"> <node CREATED="1731777778369" ID="ID_689903625" MODIFIED="1731781689836" TEXT="jedem Thread wirklich seinen eigenen Generator geben">
@ -92682,7 +92794,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#77313e" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="381;-48;" ID="Arrow_ID_1047269362" SOURCE="ID_936086670" STARTARROW="None" STARTINCLINATION="-36;80;"/> <linktarget COLOR="#77313e" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="381;-48;" ID="Arrow_ID_1047269362" SOURCE="ID_936086670" STARTARROW="None" STARTINCLINATION="-36;80;"/>
<linktarget COLOR="#6f2328" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="366;-47;" ID="Arrow_ID_1067356199" SOURCE="ID_683548249" STARTARROW="None" STARTINCLINATION="5;52;"/> <linktarget COLOR="#6f2328" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="366;-47;" ID="Arrow_ID_1067356199" SOURCE="ID_683548249" STARTARROW="None" STARTINCLINATION="5;52;"/>
<icon BUILTIN="pencil"/> <icon BUILTIN="pencil"/>
<node CREATED="1730900637026" ID="ID_1500320757" MODIFIED="1730904275397" TEXT="brauche Einflu&#xdf; auf den PRNG"> <node CREATED="1730900637026" ID="ID_1500320757" MODIFIED="1731864860121" TEXT="brauche Einflu&#xdf; auf den PRNG">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head/> <head/>
<body> <body>
@ -92691,7 +92803,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</p> </p>
</body> </body>
</html></richcontent> </html></richcontent>
<arrowlink COLOR="#c4145f" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" STARTARROW="None" STARTINCLINATION="1769;146;"/> <arrowlink COLOR="#4514c4" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" STARTARROW="None" STARTINCLINATION="1769;146;"/>
</node> </node>
<node CREATED="1730900645921" ID="ID_1469990348" MODIFIED="1730901263434" TEXT="brauche Umstellung des Headers"> <node CREATED="1730900645921" ID="ID_1469990348" MODIFIED="1730901263434" TEXT="brauche Umstellung des Headers">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
@ -139082,15 +139194,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1710186359368" ID="ID_765629285" MODIFIED="1710186365813" TEXT="Info"> <node CREATED="1710186359368" ID="ID_765629285" MODIFIED="1710186365813" TEXT="Info">
<icon BUILTIN="info"/> <icon BUILTIN="info"/>
<node CREATED="1710186277136" ID="ID_336649935" LINK="https://en.cppreference.com/w/cpp/numeric/random" MODIFIED="1710186690629" TEXT="Standard-Lib: (pseudo)-random number generation"/> <node CREATED="1710186277136" ID="ID_336649935" LINK="https://en.cppreference.com/w/cpp/numeric/random" MODIFIED="1710186690629" TEXT="Standard-Lib: (pseudo)-random number generation"/>
<node CREATED="1730916530347" FOLDED="true" ID="ID_607929754" MODIFIED="1731115515196" TEXT="Probleme / Diskussion"> <node CREATED="1730916530347" FOLDED="true" ID="ID_607929754" MODIFIED="1731868515865" TEXT="Probleme / Diskussion">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
&#160;
</p>
</body>
</html></richcontent>
<linktarget COLOR="#968bb0" DESTINATION="ID_607929754" ENDARROW="Default" ENDINCLINATION="-1401;152;" ID="Arrow_ID_682771755" SOURCE="ID_480480032" STARTARROW="None" STARTINCLINATION="-1300;91;"/> <linktarget COLOR="#968bb0" DESTINATION="ID_607929754" ENDARROW="Default" ENDINCLINATION="-1401;152;" ID="Arrow_ID_682771755" SOURCE="ID_480480032" STARTARROW="None" STARTINCLINATION="-1300;91;"/>
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
<node CREATED="1730916541434" ID="ID_1186515484" MODIFIED="1730916550532" TEXT="nicht klar wie man &#xbb;korrekt&#xab; seeded"> <node CREATED="1730916541434" ID="ID_1186515484" MODIFIED="1730916550532" TEXT="nicht klar wie man &#xbb;korrekt&#xab; seeded">
@ -139169,11 +139273,16 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1730923153709" ID="ID_1131418575" LINK="https://www.reddit.com/r/cpp/comments/ecrnjl/can_we_do_better_than_the_mersenne_twister/" MODIFIED="1730924006139" TEXT="&quot;can we do better than mersenne?&quot;"> <node CREATED="1730923153709" ID="ID_1131418575" LINK="https://www.reddit.com/r/cpp/comments/ecrnjl/can_we_do_better_than_the_mersenne_twister/" MODIFIED="1730924006139" TEXT="&quot;can we do better than mersenne?&quot;">
<node CREATED="1730924010003" ID="ID_406338445" LINK="https://burtleburtle.net/bob/rand/smallprng.html" MODIFIED="1730924059005" TEXT="Jenkins"/> <node CREATED="1730924010003" ID="ID_406338445" LINK="https://burtleburtle.net/bob/rand/smallprng.html" MODIFIED="1730924059005" TEXT="Jenkins"/>
<node CREATED="1730924013155" ID="ID_1112820214" LINK="https://pracrand.sourceforge.net/RNG_engines.txt" MODIFIED="1730924281091" TEXT="PractRand"/> <node CREATED="1730924013155" ID="ID_1112820214" LINK="https://pracrand.sourceforge.net/RNG_engines.txt" MODIFIED="1730924281091" TEXT="PractRand"/>
<node CREATED="1731866839783" ID="ID_751896062" LINK="http://prng.di.unimi.it/" MODIFIED="1731866863658" TEXT="Xoroshiro">
<linktarget COLOR="#4499cd" DESTINATION="ID_751896062" ENDARROW="Default" ENDINCLINATION="124;-17;" ID="Arrow_ID_326929346" SOURCE="ID_472584641" STARTARROW="None" STARTINCLINATION="70;-69;"/>
</node>
<node CREATED="1730926918445" ID="ID_595255954" LINK="https://www.pcg-random.org/" MODIFIED="1730927175433" TEXT="PCG-Random"> <node CREATED="1730926918445" ID="ID_595255954" LINK="https://www.pcg-random.org/" MODIFIED="1730927175433" TEXT="PCG-Random">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_595255954" ENDARROW="Default" ENDINCLINATION="228;0;" ID="Arrow_ID_1247304219" SOURCE="ID_1870117805" STARTARROW="None" STARTINCLINATION="228;25;"/> <linktarget COLOR="#a9b4c1" DESTINATION="ID_595255954" ENDARROW="Default" ENDINCLINATION="228;0;" ID="Arrow_ID_1247304219" SOURCE="ID_1870117805" STARTARROW="None" STARTINCLINATION="228;25;"/>
<node CREATED="1730929577122" HGAP="24" ID="ID_1482800255" MODIFIED="1730929596392" TEXT="ist ein Hobby-Projekt von ihr" VSHIFT="18"/> <node CREATED="1730929577122" HGAP="24" ID="ID_1482800255" MODIFIED="1730929596392" TEXT="ist ein Hobby-Projekt von ihr" VSHIFT="18"/>
<node CREATED="1730929582849" ID="ID_340137516" MODIFIED="1730929590956" TEXT="besteht den PractRand-Test"/> <node CREATED="1730929582849" ID="ID_340137516" MODIFIED="1730929590956" TEXT="besteht den PractRand-Test"/>
<node CREATED="1730940355738" ID="ID_472584641" LINK="https://pcg.di.unimi.it/pcg.php" MODIFIED="1730940454177" TEXT="fachliche Kontroverse zwischen Melissa O&apos;Neill und Sebastiano Vigna"/> <node CREATED="1730940355738" ID="ID_472584641" LINK="https://pcg.di.unimi.it/pcg.php" MODIFIED="1731866868915" TEXT="fachliche Kontroverse zwischen Melissa O&apos;Neill und Sebastiano Vigna">
<arrowlink COLOR="#4499cd" DESTINATION="ID_751896062" ENDARROW="Default" ENDINCLINATION="124;-17;" ID="Arrow_ID_326929346" STARTARROW="None" STARTINCLINATION="70;-69;"/>
</node>
</node> </node>
</node> </node>
</node> </node>