Invocation: build test-data manipulation function

* based on reproducible data in `TestFrame`
 * using Murmur64A hash-chaining to »mark« with a parameter

This emulates the simplest case of 1:1 processing and can also be applied ''in-place''
This commit is contained in:
Fischlurch 2024-11-20 21:44:50 +01:00
parent 52c8445299
commit 26bf32525b
10 changed files with 266 additions and 74 deletions

View file

@ -43,3 +43,9 @@ When relying on that hack, we should make sure always to place some kind of
`static_assert` into the corresponding implementation files to ensure the real
facilites actually _do fit_ into the guessed storage dimensions.
Portability
-----------
- Linux-only solution to discover the path of the executable: `findExePath` in 'lib/searchpath.hpp'
- hard-coded usage of `/dev/urandom` (e.g. in 'lib/random.cpp' as spec for the `std::random_device`
- using the 64bit Murmur-2.64A hash function in '/lib/hash-combine.hpp'

View file

@ -90,6 +90,14 @@ calculated hash values of the parts forming a composite data structure.
uses the standard implementation of a string hash function combining the individual
character's hashes.
Hash-chaining
~~~~~~~~~~~~~
We use a dedicated function `lib::hash::combine(s,h)` to join several source(component) hashes.
This usage pattern was pioneered by Boost and is based on the
https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp[Murmur-2.64A] hash algorithm.
WARNING: as of [yellow-background]#11/2024#, portability of hash values is an unresolved issue;
this code does not work on 32bit systems https://issues.lumiera.org/ticket/722#comment:10[see #722]
LUID values
@ -103,9 +111,10 @@ the meltdown of an atomic power plant, which, as we all know, won't ever happen
Relation to hash values
~~~~~~~~~~~~~~~~~~~~~~~
When objects incorporate sich an unique LUID, this provides for a prime candidate to
When objects incorporate such an unique LUID, this provides for a prime candidate to
derive hash values as a side-effect of that design: Since incorporating an LUID typically
means that this object has an _distinguishable identity_, all objects with the same LUID
should be considered _equivalent_ and thus hash to the same value. Consequently we can just
use a +size_t+ prefix of the LUID bitstring as hash value, without any further calculations.
This relies on LUID being generated from a reliable _entropy source._

View file

@ -0,0 +1,117 @@
how to crack nut #47
====================
:toc:
.collection of successfully employed technical solutions
Some nasty problems are recurring time and again. Maybe a trick could be found somewhere
in the net, and a library function was created to settle this damn topic once and for all.
Maybe even a nice test and demo is provided. And then the whole story will be forgotten.
_Sounds familiar?_ => ☹☻☺ ~[red]#then please leave a note here...#~
Methods
-------
Mathematics
~~~~~~~~~~~
- some basic descriptive statistics computation are defined in 'lib/stat/statistic.hpp'
- the simple case for _linear regression_ is also implemented there
- Gnuplot provides also common statistics functions, which may come in handy when the
goal is anyway to create a visualisation (-> see <<investigation,below>>)
Situations
----------
Investigation
~~~~~~~~~~~~~
summary test::
Reformulate the research and the findings into a test, which can be read top-down like a novel.
Start with documenting the basics, package helpers into a tool class, or package setup into a
workbench-style class, with individual tool modules. Provide a short version of this test with
the basic demo, which should be able to run with the regular test suite. Extended long-running
tests can be started conditionally with commandline-arguments. See 'scheduler-stress-test.cpp'
visualisation::
Use code generation to visualise data structures or functions and observation statistics.
Typically these generation statements can be packaged into an invocation helper and included
into a relevant test, but commented-out there.
+
- generate Graphviz diagrams: 'lib/dot-gen.hpp' provides a simple DSL. See 'test-chain-load-test.cpp'
- generate Gnuplot scripts: use the Text-Template engine to fill in data, possibly from a data table
* 'lib/gnuplot-gen.hpp' provides some pre-canned scripts for statistics plots
* used by the 'stress-test-rig.cpp', in combination with 'data.hpp' to collect measurement results
Common Tasks
------------
Data handling
~~~~~~~~~~~~~
persistent data set::
use the `lib::stat::DataTable` ('data.hpp') with CSV rendering -> see 'data-csv-test.cpp'
Formatting
~~~~~~~~~~
- implement a conversion-to-string operator.
- include the C++ IOStreams via 'lib/format-cout.hpp' -> this magically uses the `util::toString()`
- for testing, temporarily include 'lib/test/diagnostic-output' and use the `SHOW_EXPR` macro.
- use 'util::join' ('lib/format-util.hpp') to join arbitrary elements with `util::toString()` conversion
- use _printf-style formatters_ from Boost-format. We provide a light-weight front-end via 'lib/format-string.hpp'
* the heavyweight boost-format include is only required once, for 'lib/format-string.cpp'.
* the templated front-end passes-through most basic types and types with string-conversion
* all invocations are strictly error safe (never throw) and can thus be used from catch-handlers
- use the *Text-Template* engine. See 'text-template-test.cpp'. Can be used with simple map bindings,
but also from a `lib::GenNode` tree, or with a custom defined `DataSource` template
Language constructs
-------------------
Templates
~~~~~~~~~
build-from-anything::
use a templated constructor, possibly even with varargs
+
- use a _deduction guide_ to pick the right ctor and arguments -> see
* `ThreadJoinable` in 'thread.hpp', 698
* `DataSource<string>` specialisation only when argument can be converted to string,
in 'text-template.hpp', 745
- prevent shadowing of _automatically generated copy operations._
See https://issues.lumiera.org/ticket/963[#963]. Based on the ``disable if'' SFINAE technique.
A ready-made templated typedef `lib::metadisable_if_self` can be found in 'lib/meta/util.hpp'
Varargs
~~~~~~~
pick and manipulate individually::
The key trick is to define an _index sequence template,_ which can then be matched against
a processing template for a single argument; and the latter can have partial specialisations
+
- see 'variadic-argument-picker-test.cpp'
- but sometimes it is easier to use the tried and true technique of the Loki-Typelists, which
can be programmed recursively, similar to LISP. The »bridge« is to unpack the variadic argument pack
into the `lib::meta::Types<ARGS...>` ([yellow-background]#⚠ still broken in 2024#
see https://issues.lumiera.org/ticket/987[#987], use `lib::meta::TySeq` from 'variadic-helper.hpp' as workaround...
+
apply functor to each::
A common trick is to use `std::apply` in combination with a _fold-expression_
+
- provided as `lib::meta::forEach` in 'lib/meta/util.hpp
- The design of the `DataTable` with CSV-Formatting is based on this technique, see 'lib/stat/data.hpp'
- 'test-rand-ontology.cpp' uses this in `manipulateFrame()` to accept an arbitrary number of input chains
+
unpack iterator into tuple::
Under controlled conditions this is possible (even while it seems like time travel from the runtime into
the compile-time domain). The number of results to extract from the iterator must be known at compile time,
and the possible result types must be limited, so that a visitor can be used for double-dispatch.
+
- see tuple-record-init-test.cpp
- used in 'command-simple-closure.hpp' to receive parameter values sent via UI-Bus and package them
into a tuple for invocation of a Steam-Layer command.

View file

@ -51,10 +51,10 @@
namespace lib {
namespace hash{
/** meld the additional hash value into the given
* base hash value. This is the standard formula
* used by Lib-Boost to combine the hash values
* of parts into a composite.
/** meld the additional hash value into the given base hash value.
* This is the standard formula used by Lib-Boost to combine the hash values
* of parts into a composite, and is based on the [Murmur-2.64A] hash algorithm.
* [Murmur-2.64A]: https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp
*/
inline void
combine (size_t & combinedHash, size_t additionalHash)

View file

@ -17,6 +17,7 @@
#include "lib/test/run.hpp"
#include "lib/hash-combine.hpp"
#include "steam/engine/test-rand-ontology.hpp" ///////////TODO
#include "lib/test/diagnostic-output.hpp"/////////////////TODO
#include "lib/random.hpp"
@ -43,6 +44,12 @@ namespace test {
operator TestFrame* () { return std::launder (reinterpret_cast<TestFrame* > (&storage)); }
TestFrame* operator->() { return std::launder (reinterpret_cast<TestFrame* > (&storage)); }
TestFrame& operator* () { return * std::launder (reinterpret_cast<TestFrame* > (&storage)); }
TestFrame&
buildData (uint seq=0, uint family=0)
{
return * new(&storage) TestFrame{seq,family};
}
};
}
@ -57,9 +64,11 @@ namespace test {
run (Arg)
{
seedRand();
TestFrame::reseed();
processing_generateFrame();
processing_generateMultichan();
processing_manipulateFrame();
}
@ -102,6 +111,42 @@ namespace test {
CHECK (*(buffs[i]) == TestFrame(frameNr,flavour+i));
}
}
/** @test function to apply a numeric computation to test data frames
*/
void
processing_manipulateFrame()
{
size_t frameNr = defaultGen.u64();
uint flavour = defaultGen.u64();
Buffer iBuff, oBuff;
iBuff.buildData(frameNr,flavour);
oBuff.buildData(frameNr,flavour);
CHECK (iBuff->isPristine());
CHECK (iBuff->isPristine());
uint64_t param = defaultGen.u64();
manipulateFrame (oBuff, iBuff, param);
CHECK ( oBuff->isValid());
CHECK (not oBuff->isPristine());
CHECK ( iBuff->isPristine());
for (uint i=0; i<oBuff->data64().size(); ++i)
{
uint64_t feed = param;
uint64_t data = iBuff->data64()[i];
lib::hash::combine (feed, data);
CHECK (data == iBuff->data64()[i]);
CHECK (feed != iBuff->data64()[i]);
CHECK (feed == oBuff->data64()[i]);
}
// can also process in-place
manipulateFrame (iBuff, iBuff, param);
CHECK (not iBuff->isPristine());
CHECK ( iBuff->isValid());
CHECK (*iBuff == *oBuff); // second invocation exactly reproduced data from first invocation
}
};

View file

@ -13,11 +13,18 @@
/** @file test-rand-ontology.cpp
** Implementation of fake data processing to verify invocation logic.
** The emulated »media computations« work on TestFrame data buffers, which can be
** filled with deterministically generated pseudo-random data, that can be verified afterwards.
** Computations manipulate or combine individual data points, and mark the result again with a
** valid checksum. Hash-chaining computations are used in order to ensure that the resulting
** data values depend on all input- and parameter values, and the _exact order_ of processing.
** All computations are reproducible, and thus a test can verify a computation carried out
** within the context of the Render-Engine code.
*/
#include "steam/engine/test-rand-ontology.hpp"
#include "lib/error.hpp"
#include "lib/hash-combine.hpp"
//#include <vector>
@ -70,18 +77,19 @@ namespace test {
/**
* @param out existing allocation to place the generated TestFrame into
* @param in allocation holding the input TestFrame data
* @param param parameter to control the data manipulation (to be multiplied into the data)
* @remark this function emulates media data processing: each byte of the input data is multiplied
* with the given \a param, wrapping each result into the corresponding output byte. The
* generated result TestFrame is marked with a valid checksum.
* @param param parameter to control or »mark« the data manipulation (hash-combining)
* @remark this function emulates media data processing: data is processed in 64-bit words,
* by hash-chaining with \a param. The generated result is marked with a valid checksum.
*/
void
manipulateFrame (TestFrame* out, TestFrame* in, int param)
manipulateFrame (TestFrame* out, TestFrame const* in, uint64_t param)
{
REQUIRE (in);
REQUIRE (out);
for (size_t i=0; i < in->data().size(); ++i)
out->data()[i] = char(param * in->data()[i]);
auto calculate = [](uint64_t chain, uint64_t val){ lib::hash::combine(chain,val); return chain; };
for (size_t i=0; i < in->data64().size(); ++i)
out->data64()[i] = calculate(param, in->data64()[i]);
out->markChecksum();
}
/**
@ -93,13 +101,14 @@ namespace test {
* each result byte is the linear interpolation between the corresponding inputs.
*/
void
combineFrames (TestFrame* out, TestFrame* srcA, TestFrame* srcB, int mix)
combineFrames (TestFrame* out, TestFrame const* srcA, TestFrame const* srcB, int mix)
{
REQUIRE (srcA);
REQUIRE (srcB);
REQUIRE (out);
for (size_t i=0; i < srcA->data().size(); ++i)
out->data()[i] = char((1-mix) * srcA->data()[i] + mix * srcB->data()[i]);
out->markChecksum();
}

View file

@ -40,11 +40,11 @@ namespace test {
/** produce planar multi channel output of random data frames */
void generateMultichan (uint chanCnt, TestFrame* buffArry, size_t frameNr, uint flavour);
/** »process« random frame date by multiply-wrapping with a parameter */
void manipulateFrame (TestFrame* out, TestFrame* in, int param);
/** »process« random frame date by hash-chaining with a parameter */
void manipulateFrame (TestFrame* out, TestFrame const* in, uint64_t param);
/** mix two random data frames by a parameter-controlled proportion */
void combineFrames (TestFrame* out, TestFrame* srcA, TestFrame* srcB, int mix);
void combineFrames (TestFrame* out, TestFrame const* srcA, TestFrame const* srcB, int mix);

View file

@ -116,6 +116,13 @@ namespace test {
for (uint i=0; i<frameA.data().size(); ++i)
CHECK (frameA.data()[i] == frameB.data()[i]);
// can access data as uint64_t
CHECK (frameA.data()[ 8] == char(frameA.data64()[1])); // assuming little-endian
CHECK (frameA.data()[16] == char(frameA.data64()[2]));
CHECK (frameA.data()[24] == char(frameA.data64()[3]));
CHECK (frameA.data()[32] == char(frameA.data64()[4]));
CHECK (frameA.data().size() == 8*frameA.data64().size());
CHECK (frameA.isAlive());
CHECK (frameB.isAlive());
CHECK (frameC.isAlive());

View file

@ -73,6 +73,7 @@ namespace test {
static constexpr size_t BUFFSIZ = 1024;
using _Arr = std::array<char,BUFFSIZ>;
using _A64 = std::array<uint64_t, BUFFSIZ/sizeof(uint64_t)>;
struct Meta
{
@ -130,6 +131,8 @@ namespace test {
/** Array-style direct access to the payload data */
_Arr& data() { return * std::launder (reinterpret_cast<_Arr* > (&buffer_)); }
_Arr const& data() const { return * std::launder (reinterpret_cast<_Arr const*> (&buffer_)); }
_A64& data64() { return * std::launder (reinterpret_cast<_A64* > (&buffer_)); }
_A64 const& data64() const { return * std::launder (reinterpret_cast<_A64 const*> (&buffer_)); }
private:
void buildData();

View file

@ -18615,9 +18615,7 @@
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1664032721142" ID="ID_999001948" MODIFIED="1664313668307" TEXT="geht das?">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...das hei&#223;t...
@ -18956,9 +18954,7 @@
<font NAME="SansSerif" SIZE="10"/>
<node COLOR="#33565a" CREATED="1664726003283" ID="ID_991077863" MODIFIED="1664727540443" TEXT="show(Icon)? Nein &#x27f9; &#x25a3;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Mehrstufige Pr&#252;fung mit Hysterese (um Flackern zu vermeiden)...
@ -19342,9 +19338,7 @@
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1664060239692" ID="ID_1617851912" MODIFIED="1664060250875" TEXT="also doch erst mal &quot;bodenst&#xe4;ndig&quot; beginnen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Aua!
@ -19794,9 +19788,7 @@
</node>
<node CREATED="1661703818006" ID="ID_1356134223" MODIFIED="1661703862455" TEXT="keine Verbindung zum Layoutmanager notwendig">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Naja, stimmt nicht wirklich, denn Pixel-Angaben m&#252;ssen angepa&#223;t werden, also besteht faktisch eine Verbindung
@ -20645,9 +20637,7 @@
<icon BUILTIN="button_ok"/>
<node CREATED="1480724851312" ID="ID_1653680733" MODIFIED="1576282358097" TEXT="erzeugt R&#xfc;ckbezug f&#xfc;r Notifications">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
..d.h. der Controller mu&#223; wieder auf das Widget zugreifen
@ -22170,9 +22160,7 @@
<node CREATED="1582832787665" ID="ID_770114878" MODIFIED="1582832790629" TEXT="warum?"/>
<node CREATED="1582832791081" ID="ID_921622013" MODIFIED="1582833095134" TEXT="aus logischen Gr&#xfc;nden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...ich wollte dadurch ausdr&#252;cken, da&#223; das &#252;bergebene ViewHooked&lt;Widget&gt;&amp; urspr&#252;nglich schon einmal geHooked worden war. Tats&#228;chlich hat ja im originalen Design der ViewHook das Hookable sogar erst konstruiert, und niemand sonst konnte das. Da wir aber nun inzwischen immer mit einem ViewHookable mit eingebettetem Widget arbeiten, mu&#223; dieses freistehend konstruiert werden, und des gibt keine direkte M&#246;glichkeit mehr, diese &quot;Verdongelung&quot; auszudr&#252;cken. Und au&#223;erdem sind auch alle weiteren Ideen aufgegeben, welche auf eine engere Verzahnung der Interfaces aufbauen w&#252;rden (Stichwort &quot;quer-Beweglichkeit&quot;).
@ -25510,9 +25498,7 @@
</node>
<node CREATED="1612742199694" ID="ID_354715180" MODIFIED="1612742247324" TEXT="der 2.Pass mu&#xdf; r&#xfc;ckw&#xe4;rts aufsteigen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
damit die H&#246;hen f&#252;r die Kind-Tracks bereits gesetzt sind, wenn die Gesamth&#246;he des Parent-Track betrachtet wird
@ -38913,9 +38899,7 @@
</node>
<node COLOR="#435e98" CREATED="1619697245422" ID="ID_1061197338" MODIFIED="1619804310109" TEXT="Forwarding &#xfc;ber mehrere Schritte">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -41151,9 +41135,7 @@
</node>
<node COLOR="#338800" CREATED="1667683782783" ID="ID_1842670966" MODIFIED="1667683907910" TEXT="MAX_TIMESPAN: Begrenzung hier nicht relevant">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Der Grenzfall ist ja changedMetric = MAX_ZOOM
@ -42692,9 +42674,7 @@
</node>
<node CREATED="1670617617322" ID="ID_154517336" MODIFIED="1670617693674" TEXT="aber numerisch ein Albtraum!">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
weil hier...
@ -43736,9 +43716,7 @@
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1668294985092" ID="ID_25938691" MODIFIED="1668295715873" TEXT="Fazit: sichere Aussage nicht m&#xf6;glich">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...in vertretbarem Rahmen...
@ -44239,9 +44217,7 @@
</node>
<node CREATED="1669932981526" ID="ID_837170036" MODIFIED="1669933009189">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
&#10233; also mu&#223; man hier <i>technisch runden</i>
@ -45849,9 +45825,7 @@
<icon BUILTIN="flag-yellow"/>
<node CREATED="1665968738638" ID="ID_1311831391" MODIFIED="1665968767871" TEXT="Problem: Abweichung vom generischen diff-Format">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
schon analog zu dem, was wir hier mit dem &quot;timing&quot; machen
@ -46006,9 +45980,7 @@
</node>
<node CREATED="1523019770144" ID="ID_1782262126" MODIFIED="1557498707235">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
(GlobalCtx)-&gt;WindowLocator-&gt;<b>PanelLocator</b>
@ -92231,8 +92203,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#5e5572" DESTINATION="ID_1032840307" ENDARROW="Default" ENDINCLINATION="-1323;101;" ID="Arrow_ID_1310977916" SOURCE="ID_435456030" STARTARROW="Default" STARTINCLINATION="1366;-77;"/>
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1728765172917" ID="ID_33308294" MODIFIED="1728765183676" TEXT="Zahl der Leads und Ports pr&#xfc;fen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1728765172917" ID="ID_33308294" MODIFIED="1729983023889" TEXT="Zahl der Leads und Ports pr&#xfc;fen">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1732121078339" HGAP="61" ID="ID_279447757" MODIFIED="1732121109543" TEXT="ProcNodeDiagnostic" VSHIFT="4">
<font NAME="Monospaced" SIZE="9"/>
</node>
</node>
</node>
<node CREATED="1728769243429" ID="ID_1535113263" MODIFIED="1728769249651" TEXT="f&#xfc;r einen Port...">
@ -92486,7 +92461,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1728771355851" ID="ID_1533221865" MODIFIED="1728772550469" TEXT="Berechnungsweg komplett deterministic and pure">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1728771355851" ID="ID_1533221865" MODIFIED="1732145905134" TEXT="Berechnungsweg komplett deterministic and pure">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -92503,10 +92478,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</ul>
</body>
</html></richcontent>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1728782135051" ID="ID_391399838" MODIFIED="1728782152864" TEXT="Standard-&#xbb;Operationen&#xab; (in der Test-Ontology)">
<icon BUILTIN="pencil"/>
<node COLOR="#435e98" CREATED="1728782135051" ID="ID_391399838" MODIFIED="1732146034999" TEXT="Standard-&#xbb;Operationen&#xab; (in der Test-Ontology)">
<linktarget COLOR="#556273" DESTINATION="ID_391399838" ENDARROW="Default" ENDINCLINATION="-384;24;" ID="Arrow_ID_290133862" SOURCE="ID_607130868" STARTARROW="None" STARTINCLINATION="257;-992;"/>
<node CREATED="1728782215620" ID="ID_571179061" MODIFIED="1728782226782" TEXT="un&#xe4;r, bin&#xe4;r, ... N-&#xe4;r"/>
<node CREATED="1728782276193" ID="ID_151408357" MODIFIED="1728782369538" TEXT="die Berechnung selber ist eine Hashverkn&#xfc;pfung (boost hash_combine)">
<node CREATED="1728782276193" ID="ID_151408357" MODIFIED="1732122042230" TEXT="die Berechnung selber ist eine Hashverkn&#xfc;pfung (analog boost hash_combine)">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -92526,12 +92502,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node CREATED="1728782874164" ID="ID_1997651851" MODIFIED="1728783179058" TEXT="dieser Seed, zusammen mit den Kenndaten, bildet eine reproduzierbare Identit&#xe4;t">
<node CREATED="1728782874164" ID="ID_1997651851" MODIFIED="1732122136120" TEXT="dieser Seed, zusammen mit den Kenndaten, bildet eine reproduzierbare Identit&#xe4;t">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...zwar handelt es sich stets nur um eine Hash-Verkn&#252;pfung, aber die Arit&#228;t (und ggfs. sp&#228;ter auch noch ein Array-Wertiger Input) kommen als Steuerparameter hinzu. Diese Parameter k&#246;nnen als lesbarer Spec-String ausgegeben werden, und in einen Hash eingerechnet werden, der dann die Funktion markiert und unterscheidbar macht. Wenn ein Seed explizit angegeben wird, dann flie&#223;t er zus&#228;tzlich mit ein, und markiert au&#223;erdem auch die Berechnung an jedem Datenpunkt
...zwar handelt es sich stets nur um eine Hash-Verkn&#252;pfung, aber die Arit&#228;t (und ggfs. sp&#228;ter auch noch ein Array-wertiger Input) kommen als Steuerparameter hinzu. Diese Parameter k&#246;nnen als lesbarer Spec-String ausgegeben werden, und in einen Hash eingerechnet werden, der dann die Funktion markiert und unterscheidbar macht. Wenn ein Seed explizit angegeben wird, dann flie&#223;t er zus&#228;tzlich mit ein, und markiert au&#223;erdem auch die Berechnung an jedem Datenpunkt
</p>
</body>
</html></richcontent>
@ -92557,7 +92533,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node CREATED="1728783585707" ID="ID_288581450" MODIFIED="1728783674793" TEXT="f&#xfc;r jede Berechnung gibt es eine human-readable spec">
<node CREATED="1732145995543" ID="ID_209219518" MODIFIED="1732146006347" TEXT="Verkn&#xfc;pfung mehrerer Eingabpuffer">
<node COLOR="#435e98" CREATED="1732146009058" ID="ID_422352708" MODIFIED="1732146038271" TEXT="linearer Mix von zwei Eingabepuffern"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732146039895" ID="ID_136718896" MODIFIED="1732146062196" TEXT="N-fach Kombination mit Parameter-Seed">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1728783585707" ID="ID_288581450" MODIFIED="1732146078102" TEXT="f&#xfc;r jede Berechnung gibt es eine human-readable spec">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -92566,6 +92548,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</p>
</body>
</html></richcontent>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1728772511968" ID="ID_1684753208" MODIFIED="1729981657484" TEXT="EventLog zuschaltbar f&#xfc;r jeden Schritt">
@ -92797,7 +92780,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1730827701591" ID="ID_1382558170" MODIFIED="1730827720498" TEXT="mu&#xdf; nun beginnen, die Test-Processing-Funktionen zu organisieren">
<icon BUILTIN="smily_bad"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1730827749568" ID="ID_607130868" MODIFIED="1730836275467" TEXT="die Basis-Funktionen als free-functions realisieren">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1730827749568" ID="ID_607130868" MODIFIED="1732121192105" TEXT="die Basis-Funktionen als free-functions realisieren">
<arrowlink COLOR="#556273" DESTINATION="ID_391399838" ENDARROW="Default" ENDINCLINATION="-384;24;" ID="Arrow_ID_290133862" STARTARROW="None" STARTINCLINATION="257;-992;"/>
<icon BUILTIN="pencil"/>
<node CREATED="1730828045224" ID="ID_874340553" MODIFIED="1730828060299" TEXT="generateFrame"/>
<node CREATED="1730828224345" ID="ID_1955731193" MODIFIED="1730828238872" TEXT="generateMultichan"/>
@ -92921,6 +92905,18 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732122224270" ID="ID_1520955122" MODIFIED="1732122384309" TEXT="brauche Zugang zu den Daten in passendem Format">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Im Datenblock liegt lediglich eine Sequenz von 1014 Bytes &#8212; man m&#246;chte darauf jedoch flexibel aber getypt zugreifen k&#246;nnen
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1732112455819" ID="ID_1055009498" MODIFIED="1732112465158" TEXT="sp&#xe4;ter nachr&#xfc;stbar: Lifecycle">
<icon BUILTIN="hourglass"/>
</node>