Chain-Load: demonstrate pruning and separated graph segments

Through introduction of a ''pruning rule'', it is possible
to create exit nodes in the middle of the graph. With increased
intensity of pruning, it is possible to ''choke off'' the generation
and terminate the graph; in such a case a new seed node is injected
automatically. By combination with seed rules, an equilibrium of
graph start and graph termination can be achieved.

Following this path, it should be possible to produce a pattern,
which is random but overall stable and well suited to simulate
a realistic processing load.

However, finding proper parameters turns out quite hard in practice,
since the behaviour is essentially contingent and most combinations
either lead to uninteresting trivial small graph chunks, or to
large, interconnected and exponentially expanding networks
This commit is contained in:
Fischlurch 2023-12-01 04:50:11 +01:00
parent 38f27f967f
commit bb69cf02e3
3 changed files with 232 additions and 7 deletions

View file

@ -231,6 +231,7 @@ namespace test {
/** @test demonstrate shaping of generated topology
* - the expansion rule injects forking nodes
* - after some expansion, width limitation is enforced
@ -302,6 +303,7 @@ namespace test {
/** @test demonstrate impact of reduction on graph topology
* - after one fixed initial expansion, reduction causes
* all chains to be joined eventually
@ -331,7 +333,6 @@ namespace test {
CHECK (stat.indicators[STAT_NODE].cL == "0.37890625"_expect); // Nodes are concentrated towards the beginning
// expansion and reduction can counterbalance each other
graph.expansionRule(graph.rule().probability(0.2).maxVal(3).shuffle(555))
.reductionRule(graph.rule().probability(0.2).maxVal(3).shuffle(555))
@ -350,7 +351,6 @@ namespace test {
CHECK (stat.indicators[STAT_JOIN].cL == "0.66666667"_expect); // while joins need forks as prerequisite
// expansion bursts can be balanced with a heightened reduction intensity
graph.expansionRule(graph.rule().probability(0.3).maxVal(4).shuffle(555))
.reductionRule(graph.rule().probability(0.9).maxVal(2).shuffle(555))
@ -373,6 +373,7 @@ namespace test {
/** @test demonstrate shaping of generated topology by seeding new chains
* - the seed rule allows to start new chains in the middle of the graph
* - combined with with reduction, the emerging structure resembles
@ -405,7 +406,6 @@ namespace test {
CHECK (stat.indicators[STAT_JOIN].cL == "0.92857143"_expect); // while joining only happens at the end when connecting to exit
// combining random seed nodes with reduction leads to a processing pattern
// with side-chaines successively joined into a single common result
graph.seedingRule(graph.rule().probability(0.2).maxVal(3).shuffle())
@ -430,6 +430,7 @@ namespace test {
/** @test TODO demonstrate shaping of generated topology
* - TODO the prune rule terminates chains randomly
* - this can lead to fragmentation in several sub-graphs
@ -438,7 +439,165 @@ namespace test {
void
verify_PruneChains()
{
ChainLoad32 graph;
// terminate chains randomly
graph.pruningRule(graph.rule().probability(0.2))
.buildToplolgy()
// .printTopologyDOT()
// .printTopologyStatistics()
;
CHECK (graph.getHash() == 0xC4AE6EB741C22FCE);
auto stat = graph.computeGraphStatistics();
CHECK (stat.levels == 32); // only a single line of connections...
CHECK (stat.segments == 8); // albeit severed into 8 segments
CHECK (stat.indicators[STAT_NODE].pS == 4); // with always 4 Nodes per segment
CHECK (stat.indicators[STAT_NODE].pL == 1); // and only ever a single node per level
CHECK (stat.indicators[STAT_SEED].cnt == 8); // consequently we get 8 »Seed« nodes
CHECK (stat.indicators[STAT_EXIT].cnt == 8); // 8 »Exit« nodes
CHECK (stat.indicators[STAT_LINK].cnt == 16); // and 16 interconnecting links
// combined with expansion, several tree-shaped segments emerge
graph.pruningRule(graph.rule().probability(0.2))
.expansionRule(graph.rule().probability(0.6))
.setSeed(10101)
.buildToplolgy()
// .printTopologyDOT()
// .printTopologyStatistics()
;
CHECK (graph.getHash() == 0xC515DB464FF76818);
stat = graph.computeGraphStatistics();
CHECK (stat.levels == 15); //
CHECK (stat.segments == 5); // this time the graph is segregated into 5 parts
CHECK (stat.indicators[STAT_NODE].pS == 6.4); // with 4 Nodes per segment
CHECK (stat.indicators[STAT_FORK].sL == 0.0); // where »Fork« is always placed at the beginning of each segment
CHECK (stat.indicators[STAT_LINK].sL == 0.5); // carry-on »Link« nodes in the very middle of the segment
CHECK (stat.indicators[STAT_EXIT].sL == 1.0); // and several »Exit« at the end
CHECK (stat.indicators[STAT_EXIT].pS == 2.6); // averaging 2.6 exits per segment (4·3 + 1)/5
CHECK (stat.indicators[STAT_SEED].cnt == 5); // so overall we get 8 »Seed« nodes
CHECK (stat.indicators[STAT_FORK].cnt == 5); // 5 »Fork« nodes
CHECK (stat.indicators[STAT_EXIT].cnt == 13); // 13 »Exit« nodes
CHECK (stat.indicators[STAT_LINK].cnt == 14); // and 14 interconnecting links
CHECK (stat.indicators[STAT_NODE].pL == "2.1333333"_expect); // leading to ∅ ~2 Nodes per level
// however, by chance, with more randomised pruning points...
graph.pruningRule(graph.rule().probability(0.2).shuffle(5))
.expansionRule(graph.rule().probability(0.6))
.setSeed(10101)
.buildToplolgy()
// .printTopologyDOT()
// .printTopologyStatistics()
;
CHECK (graph.getHash() == 0xEF172CC4B0DE2334);
stat = graph.computeGraphStatistics();
CHECK (stat.segments == 1); // ...the graph can evade severing altogether
CHECK (stat.indicators[STAT_FORK].cnt == 2); // with overall 2 »Fork«
CHECK (stat.indicators[STAT_EXIT].cnt == 9); // and 9 »Exit« nodes
CHECK (stat.indicators[STAT_EXIT].pL == "1.2857143"_expect); // ∅ 1.3 exits per level
CHECK (stat.indicators[STAT_NODE].pL == "4.5714286"_expect); // ∅ 4.6 nodes per level
graph.expansionRule(graph.rule()); // reset
// combined with a special seeding rule,
// which injects /another seed/ in the next level after each seed,
// an equilibrium of chain seeding and termination can be achieved...
graph.seedingRule(graph.rule_atStart(1))
.pruningRule(graph.rule().probability(0.2))
.setSeed(10101)
.buildToplolgy()
// .printTopologyDOT()
// .printTopologyStatistics()
;
CHECK (graph.getHash() == 0xD0A27C9B81058637);
// NOTE: this example produced 10 disjoint graph parts,
// which however start and end interleaved
stat = graph.computeGraphStatistics();
CHECK (stat.levels == 13); // Generation carries on for 13 levels
CHECK (stat.segments == 1); // NOTE: the detection of segments FAILS here (due to interleaved starts)
CHECK (stat.indicators[STAT_SEED].cnt == 11); // 11 »Seed« nodes
CHECK (stat.indicators[STAT_EXIT].cnt == 10); // 10 »Exit« nodes
CHECK (stat.indicators[STAT_LINK].cnt == 10); // 10 interconnecting links
CHECK (stat.indicators[STAT_JOIN].cnt == 1); // and one additional »Join«
CHECK (stat.indicators[STAT_JOIN].cL == "0.91666667"_expect); // ....appended at graph completion
CHECK (stat.indicators[STAT_NODE].pL == "2.4615385"_expect); // overall ∅ 2½ nodes per level
CHECK (stat.indicators[STAT_NODE].cL == "0.48697917"_expect); // with generally levelled distribution
CHECK (stat.indicators[STAT_SEED].cL == "0.41666667"_expect); // also for the seeds
CHECK (stat.indicators[STAT_EXIT].cL == "0.55"_expect); // and the exits
// The next example is »interesting« insofar it shows self-similarity
// The generation is entirely repetitive and locally predictable,
// producing an ongoing sequence of small graph segments,
// partially overlapping with interwoven starts.
graph.seedingRule(graph.rule().fixedVal(1))
.pruningRule(graph.rule().probability(0.5))
.reductionRule(graph.rule().probability(0.8).maxVal(4))
.setSeed(10101)
.buildToplolgy()
// .printTopologyDOT()
// .printTopologyStatistics()
;
CHECK (graph.getHash() == 0x1D56DF2FB0D4AF97);
stat = graph.computeGraphStatistics();
CHECK (stat.levels == 9); // Generation carries on for 13 levels
CHECK (stat.indicators[STAT_JOIN].pL == 1); // with one »Join« event per level on average
CHECK (stat.indicators[STAT_SEED].cnt == 21); // seeds are injected with /fixed rate/, meaning that
CHECK (stat.indicators[STAT_SEED].pL == "2.3333333"_expect); // there is one additional seed for every node in previous level
TestChainLoad<256> gra_2;
// The next example is »interesting« insofar it shows self-similarity
// The generation is entirely repetitive and locally predictable,
// producing an ongoing sequence of small graph segments,
// partially overlapping with interwoven starts.
// gra_2.seedingRule(gra_2.rule_atLink(1))
// .pruningRule(gra_2.rule().probability(0.4))
// .reductionRule(gra_2.rule().probability(0.6).maxVal(5).minVal(2))
// .setSeed(23)
// .buildToplolgy()
// .printTopologyDOT()
// .printTopologyStatistics()
// ;
// this one goes into a stable repetition loop
// gra_2.seedingRule(gra_2.rule_atLink(1))
// .pruningRule(gra_2.rule().probability(0.5))
// .reductionRule(gra_2.rule().probability(0.6).maxVal(5).minVal(2))
// .setSeed(23)
// .buildToplolgy()
// .printTopologyDOT()
// .printTopologyStatistics()
// ;
// this one comes close to a relistic stable processing pattern
// just the individual graph is still to complicated
// and it the load increases over time
gra_2.seedingRule(gra_2.rule().probability(0.5).maxVal(2))
// .pruningRule(gra_2.rule().probability(0.55))
.reductionRule(gra_2.rule().probability(0.5).maxVal(5))
.pruningRule(gra_2.rule_atJoin(1))
.setSeed(42)
.buildToplolgy()
.printTopologyDOT()
.printTopologyStatistics()
;
//SHOW_EXPR(graph.getHash())
stat = gra_2.computeGraphStatistics();
// CHECK (stat.levels == 9); // Generation carries on for 13 levels
}
//SHOW_EXPR(graph.getHash())
//SHOW_EXPR(stat.indicators[STAT_NODE].pL)

View file

@ -359,6 +359,38 @@ namespace test {
});
}
static Rule
rule_atJoin (uint v)
{
return Rule().mapping([v](Node* n)
{
return isJoin(n) ? Rule().fixedVal(v)
: Rule();
});
}
static Rule
rule_atLink (uint v)
{
return Rule().mapping([v](Node* n)
{ // NOTE: when applying these rules,
// successors are not yet wired...
return not (isJoin(n) or isStart(n))
? Rule().fixedVal(v)
: Rule();
});
}
static Rule
rule_atJoin_else (double p1, double p2, uint v=1)
{
return Rule().mapping([p1,p2,v](Node* n)
{
return isJoin(n) ? Rule().probability(p1).maxVal(v)
: Rule().probability(p2).maxVal(v);
});
}
/**

View file

@ -96296,15 +96296,49 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1701226052691" ID="ID_929780401" MODIFIED="1701226056300" TEXT="Prune">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1701226052691" ID="ID_929780401" MODIFIED="1701401958232" TEXT="Prune">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1701401689510" ID="ID_453433047" MODIFIED="1701401733961" TEXT="Pruning allein &#x27f9; Graph zerlegt">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1701401742643" ID="ID_90185161" MODIFIED="1701401751675" TEXT="Prune + Expand &#x27f9; kleine B&#xe4;umchen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1701401765792" ID="ID_796883949" MODIFIED="1701401779784" TEXT="+ shuffle &#x27f9; Graph zerf&#xe4;llt nicht (mehr)">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1701401867273" ID="ID_1917139651" MODIFIED="1701401954627" TEXT="Seed + Prune + Reduce....">
<arrowlink COLOR="#659b9f" DESTINATION="ID_633684852" ENDARROW="Default" ENDINCLINATION="-7;-31;" ID="Arrow_ID_1330203959" STARTARROW="None" STARTINCLINATION="-67;8;"/>
</node>
</node>
<node COLOR="#338800" CREATED="1701226061434" ID="ID_1246960546" MODIFIED="1701314215907" TEXT="Gleichgewicht">
<icon BUILTIN="button_ok"/>
<node CREATED="1701314218952" ID="ID_959655971" MODIFIED="1701314254700" TEXT="Expansion &#x27f5;&#x27f6; Reduction"/>
<node CREATED="1701401672045" ID="ID_277348330" MODIFIED="1701401686590" TEXT="Seed &#x27f5;&#x27f6; Reduction + Pruning"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1701226065633" ID="ID_633684852" MODIFIED="1701402052810" TEXT="Teilgraphen">
<linktarget COLOR="#659b9f" DESTINATION="ID_633684852" ENDARROW="Default" ENDINCLINATION="-7;-31;" ID="Arrow_ID_1330203959" SOURCE="ID_1917139651" STARTARROW="None" STARTINCLINATION="-67;8;"/>
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1701401801875" ID="ID_613538695" MODIFIED="1701401819064" TEXT="Seed + Prune &#x27f9; interleaved graphs">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1701401829056" ID="ID_623081988" MODIFIED="1701401856489" TEXT="Seed + Prune + Reduce &#x27f9; self similar structures">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1701401968501" ID="ID_1106827463" MODIFIED="1701401978487" TEXT="Suche nach realistischen Processing-Pattern">
<node COLOR="#338800" CREATED="1701402009239" ID="ID_1542545632" MODIFIED="1701402022723" TEXT="Complex-interleaved">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1701402015035" ID="ID_427886072" MODIFIED="1701402022724" TEXT="semi-complex stable state">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1701402024221" ID="ID_656477574" MODIFIED="1701402035013" TEXT="simple-interleaved">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1701402036180" ID="ID_1920671782" MODIFIED="1701402046419" TEXT="will mir nicht recht gelingen">
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1701226065633" ID="ID_633684852" MODIFIED="1701226072137" TEXT="Teilgraphen">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>