Motif sequence generation
#
MotifSequenceGenerator — Module
MotifSequenceGenerator
This module generates random sequences of motifs, under the constrain that the sequence has some total length ℓ so that q - δq ≤ ℓ ≤ q + δq. All main functionality is given by the function random_sequence.
#
MotifSequenceGenerator.random_sequence — Function
random_sequence(motifs::Vector{M}, q, limits, translate, δq = 0; kwargs...)
Create a random sequence of motifs of type M, under the constraint that the sequence has "length" ℓ exactly within q - δq ≤ ℓ ≤ q + δq. Return the sequence itself as well as the sequence of indices of motifs used to create it. A vector of probabilities weights can be given as a keyword argument, which then dictates the sampling probability for each entry of motifs for the initial sequence created.
"length" here means an abstracted length defined by the struct M, based on the limits and translate functions. It does not refer to the amount of elements!
M can be anything, given the two functions
-
limits(motif): Some function that given themotifit returns the(start, fine)of the the motif in the same units asq. This function establishes a measure of length, which simply isfine - start. -
translate(motif, t): Some function that given themotifit returns a new motif which is translated byt(either negative or positive), with respect to the same units asq.
Other Keywords
Please see the source code (use @which) for a full description of the algorithm.
-
tries = 5: Up to how many initial random sequences are accepted. -
taulcut = 2: Up to how times an element is dropped from the initial guess. -
summands = 3: Up to how many motifs may be combined as a sum to complete a sequence.
Simple Example
This example illustrates how the module MotifSequenceGenerator works using a simple struct. For a more realistic, and much more complex example, see the example using music notes.
Let’s say that we want to create a random sequence of "shouts", which are described by the struct
struct Shout
shout::String
start::Int
end
Let’s first create a vector of shouts that will be used as the pool of possible motifs that will create the random sequence:
using Random
shouts = [Shout(uppercase(randstring(rand(3:5))), rand(1:100)) for k in 1:5]
5-element Vector{Main.Shout}:
Main.Shout("W0C", 15)
Main.Shout("LL5XW", 59)
Main.Shout("YVHOF", 8)
Main.Shout("PEJVC", 9)
Main.Shout("HX03", 73)
Notice that at the moment the values of the .start field of Shout are irrelevant. MotifSequenceGenerator will translate all motifs to start point 0 while operating.
Now, to create a random sequence, we need to define two concepts:
shoutlimits(s::Shout) = (s.start, s.start + length(s.shout) + 1);
shouttranslate(s::Shout, n) = Shout(s.shout, s.start + n);
shouttranslate (generic function with 1 method)
This means that we accept that the temporal length of a Shout is length(s.shout) + 1.
We can now create random sequences of shouts that have total length of exactly q:
using MotifSequenceGenerator
q = 30
sequence, idxs = random_sequence(shouts, q, shoutlimits, shouttranslate)
sequence
6-element Vector{Main.Shout}:
Main.Shout("W0C", 0)
Main.Shout("LL5XW", 4)
Main.Shout("W0C", 10)
Main.Shout("W0C", 14)
Main.Shout("YVHOF", 18)
Main.Shout("LL5XW", 24)
sequence, idxs = random_sequence(shouts, q, shoutlimits, shouttranslate)
sequence
5-element Vector{Main.Shout}:
Main.Shout("LL5XW", 0)
Main.Shout("YVHOF", 6)
Main.Shout("YVHOF", 12)
Main.Shout("PEJVC", 18)
Main.Shout("LL5XW", 24)
Notice that it is impossible to create a sequence of length e.g. 7 with the above pool. Doing random_sequence(shouts, 7, shoutlimits, shouttranslate) would throw an error.
Floating point lengths
The lengths of the motifs do not have to be integers. When using motifs with floating lengths, it is advised to give a non-0 δq to random_sequence. The following example modifies the Shout struct and shows how it can be done with floating length.
struct FloatShout
shout::String
dur::Float64
start::Float64
end
rs(x) = uppercase(randstring(x))
shouts = [FloatShout(rs(rand(3:5)), rand()+1, rand()) for k in 1:5]
shoutlimits(s::FloatShout) = (s.start, s.start + s.dur);
shouttranslate(s::FloatShout, n) = FloatShout(s.shout, s.dur, s.start + n);
q = 10.0
δq = 1.0
r, s = random_sequence(shouts, q, shoutlimits, shouttranslate, δq)
r
6-element Vector{Main.FloatShout}:
Main.FloatShout("KVTW", 1.1276816927320024, 0.0)
Main.FloatShout("TTYJ", 1.5868177186878274, 1.1276816927320024)
Main.FloatShout("A1LSJ", 1.916592554483628, 2.7144994114198298)
Main.FloatShout("KVTW", 1.1276816927320024, 4.631091965903458)
Main.FloatShout("XXG", 1.7047743456209954, 5.7587736586354605)
Main.FloatShout("TTYJ", 1.5868177186878274, 7.463548004256456)
s
6-element Vector{Int64}:
3
1
4
3
2
1