diff --git a/HelpSource/Classes/MarkovSet.schelp b/HelpSource/Classes/MarkovSet.schelp index 247d1f9..712d166 100644 --- a/HelpSource/Classes/MarkovSet.schelp +++ b/HelpSource/Classes/MarkovSet.schelp @@ -4,8 +4,7 @@ categories:: Collections>Unordered, Libraries>MathLib>Markov & Fuzzy related:: Classes/MarkovSetN, Classes/ShannonMarkovSet, Classes/ShannonFinger DESCRIPTION:: -MarkovSet is a Dictionary that contains keys pointing to WeighBags that contain objects and their probabilities. By parsing in a stream the Set "learns" what element can possibly follow another.footnote::See: http://www.taygeta.com/rwalks/rwalks.html:: - +MarkovSet is a Dictionary that contains keys pointing to WeighBags that contain objects and their probabilities. By parsing in a stream the Set "learns" what element can possibly follow another (see random walk). Part of link::Guides/MathLib::, a diverse library of mathematical functions. @@ -30,7 +29,10 @@ If args is code::nil::, the set is created and may be trained by the other metho ARGUMENT:: updateSeeds If set to code::true::, each element is always added to the seeds - +ARGUMENT:: remanence +Allows a dynamic Markov chain in the field of remanence as maximun order. +NOTE:: The remanence is effective only in a dynamic Markov chain context, which requires strong::element:: as an Array. In that case only the method code::nextProb::, code::nextIncludes:: and code::parseSeq:: are operative. Otherwise remanence is simply ignored. +:: METHOD:: fill @@ -194,6 +196,16 @@ x = Pfsm2(m, inf).asStream; ) :: +subsection:: Dynamic Markov Chain + +code:: +d = Array.with(seq1.asArray, seq2.asArray...seqN.asArray); +m = MarkovSet.new(remanence: 3, updateSeeds: true); +m.parseSeq(d, { "Parsing data completed!".postln }); +m.nextProb; +:: section:: Authors Julian Rohrhuber, 2004, 2007. + +Yann Ics, 2022 (Dynamic Markov Chain). diff --git a/classes/MarkovSet/MarkovSet.sc b/classes/MarkovSet/MarkovSet.sc index b2e09dd..bd626be 100644 --- a/classes/MarkovSet/MarkovSet.sc +++ b/classes/MarkovSet/MarkovSet.sc @@ -9,16 +9,17 @@ ________________________________________________________________________________ By parsing in a stream the Set 'learns' what element can possibly follow another. for reference see: http://www.taygeta.com/rwalks/rwalks.html ______________________________________________________________________________________ version 3.5, Julian Rohrhuber, 12/2004, 3/2007 +version 3.5.1, contribution Yann Ics, Summer 2022 */ MarkovSet { - var updateSeeds, updateSeeds, 1) } + { + ^this.nextProb(pk[1..], prob) + } + { bag.weights.size == 1 } + { + ^this.nextProb(pk[1..], prob) + } + { true } + { + if (prob.asBoolean) + { ^[bag.items, bag.counts] } + { ^bag.wchoose } + } + } + + nextIncludes { arg prevKey, includes; + var ins, tmp; + var prob = this.nextProb(prevKey, true); + if (prob.isNil.not) + { + // [TODO] when includes.size > 1 + // (it.asArray.asSet & includes.asArray.asSet) + // should respect their respective order as indices + // and be optimised ... + // e.g. [0, 7, 0, 5] should match only with [0, 7], [0, 0], [0, 5], [7, 0], [7, 5], [0, 7, 0], [0, 7, 5], [0, 0, 5], [7, 0, 5] or [0, 7, 0, 5] as includes + ins = prob[0].selectIndices{|it| (it.asArray.asSet & includes.asArray.asSet) == includes.asArray.asSet}; + if (ins.isEmpty && this.updateSeeds) + { + ins = prob[0].selectIndices{|it| (it.asArray.asSet & includes.asArray.asSet).isEmpty.not}; + if (ins.size > 0) { "partial match".postln } + } + }; + if (ins.size == 0) + { + if (this.updateSeeds) + { + tmp = this.dmc.select{|it| (it[0].asArray.asSet & includes.asArray.asSet) == includes.asArray.asSet}; + if (tmp.isEmpty) + { + tmp = this.dmc.select{|it| (it[0].asArray.asSet & includes.asArray.asSet).isEmpty.not}; + if (tmp.isEmpty) + { ^this.nextProb } + { ^tmp.flopChoose } + } + { ^tmp.flopChoose } + } + { ^nil } + } + { + ^ins.collect{|ind| [prob[0][ind], prob[1][ind]]}.flopChoose; + } + } + + parseSeq { arg data, completionFunc; + // data is a list of sequence(s) + // e.g. Array.with(seq1.asArray, seq2.asArray...seqN.asArray) + data.do{|seq| + seq.windloop(this.remanence).do{|len| + len.do{|it| this.read(it[..it.size-2], it.last)}}}; + this.makeSeeds; + completionFunc.value; + } +} + +// get weighted array for method nextProb in MarkovSet ++ ArrayedCollection { + windloop { arg order; + var ord; + // order is an integer strictly superior to zero + if (order > this.size) { order = this.size }; + ^(2..order+1).collect + { + |k| + (this.size-k+1).collect + { + |i| + this[i..i+k-1] + } + } + } + + flopChoose { + // this = [[item1, countItem1], [item2, countItem2] ... [itemN, countItemN]] + var tmp = this.flop; + ^tmp[0].wchoose(tmp[1].normalizeSum) + } +} +//-------------------------------------------------- +// ref: https://yannics.github.io/ +// - Journal of Generative Sonic Art +// - Neuromuse3 +//-------------------------------------------------- + +