Reference

Abstract type

SymbolicLongMemorySequencesModule
SymbolicLongMemorySequences

Self-Similar Symbols Sequence Synthesis.

SymbolicLongMemorySequences.jl generates Long-Range Dependent (LRD) sequences of categorical (non-numerical) symbols for use as ground-truth test data in LRD estimation studies.

Generators

IDTypeMechanism
PB1SpectralFGNSpectral fGn synthesis + quantization
PB2LGCMLatent Gaussian categorical model
PB3WaveletMarkovSpectral/Haar driver + Markov regimes
PB4IntermittentMapSymbolsIntermittent-map driver + quantization
MB1aLAMPLinear-Additive Markov Process
MB1bDyadicLAMPDyadic-bucket LAMP approximation
MB1cCalibratedAdditiveMarkovCentered additive memory function
MB2OnOffMarkovHeavy-tailed regime-switching Markov
MB3FSSFractal Symbol Sequence via FRP/FSNP
MB4aHawkesSymbolNormalized Hawkes-style symbol process
MB4bSelfExcitingMassUnnormalized self-exciting symbol mass
MB4cLogitSelfExcitingMassLog-contrast self-exciting symbol mass
MB5DuplicationMutationCopy-mutate symbolic growth

Common interface

generate(g, n; rng = Random.default_rng()) -> Vector
generate_with_latent(g, n; rng)             -> (Vector, Matrix)
make_generator(id, alphabet; kwargs...)     -> LRDGenerator
method_ids()                                -> Tuple
method_info(id)                             -> MethodInfo
method_parameters(id)                       -> Tuple
save_sequence(filepath, seq, g; created)   -> filepath

Examples

julia> g = make_generator(:PB1, [:a, :b]; H = 0.75)
SpectralFGN{Vector{Symbol}, Vector{Float64}}(H=0.75, k=2)

julia> length(generate(g, 16; rng = MersenneTwister(1)))
16
source
SymbolicLongMemorySequences.LRDGeneratorType
LRDGenerator

Abstract supertype for all LRD symbol-sequence generators in SymbolicLongMemorySequences.jl.

Concrete subtypes must implement:

generate(g::MyGenerator, n::Int; rng::AbstractRNG = Random.default_rng()) -> Vector

Examples

julia> SpectralFGN(0.8, [:a, :b]) isa LRDGenerator
true
source

Common interface

SymbolicLongMemorySequences.generateFunction
generate(g, n; rng = Random.default_rng()) -> Vector

Generate a sequence of n symbols using LRD generator g.

Returns a Vector whose element type matches the alphabet of g.

Arguments

  • g::LRDGenerator: configured generator instance.
  • n::Int: number of symbols to emit.

Keyword Arguments

  • rng::AbstractRNG: random number generator (default: Random.default_rng()).

Examples

julia> g = SpectralFGN(0.8, ['a', 'b', 'c'])
julia> seq = generate(g, 1000)
julia> length(seq) == 1000
true
source
SymbolicLongMemorySequences.generate_with_latentFunction
generate_with_latent(g::SpectralFGN, n; rng) -> sequence, latent

Generate n symbols and return the one-row latent fGn matrix used before quantization.

Examples

julia> g = SpectralFGN(0.75, [:a, :b]);
julia> seq, latent = generate_with_latent(g, 16; rng = MersenneTwister(1));
julia> length(seq), size(latent)
(16, (1, 16))
source
generate_with_latent(g::LGCM, n; rng) -> sequence, latent

Generate n symbols and return the k × n latent fGn matrix used by the calibrated argmax transform.

Examples

julia> g = LGCM(0.75, [:a, :b]; calibration_iters = 2);
julia> seq, latent = generate_with_latent(g, 16; rng = MersenneTwister(1));
julia> length(seq), size(latent)
(16, (2, 16))
source
generate_with_latent(g::WaveletMarkov, n; rng) -> sequence, latent

Generate n symbols and return the one-row latent regime-driver matrix used before rank-binning into Markov regimes.

Examples

julia> P = [0.9 0.1; 0.2 0.8];
julia> g = WaveletMarkov(0.75, [:a, :b], [P, P]);
julia> seq, latent = generate_with_latent(g, 16; rng = MersenneTwister(1));
julia> length(seq), size(latent)
(16, (1, 16))
source
generate_with_latent(g::IntermittentMapSymbols, n; rng) -> sequence, latent

Generate n symbols and return the one-row intermittent-map driver matrix used before quantization.

Examples

julia> g = IntermittentMapSymbols(1.6, [:a, :b]; burnin = 10);
julia> seq, latent = generate_with_latent(g, 16; rng = MersenneTwister(1));
julia> length(seq), size(latent)
(16, (1, 16))
source
generate_with_latent(g, n; rng) -> sequence, latent

Generate a property-based symbolic sequence and return the numerical latent series used before symbolization.

The returned latent value is a width × n matrix, where width is latent_width of the symbolizer. This helper is intended for validation and research workflows where the numerical long-memory driver should be diagnosed alongside the final symbolic sequence. It is additive to the common generate contract; ordinary callers can continue to use generate(g, n; rng).

Examples

julia> g = PropertyBasedGenerator(SpectralFGNSource(0.75),
...                               QuantileSymbolizer([:a, :b]));

julia> seq, latent = generate_with_latent(g, 16; rng = MersenneTwister(1));

julia> length(seq), size(latent)
(16, (1, 16))
source
SymbolicLongMemorySequences.MethodInfoType
MethodInfo

Metadata returned by method_info for one SymbolicLongMemorySequences synthesis method.

Fields:

  • id: stable method identifier, such as :PB1 or :MB5.
  • family: :property_based or :model_based.
  • type_name: exported generator type name.
  • defaults: standard-case keyword defaults used by make_generator.
  • parameters: keyword metadata for the factory inputs accepted by this method.
  • standard_cases: named construction presets accepted by make_generator.
  • description: short human-readable summary.

Examples

julia> info = method_info(:PB1)
MethodInfo(id=PB1, type=SpectralFGN)

julia> info.defaults.H
0.8

julia> method_parameters(:PB1)[1].name
:H
source
SymbolicLongMemorySequences.ParameterInfoType
ParameterInfo

Metadata for one keyword accepted by make_generator.

Fields:

  • name: keyword name.
  • kind: currently :keyword; reserved for future input categories.
  • default: factory default value.
  • domain: concise domain or accepted-value summary.
  • description: short human-readable explanation.

Examples

julia> p = method_parameters(:PB1)[1]
ParameterInfo(name=H, default=0.8)

julia> p.domain
"0.5 < H < 1"
source
SymbolicLongMemorySequences.method_idsFunction
method_ids(; family = :all) -> Tuple{Vararg{Symbol}}

Return the stable method identifiers accepted by make_generator.

Use family = :property_based or family = :model_based to filter the list.

Examples

julia> method_ids()[1:3]
(:PB1, :PB2, :PB3)

julia> :MB5 in method_ids(family = :model_based)
true
source
SymbolicLongMemorySequences.method_infoFunction
method_info(id) -> MethodInfo
method_info() -> Tuple{Vararg{MethodInfo}}

Return metadata and standard defaults for one method accepted by make_generator. id may be a method identifier such as :PB1 or an exported type name such as :SpectralFGN. With no argument, return metadata for all methods in method_ids order.

Examples

julia> method_info(:MB5).type_name
:DuplicationMutation

julia> method_info(:SpectralFGN).id
:PB1

julia> length(method_info()) == length(method_ids())
true
source
SymbolicLongMemorySequences.method_parametersFunction
method_parameters(id) -> Tuple{Vararg{ParameterInfo}}

Return keyword metadata for the factory inputs accepted by one method.

This is a discovery helper for user interfaces, examples, and benchmark grids. All methods still require the positional alphabet input to make_generator, and sequence length n is supplied later to generate.

Examples

julia> first(method_parameters(:PB1)).name
:H

julia> any(p -> p.name === :mutation_probability, method_parameters(:MB5))
true
source
SymbolicLongMemorySequences.make_generatorFunction
make_generator(id, alphabet; kwargs...) -> LRDGenerator

Construct a standard SymbolicLongMemorySequences generator by method identifier.

This is a convenience API for common cases. It does not replace the explicit scientific constructors: use method_info(id).defaults to inspect default parameters, then pass keyword overrides as needed. id may be a method id (:PB1, :MB1c) or a type name (:SpectralFGN, :DuplicationMutation).

Common Keywords

  • marginal = :uniform: target marginal where the method has one.
  • case: standard preset for methods that need local/regime structure.

Examples

julia> g = make_generator(:PB1, [:a, :b]; H = 0.75)
SpectralFGN{Vector{Symbol}, Vector{Float64}}(H=0.75, k=2)

julia> generate(g, 4; rng = MersenneTwister(1)) isa Vector{Symbol}
true

julia> make_generator(:MB5, ['A', 'C']; alpha = 1.4, max_block_length = 128)
DuplicationMutation{Vector{Char}, Vector{Float64}}(α=1.4, k=2, μ=0.02, seed=64, max_block=128)
source
SymbolicLongMemorySequences.save_sequenceFunction
save_sequence(filepath, seq, gen; created = string(today())) -> filepath

Write a generated symbol sequence to an INC file (IncCSV.jl format) with full provenance metadata.

The INC file contains:

  • A metadata block recording the SymbolicLongMemorySequences.jl package version, the generator type and all its parameters, and the creation date.
  • A two-column CSV body: index (1-based integer) and symbol (string).

Arguments

  • filepath::AbstractString: output path (.inc extension recommended).
  • seq::AbstractVector: symbol sequence as returned by generate.
  • gen::LRDGenerator: the generator instance used to produce seq.

Keyword Arguments

  • created::String: creation date (default: today's date in ISO 8601 format).

Returns

filepath, to allow chaining.

Examples

julia> g   = SpectralFGN(0.8, [:a, :b, :c])
julia> seq = generate(g, 1000)
julia> save_sequence("output.inc", seq, g)
"output.inc"
source
SymbolicLongMemorySequences.LocalStructureSpecType
LocalStructureSpec

Abstract supertype for explicit local-structure specifications.

MarkovSpec is the current concrete first-order specification. Future higher-order specifications, such as sparse trigram controls, should subtype LocalStructureSpec and define local_structure_order.

Examples

julia> MarkovSpec([:a, :b], [0.9 0.1; 0.2 0.8]) isa LocalStructureSpec
true
source
SymbolicLongMemorySequences.MarkovSpecType
MarkovSpec(alphabet, transition_matrix)

Validated first-order Markov specification over an ordered symbol alphabet.

transition_matrix[i, j] is the conditional probability of emitting alphabet[j] after alphabet[i].

Examples

julia> spec = MarkovSpec([:a, :b], [0.9 0.1; 0.2 0.8])
MarkovSpec{Vector{Symbol}}(k=2)

julia> spec.transition_matrix[1, :]
2-element Vector{Float64}:
 0.9
 0.1
source
SymbolicLongMemorySequences.local_structure_orderFunction
local_structure_order(spec) -> Int

Return the Markov order of a local-structure specification.

MarkovSpec has order 1. This function is the extension point for future higher-order local-structure specifications; SymbolicLongMemorySequences.jl does not currently expose a trigram-control specification.

Examples

julia> local_structure_order(MarkovSpec([:a, :b], [0.9 0.1; 0.2 0.8]))
1
source
SymbolicLongMemorySequences.ControlCapabilitiesType
ControlCapabilities

Programmatic description of a generator's user-facing control strengths.

Fields use stable symbolic levels:

  • alphabet: :exact
  • marginal: :finite_sample, :empirical, :implied, :innovation_target, or :asymptotic
  • bigram: :per_regime or :induced
  • trigram: :induced
  • lrd: :approximate, :latent_approximate, :finite_history, or :nominal

Examples

julia> caps = control_capabilities(SpectralFGN(0.8, [:a, :b]));
julia> caps.alphabet, caps.marginal
(:exact, :finite_sample)
source
SymbolicLongMemorySequences.control_capabilitiesFunction
control_capabilities(g) -> ControlCapabilities

Return the declared control strengths of generator g.

Examples

julia> control_capabilities(SpectralFGN(0.8, [:a, :b])).marginal
:finite_sample

julia> control_capabilities(FSS(1.5, [:a, :b])).bigram
:induced
source

Property-based generators

SymbolicLongMemorySequences.PropertyBasedGeneratorType
PropertyBasedGenerator(source, symbolizer)

Composable property-based generator.

Property-based synthesis has two layers: a numerical LatentSource that carries the large-scale dependence, and a Symbolizer that maps the latent series to a finite alphabet. Not every source can feed every symbolizer; construction checks the required latent_width.

Named generators such as SpectralFGN, LGCM, WaveletMarkov, and IntermittentMapSymbols remain the stable standard cases. PropertyBasedGenerator exposes the lower-level composition path for controlled experiments.

Examples

julia> src = SpectralFGNSource(0.8);
julia> sym = QuantileSymbolizer([:a, :b], [0.25, 0.75]);
julia> g = PropertyBasedGenerator(src, sym)
PropertyBasedGenerator(source=SpectralFGNSource, symbolizer=QuantileSymbolizer)

julia> length(generate(g, 16; rng = MersenneTwister(1)))
16
source
SymbolicLongMemorySequences.SpectralFGNSourceType
SpectralFGNSource(H)

Numerical latent source using the approximate spectral fGn construction also used by SpectralFGN.

The source can generate any positive number of independent latent streams. Each stream uses Hurst parameter H. This makes it compatible with one-stream symbolizers such as QuantileSymbolizer and multi-stream symbolizers such as ArgmaxSymbolizer.

Examples

julia> src = SpectralFGNSource(0.75)
SpectralFGNSource(H=0.75)

julia> size(generate_latent(src, 8, 2; rng = MersenneTwister(1)))
(2, 8)
source
SymbolicLongMemorySequences.HaarLRDSourceType
HaarLRDSource(H; cascade_depth = 0)

Numerical latent source using the simple Haar-like cascade retained for PB3 comparison studies.

cascade_depth = 0 means choose floor(log2(n)) at generation time. This is a pragmatic finite-sample latent driver, not a calibrated wavelet synthesis package.

Examples

julia> src = HaarLRDSource(0.8; cascade_depth = 3)
HaarLRDSource(H=0.8, cascade_depth=3)

julia> size(generate_latent(src, 8, 1; rng = MersenneTwister(1)))
(1, 8)
source
SymbolicLongMemorySequences.IntermittentMapSourceType
IntermittentMapSource(z; burnin = 1000)

One-stream numerical latent source using the Pomeau-Manneville-style intermittent map also used by IntermittentMapSymbols.

Because this source represents one deterministic latent map trajectory, it is compatible with one-stream symbolizers such as QuantileSymbolizer and MarkovRegimeSymbolizer, but not with ArgmaxSymbolizer.

Examples

julia> src = IntermittentMapSource(1.6; burnin = 10)
IntermittentMapSource(z=1.6, burnin=10)

julia> size(generate_latent(src, 8, 1; rng = MersenneTwister(1)))
(1, 8)
source
SymbolicLongMemorySequences.QuantileSymbolizerType
QuantileSymbolizer(alphabet [, marginal])

One-stream symbolizer using rank/quantile binning.

The sorted latent values are assigned to alphabet with finite-sample counts as close as possible to marginal.

Examples

julia> sym = QuantileSymbolizer([:a, :b], [0.25, 0.75])
QuantileSymbolizer{Vector{Symbol}, Vector{Float64}}(k=2)

julia> latent_width(sym)
1
source
SymbolicLongMemorySequences.ArgmaxSymbolizerType
ArgmaxSymbolizer(alphabet [, marginal]; calibration_iters = 25,
                 calibration_rate = 0.7)

Multi-stream symbolizer using calibrated argmax over one latent series per alphabet symbol.

This is the symbolization transform used by LGCM. It requires latent_width(symbolizer) == length(alphabet).

Examples

julia> sym = ArgmaxSymbolizer([:a, :b, :c])
ArgmaxSymbolizer{Vector{Symbol}, Vector{Float64}}(k=3)

julia> latent_width(sym)
3
source
SymbolicLongMemorySequences.MarkovRegimeSymbolizerType
MarkovRegimeSymbolizer(alphabet, transition_matrices;
                       regime_weights = uniform)

One-stream symbolizer that rank-bins a latent driver into regimes, then emits symbols from regime-specific Markov transition matrices.

This is the symbolization transform used by WaveletMarkov. The latent source supplies regime persistence; the transition matrices supply local bigram structure.

Examples

julia> P1 = [0.9 0.1; 0.2 0.8];
julia> P2 = [0.3 0.7; 0.6 0.4];
julia> sym = MarkovRegimeSymbolizer([:a, :b], [P1, P2])
MarkovRegimeSymbolizer{Vector{Symbol}, Vector{Float64}}(k=2, R=2)

julia> latent_width(sym)
1
source
SymbolicLongMemorySequences.latent_widthFunction
latent_width(symbolizer) -> Int

Return the number of latent numerical series required by symbolizer.

Examples

julia> latent_width(QuantileSymbolizer([:a, :b]))
1

julia> latent_width(ArgmaxSymbolizer([:a, :b]))
2
source
SymbolicLongMemorySequences.generate_latentFunction
generate_latent(source, n, width; rng) -> Matrix{Float64}

Generate a width × n matrix of numerical latent series from source.

Examples

julia> latent = generate_latent(SpectralFGNSource(0.75), 8, 2;
...                            rng = MersenneTwister(1));
julia> size(latent)
(2, 8)
source
SymbolicLongMemorySequences.symbolizeFunction
symbolize(symbolizer, latent; rng) -> Vector

Map a width × n latent matrix to symbols using symbolizer.

Examples

julia> latent = reshape([0.1, 0.8, 0.2, 0.9], 1, 4);
julia> symbolize(QuantileSymbolizer([:a, :b]), latent; rng = MersenneTwister(1))
4-element Vector{Symbol}:
 :a
 :b
 :a
 :b
source
SymbolicLongMemorySequences.SpectralFGNType
SpectralFGN(H, alphabet [, marginal])

Property-based LRD symbol-sequence generator (PB1).

Synthesises fractional Gaussian noise (fGn) with Hurst parameter H via an approximate spectral (FFT) method, then maps the real-valued output to symbols using sample-quantile thresholding targeting a prescribed marginal distribution.

Arguments

  • H::Real: Hurst parameter, H ∈ (0.5, 1.0). Higher values give stronger LRD.
  • alphabet: ordered collection of symbols.
  • marginal::AbstractVector{<:Real}: target marginal probabilities (default: uniform).

Complexity

O(n log n) time, O(n) memory.

Notes

Short-range structure (bigrams, etc.) is determined entirely by the quantization scheme and cannot be prescribed independently. For joint control of LRD and local structure see LAMP.

The spectral method is approximate: it reproduces the asymptotic spectral slope correctly but may deviate from the exact fGn autocovariance near lag 0. Requires n ≥ 4 (at least one interior frequency pair).

References

Paxson, V. (1997). Fast, approximate synthesis of fractional Gaussian noise for generating self-similar network traffic. Computer Communications Review 27, 5–18.

Dieker, T. (2004). Simulation of fractional Brownian motion. PhD thesis, University of Twente.

Examples

julia> g = SpectralFGN(0.8, [:a, :b, :c])
SpectralFGN{Vector{Symbol}, Vector{Float64}}(H=0.8, k=3)

julia> seq = generate(g, 4096; rng = MersenneTwister(1))
julia> length(seq) == 4096 && eltype(seq) == Symbol
true
source
SymbolicLongMemorySequences.LGCMType
LGCM(H, alphabet [, marginal]; calibration_iters = 25, calibration_rate = 0.7)

Property-based LRD symbol-sequence generator (PB2): Latent Gaussian Categorical Model.

For each symbol, LGCM generates a latent fGn stream with Hurst parameter H. At each time step the emitted symbol is the argmax of the latent streams after adding per-symbol offsets. The offsets are calibrated on the generated latent sample so the output marginal is close to the requested marginal.

Arguments

  • H::Real: Hurst parameter, H ∈ (0.5, 1.0).
  • alphabet: ordered collection of unique symbols.
  • marginal::AbstractVector{<:Real}: target marginal probabilities.

Keyword Arguments

  • calibration_iters::Int = 25: number of mean-offset calibration passes.
  • calibration_rate::Real = 0.7: step size for the log-ratio calibration update.

Complexity

O(calibration_iters · n · k) time and O(n · k) memory.

Notes

The marginal calibration is empirical: it adjusts offsets for the realised latent sample rather than solving the exact multivariate Gaussian choice probabilities. It gives practical marginal control while preserving the latent argmax mechanism. For exact finite-sample marginal counts, use SpectralFGN.

Examples

julia> g = LGCM(0.8, [:a, :b], [0.4, 0.6]; calibration_iters = 3)
LGCM{Vector{Symbol}, Vector{Float64}}(H=0.8, k=2)

julia> length(generate(g, 128; rng = MersenneTwister(1)))
128
source
SymbolicLongMemorySequences.WaveletMarkovType
WaveletMarkov(H, alphabet, transition_matrices;
              regime_weights = uniform, cascade_depth = auto,
              driver = :spectral)

Property-based LRD symbol-sequence generator (PB3): multiscale cascade driving a Markov state machine.

WaveletMarkov generates a latent long-memory driver, rank-bins the driver into regimes, and lets each regime select one Markov transition matrix over alphabet. The default driver = :spectral uses the same approximate spectral fGn synthesis as SpectralFGN before rank-binning. The legacy driver = :haar path keeps the original simple Haar-style Gaussian cascade for comparison and validation studies.

Arguments

  • H::Real: Hurst parameter for the latent multiscale driver, H ∈ (0.5, 1.0).
  • alphabet: ordered collection of unique symbols.
  • transition_matrices: vector of row-stochastic k × k matrices, one per regime.

Keyword Arguments

  • regime_weights: target fraction of time spent in each regime. Defaults to uniform over regimes.
  • cascade_depth::Int = 0: number of dyadic cascade levels. 0 means choose floor(log2(n)) at generation time. Used only with driver = :haar.
  • driver::Symbol = :spectral: latent regime driver, either :spectral or :haar.

Complexity

O(n log n + n k) time with O(n + R k²) memory.

Notes

This is a pragmatic PB3 implementation: the spectral driver gives the current default latent LRD pathway, while the Haar-like cascade is retained as a comparison path rather than a calibrated wavelet synthesis package. The important interface property is present: local bigram structure is controlled by explicit Markov matrices while a latent long-memory process controls regime persistence.

Symbol-level ACF and spectrum diagnostics only see this regime persistence when the regimes have different observable stationary symbol distributions. If every regime has the same stationary marginal, the latent multiscale process may be mostly hidden from one-hot symbol diagnostics.

Examples

julia> P1 = [0.9 0.1; 0.2 0.8];
julia> P2 = [0.3 0.7; 0.6 0.4];
julia> g = WaveletMarkov(0.8, [:a, :b], [P1, P2])
WaveletMarkov{Vector{Symbol}, Vector{Float64}}(H=0.8, k=2, R=2, driver=spectral)

julia> length(generate(g, 64; rng = MersenneTwister(1)))
64
source
SymbolicLongMemorySequences.IntermittentMapSymbolsType
IntermittentMapSymbols(z, alphabet [, marginal]; burnin = 1000)

Property-based symbolic generator (PB4) using a latent intermittent map.

The latent driver follows the Pomeau-Manneville-style update

x[t+1] = (x[t] + x[t]^z) mod 1

from a random initial state. Intermittency near zero can create long laminar episodes and broad finite-scale dependence. The generated real-valued driver is rank-binned into alphabet, so finite-sample symbol counts are as close as possible to marginal.

This is a latent-dynamics generator, not an exact symbolic LRD construction. The parameter z controls the strength of intermittency, but SymbolicLongMemorySequences.jl does not claim a closed-form finite-sample Hurst parameter for this model.

Arguments

  • z::Real: intermittency exponent, z > 1.
  • alphabet: ordered collection of symbols.
  • marginal::AbstractVector{<:Real}: target marginal probabilities (default: uniform).

Keyword Arguments

  • burnin::Int = 1000: number of latent-map iterations discarded before collecting the driver.

Complexity

O(n log n) time from rank binning, O(n) memory.

References

Provata, A., & Beck, C. (2012). Coupled intermittent maps modelling the statistics of genomic sequences: a network approach. arXiv:1205.2249.

Examples

julia> g = IntermittentMapSymbols(1.6, [:A, :B], [0.4, 0.6])
IntermittentMapSymbols{Vector{Symbol}, Vector{Float64}}(z=1.6, k=2, burnin=1000)

julia> seq = generate(g, 1024; rng = MersenneTwister(1))
julia> length(seq) == 1024 && eltype(seq) == Symbol
true
source

Model-based generators

SymbolicLongMemorySequences.LAMPType
LAMP(beta, alphabet [, marginal]; d = 1000, epsilon = 0.01,
     transition_matrix = identity)

Model-based LRD symbol-sequence generator (MB1a): exact finite-history Linear-Additive Markov Process.

At each step the probability of the next symbol is a convex combination of transition-matrix rows selected by the most recent d history symbols, mixed with an optional innovation term:

q(s) = (1 - epsilon) * Σⱼ wⱼ * P[Xₜ₋ⱼ, s] + epsilon * p(s)

with power-law weights wⱼ ∝ j^{-(1+β)}, so the autocovariance decays as a power law with exponent β up to the finite history depth, giving nominal Hurst parameter H = (2−β)/2.

Arguments

  • beta::Real: ACF decay exponent, β ∈ (0, 1).
  • alphabet: ordered collection of symbols.
  • marginal::AbstractVector{<:Real}: stationary marginal (default: uniform).

Keyword Arguments

  • d::Int = 1000: history depth. The effective LRD range is bounded by d; for finite sequences d may exceed n. Only observed history contributes; missing pre-history mass is assigned to the target marginal.
  • epsilon::Real = 0.01: marginal innovation probability. Larger values improve finite-sample marginal control but weaken history dependence.
  • transition_matrix: row-stochastic transition matrix over alphabet. The default is identity, so history symbols tend to copy themselves. Use lamp_repeat_transition for a simple identity/dyad mixture.

Complexity

O(n·min(d,n)) time, O(d + n) memory.

References

Kumar, R., Raghu, M., Sarlos, T., & Tomkins, A. (2017). Linear additive Markov processes. WWW '17, 411–419.

Singh, M., Greenberg, C., & Klakow, D. (2016). The custom decay language model for long range dependencies. TSD, 343–351.

Examples

julia> g = LAMP(0.5, [:a, :b, :c]; d = 500, epsilon = 0.02)
LAMP{Vector{Symbol}, Vector{Float64}}(β=0.5, k=3, d=500, ε=0.02)

julia> seq = generate(g, 5000; rng = MersenneTwister(42))
julia> length(seq) == 5000 && eltype(seq) == Symbol
true
source
SymbolicLongMemorySequences.DyadicLAMPType
DyadicLAMP(beta, alphabet [, marginal]; d = 1_000_000, epsilon = 0.01,
           transition_matrix = identity)

Scalable dyadic-bucket approximation to LAMP (MB1b).

DyadicLAMP uses the same power-law lag weights and transition-matrix control as exact LAMP, but compresses observed history into age buckets 1, 2:3, 4:7, and so on. Each bucket contributes its total power-law weight times the empirical symbol mix in that bucket. Missing pre-history mass is assigned to the target marginal.

This is a finite-sequence approximation for large d and long sequences; it is not an exact replacement for LAMP.

Complexity

O(n · k · log(n) · log(min(d, n))) time and O(n · k) memory, where k is the alphabet size.

Examples

julia> p = [0.4, 0.6]
julia> P = lamp_repeat_transition(p; repeat_probability = 0.8)
julia> g = DyadicLAMP(0.5, [:a, :b], p; d = 10_000, transition_matrix = P)
DyadicLAMP{Vector{Symbol}, Vector{Float64}}(β=0.5, k=2, d=10000, ε=0.01)

julia> length(generate(g, 1000; rng = MersenneTwister(1))) == 1000
true
source
SymbolicLongMemorySequences.CalibratedAdditiveMarkovType
CalibratedAdditiveMarkov(beta, alphabet [, marginal]; d = 1000,
                         strength = 0.8)

Model-based symbolic generator (MB1c) using a centered additive Markov memory function.

At each step, the next-symbol probabilities are

q(s) = p(s) + strength * Σⱼ wⱼ * (1[X[t-j] = s] - p(s)),

where p is the target marginal and wⱼ ∝ j^(-beta) over 1:d. The centered terms sum to zero across symbols, so q remains a probability vector for strength ∈ [0, 1]. Larger strength gives more weight to observed history; strength = 0 gives iid draws from marginal.

This generator is related to additive Markov-chain memory-function models. It is finite-history and does not claim exact asymptotic LRD beyond the configured memory depth d.

Arguments

  • beta::Real: nominal memory-function decay exponent, beta ∈ (0, 1).
  • alphabet: ordered collection of symbols.
  • marginal::AbstractVector{<:Real}: target marginal probabilities (default: uniform).

Keyword Arguments

  • d::Int = 1000: history depth and finite memory cutoff.
  • strength::Real = 0.8: history coupling strength in [0, 1].

Complexity

O(n·min(d,n)) time, O(n) memory.

References

Melnyk, S. S., Usatenko, O. V., & Yampol'skii, V. A. (2006). Memory functions of the additive Markov chains: applications to complex dynamic systems. Physica A 361, 405-415.

Mayzelis, Z. A., Apostolov, S. S., Melnyk, S. S., Usatenko, O. V., & Yampol'skii, V. A. (2006). Additive N-step Markov chains as prototype model of symbolic stochastic dynamical systems with long-range correlations.

Examples

julia> g = CalibratedAdditiveMarkov(0.4, [:x, :y], [0.3, 0.7]; d = 200)
CalibratedAdditiveMarkov{Vector{Symbol}, Vector{Float64}}(β=0.4, k=2, d=200, strength=0.8)

julia> length(generate(g, 1000; rng = MersenneTwister(1))) == 1000
true
source
SymbolicLongMemorySequences.OnOffMarkovType
OnOffMarkov(alpha, alphabet, transition_matrices, switching_matrix; L_min = 1.0)

Model-based LRD symbol-sequence generator (MB2): Heavy-tailed On/Off doubly-stochastic Markov chain.

The generator alternates between regimes. Each regime has its own Markov transition matrix over alphabet; regime sojourn lengths are Pareto-distributed with tail index alpha. A row-stochastic switching_matrix controls which regime follows the current one after a sojourn ends.

Arguments

  • alpha::Real: Pareto tail index, alpha ∈ (1, 2), with nominal H = (3 - alpha) / 2.
  • alphabet: ordered collection of unique symbols.
  • transition_matrices: vector of row-stochastic k × k matrices, one per regime.
  • switching_matrix: row-stochastic R × R regime transition matrix.

Keyword Arguments

  • L_min::Real = 1.0: Pareto scale parameter for regime sojourns.

Complexity

O(n · k) time with the current sequential sampler and O(n + R · k²) memory.

Notes

This method is the natural first implementation for user-specified bigram structure: each regime has an explicit Markov transition matrix. Aggregate marginals and bigrams depend on regime occupancy, switching dynamics, and the per-regime stationary distributions.

For finite symbol-level ACF and spectrum diagnostics, use regimes with different observable stationary symbol distributions and choose L_min large enough for heavy-tailed sojourns to appear at the simulated sequence length. Regimes with identical stationary marginals can carry latent long memory while looking nearly short-memory to one-hot diagnostics.

Examples

julia> P1 = [0.9 0.1; 0.2 0.8];
julia> P2 = [0.3 0.7; 0.6 0.4];
julia> Q = [0.2 0.8; 0.8 0.2];
julia> g = OnOffMarkov(1.4, [:a, :b], [P1, P2], Q; L_min = 2.0)
OnOffMarkov{Vector{Symbol}}(α=1.4, H≈0.8, k=2, R=2)

julia> length(generate(g, 64; rng = MersenneTwister(1)))
64
source
SymbolicLongMemorySequences.FSSType
FSS(alpha, alphabet; rates = ones(k), x_min = 1.0)

Model-based LRD symbol-sequence generator (MB3): Fractal Symbol Sequence.

Each symbol is governed by an independent Pareto-distributed renewal process: inter-arrival times τ ~ Pareto(α, x_min). The output merges all symbol streams in event-time order — the symbol with the earliest pending event is emitted at each step.

LRD arises through heavy-tailed inter-arrival times. For tail index α ∈ (1, 2), the return-time variance is infinite, giving nominal Hurst parameter H = (3−α)/2.

Arguments

  • alpha::Real: Pareto tail index, α ∈ (1, 2).
  • alphabet: ordered collection of symbols.

Keyword Arguments

  • rates::AbstractVector{<:Real}: per-symbol base arrival rates. Symbol i appears with long-run frequency proportional to rates[i]. Default: uniform.
  • x_min::Real = 1.0: Pareto scale parameter (minimum inter-arrival time).

Complexity

O(n·k) time, O(k + n) memory (k = alphabet size).

Notes

Because each symbol stream is independent, joint symbol statistics (bigrams, etc.) cannot be prescribed independently of the marginal.

Missing-scales pitfall (Roughan, Yates & Veitch 1999): if the mean inter-arrival time x_min · α/(α−1) / rateᵢ is large relative to n, the observable LRD scale range is reduced. Keep rates such that each symbol appears O(√n) or more times.

References

Lowen, S. B., & Teich, M. C. (1995). Estimation and simulation of fractal stochastic point processes. Fractals 3(1), 183–210.

Roughan, M., Yates, J., & Veitch, D. (1999). The mystery of the missing scales: pitfalls in the use of fractal renewal processes. Applications of Heavy Tailed Distributions in Economics, Engineering and Statistics.

Examples

julia> g = FSS(1.4, [:a, :b, :c])
FSS{Vector{Symbol}, Vector{Float64}}(α=1.4, H≈0.8, k=3)

julia> seq = generate(g, 5000; rng = MersenneTwister(7))
julia> length(seq) == 5000 && eltype(seq) == Symbol
true
source
SymbolicLongMemorySequences.HawkesSymbolType
HawkesSymbol(beta, alphabet; baseline = ones(k), excitation = I,
             d = 1000, c = 1.0)

Model-based symbolic generator (MB4a): normalized discrete-time Hawkes-style symbols.

At each step the generator forms a non-negative intensity for every symbol,

\[lambda_j(t) = baseline_j + \sum_{l=1}^{\min(d,t-1)} w_l excitation_{X_{t-l},j},\]

where w_l is proportional to (l + c)^(-beta). The next symbol is sampled with probability proportional to these intensities.

This is a finite-history, discrete-time symbolic analogue of the Hawkes-process word-occurrence model of Ogura, Hanada, Amano, and Kondo (2022). It is useful for creating bursty word-like symbolic sequences: with an identity excitation matrix, recent appearances of a symbol raise its chance of appearing again.

Arguments

  • beta::Real: power-law memory-kernel exponent, beta in (0, 1).
  • alphabet: ordered collection of unique symbols.

Keyword Arguments

  • baseline::AbstractVector{<:Real}: positive baseline symbol intensities.
  • excitation::AbstractMatrix{<:Real}: non-negative k x k matrix where row i contributes excitation after observing alphabet[i].
  • d::Integer = 1000: finite history depth.
  • c::Real = 1.0: positive kernel offset.

Complexity

O(n * k * min(d, n)) time, O(n + d) memory.

Notes

target_marginal(g) reports baseline / sum(baseline), but the realized marginal also depends on excitation, beta, d, and finite-sample effects. This method should therefore be treated as having an implied marginal, not exact marginal control.

References

Ogura, H., Hanada, Y., Amano, H., & Kondo, M. (2022). Modeling long-range dynamic correlations of words in written texts with Hawkes processes. Entropy, 24(7),

  1. https://doi.org/10.3390/e24070858

Examples

julia> g = HawkesSymbol(0.6, [:a, :b]; baseline = [1.0, 1.0],
...                     excitation = [2.0 0.0; 0.0 2.0], d = 100)
HawkesSymbol{Vector{Symbol}}(beta=0.6, k=2, d=100)

julia> seq = generate(g, 1000; rng = MersenneTwister(7))
julia> length(seq) == 1000 && eltype(seq) == Symbol
true
source
SymbolicLongMemorySequences.SelfExcitingMassType
SelfExcitingMass(beta, alphabet, marginal = uniform; default_mass = 1.0,
                 excitation_strength = 1.0, smoothing = 0.05,
                 excitation = I, d = 1000, c = 1.0)

Model-based symbolic generator (MB4b): unnormalized self-exciting symbol mass.

At time t, the generator assigns a non-negative mass to each symbol,

\[m_j(t) = b p_j + \eta\left(s p_j + \sum_{l=1}^{\min(d,t-1)} (l + c)^{-\beta} E_{X_{t-l},j}\right),\]

where p is the target/default marginal, b = default_mass, eta = excitation_strength, s = smoothing, and E is a non-negative excitation matrix. The next symbol is sampled from m(t) / sum(m(t)).

Unlike HawkesSymbol, the power-law kernel is not normalized. The total history mass can therefore grow over the represented scale range, allowing the self-exciting component to dominate the default marginal after startup while the default and smoothing masses keep all symbols reachable. This is a discrete-time categorical adaptation of Hawkes-style self-excitation rather than a fitted continuous-time Hawkes process.

Arguments

  • beta::Real: power-law memory-kernel exponent, beta in (0, 1).
  • alphabet: ordered collection of unique symbols.
  • marginal: target/default symbol probabilities. Defaults to uniform.

Keyword Arguments

  • default_mass::Real = 1.0: baseline mass in the target marginal direction.
  • excitation_strength::Real = 1.0: multiplier for the self-exciting mass.
  • smoothing::Real = 0.05: target-marginal floor inside the excitation component.
  • excitation::AbstractMatrix{<:Real}: non-negative k x k matrix where row i contributes excitation after observing alphabet[i].
  • d::Integer = 1000: finite history depth.
  • c::Real = 1.0: positive kernel offset.

Complexity

O(n * k * min(d, n)) time, O(n + d) memory.

Notes

target_marginal(g) reports marginal, but strong excitation can distort the finite-sample realized marginal. Use validation diagnostics when marginal control matters.

References

The construction is motivated by Hawkes self-excitation and the use of Hawkes processes for long-range word recurrence, but modifies the categorical sampler by using an unnormalized discrete-time power-law memory mass.

Examples

julia> g = SelfExcitingMass(0.4, [:a, :b], [0.5, 0.5]; d = 100,
...                        default_mass = 0.2, excitation_strength = 1.0)
SelfExcitingMass{Vector{Symbol}, Vector{Float64}}(beta=0.4, k=2, d=100)

julia> seq = generate(g, 1000; rng = MersenneTwister(7))
julia> length(seq) == 1000 && eltype(seq) == Symbol
true
source
SymbolicLongMemorySequences.LogitSelfExcitingMassType
LogitSelfExcitingMass(beta, alphabet, marginal = uniform;
                      default_mass = 0.2,
                      excitation_strength = 1.0,
                      smoothing = 0.05,
                      contrast_strength = 1.0,
                      log_floor = 1e-12,
                      excitation = I,
                      d = nothing,
                      c = 0.0)

Model-based symbolic generator (MB4c): log-contrast self-exciting symbol mass.

This variant keeps the MB4b idea of an unnormalized power-law excitation mass, but converts that mass into a centered log contrast before categorical sampling. At time t, define

M_j(t) = (b + eta * s) * p_j
       + eta * sum_{l=1}^{L_t} (l + c)^(-beta) * E[X_{t-l}, j]

where L_t = t - 1 when d === nothing, otherwise L_t = min(d, t - 1). MB4c then computes a centered log contrast,

theta_j(t) = a * (log(M_j(t) + epsilon)
             - sum_i p_i * log(M_i(t) + epsilon))

and samples with weights proportional to

p_j * exp(theta_j(t)).

The centering removes common-mode growth in the total excitation mass before the final probability normalization. Thus d is best read as a computational truncation depth; d = nothing represents the full available discrete history. The offset c is a short-lag regularizer, not a long-memory exponent; the asymptotic decay is controlled by beta.

Arguments

  • beta::Real: power-law memory-kernel exponent, beta in (0, 1).
  • alphabet: ordered collection of unique symbols.
  • marginal: target/default symbol probabilities. Defaults to uniform.

Keyword Arguments

  • default_mass::Real = 0.2: baseline mass in the target marginal direction.
  • excitation_strength::Real = 1.0: multiplier for self-excitation.
  • smoothing::Real = 0.05: target-marginal floor inside the excitation mass.
  • contrast_strength::Real = 1.0: multiplier applied to centered log contrasts.
  • log_floor::Real = 1e-12: positive floor used inside the logarithm.
  • excitation::AbstractMatrix{<:Real}: non-negative symbol excitation matrix.
  • d::Union{Nothing,Integer} = nothing: computational history truncation.
  • c::Real = 0.0: non-negative short-lag kernel offset.

Complexity

O(n * k * min(d, n)) time for finite d, O(n^2 k) time for d = nothing, and O(n) memory.

Examples

julia> g = LogitSelfExcitingMass(0.4, [:a, :b], [0.5, 0.5]; d = 100)
LogitSelfExcitingMass{Vector{Symbol}, Vector{Float64}}(beta=0.4, k=2, d=100)

julia> seq = generate(g, 1000; rng = MersenneTwister(7))
julia> length(seq) == 1000 && eltype(seq) == Symbol
true
source
SymbolicLongMemorySequences.DuplicationMutationType
DuplicationMutation(alpha, alphabet [, marginal]; mutation_probability = 0.01,
                    seed_length = 64, max_block_length = 4096)

Model-based symbolic growth generator (MB5) using copy-and-mutate block duplication.

Generation starts with seed_length iid symbols from marginal. The sequence then grows one symbol at a time by choosing a power-law copy distance, copying the symbol at that lag, and mutating the copied symbol independently with probability mutation_probability. Copy distances are drawn from a truncated power law P(D = ell) ∝ ell^(-alpha) over the available history, capped by max_block_length.

This is a finite-sequence symbolic analogue of expansion-modification and duplication-mutation ideas. It is naturally DNA-like, but it does not provide direct bigram control or an exact Hurst-parameter guarantee. The power-law copy distance is the part that gives a pathway to broad lag dependence. Earlier block-copy variants with uniformly chosen source blocks mostly created local duplication patches rather than a power-law autocorrelation curve.

Arguments

  • alpha::Real: copy-distance exponent, alpha > 1; use values near 1 for slower empirical decay and broader dependence.
  • alphabet: ordered collection of symbols.
  • marginal::AbstractVector{<:Real}: mutation replacement and seed marginal probabilities (default: uniform).

Keyword Arguments

  • mutation_probability::Real = 0.01: per-symbol mutation probability.
  • seed_length::Int = 64: iid prefix length before copy-mutate growth.
  • max_block_length::Int = 4096: legacy keyword naming the maximum copy distance/backward memory window.

Complexity

O(n log d + d) time and O(n + d) memory, where d = max_block_length.

References

Li, W. (1991). Expansion-modification systems: a model for spatial 1/f spectra. Physical Review A 43, 5240-5260.

Li, W., Marr, T. G., & Kaneko, K. (1994). Understanding long-range correlations in DNA sequences. Physica D 75, 392-416.

Examples

julia> g = DuplicationMutation(1.5, ['A', 'C', 'G', 'T']; mutation_probability = 0.02)
DuplicationMutation{Vector{Char}, Vector{Float64}}(α=1.5, k=4, μ=0.02, seed=64, max_block=4096)

julia> length(generate(g, 500; rng = MersenneTwister(1))) == 500
true
source

Utilities

SymbolicLongMemorySequences.target_marginalFunction
target_marginal(g) -> Vector{Float64}

Return the marginal probabilities a generator claims to target.

Examples

julia> target_marginal(SpectralFGN(0.8, [:a, :b], [0.25, 0.75]))
2-element Vector{Float64}:
 0.25
 0.75
source
SymbolicLongMemorySequences.empirical_marginalFunction
empirical_marginal(seq, alphabet) -> Vector{Float64}

Estimate the marginal distribution of seq over alphabet.

Examples

julia> empirical_marginal([:a, :b, :b, :a], [:a, :b])
2-element Vector{Float64}:
 0.5
 0.5
source
SymbolicLongMemorySequences.empirical_bigramFunction
empirical_bigram(seq, alphabet) -> Matrix{Float64}

Estimate row-normalised bigram transition probabilities over alphabet. Rows with no observations are left as zeros.

Examples

julia> empirical_bigram([:a, :b, :b, :a], [:a, :b])
2×2 Matrix{Float64}:
 0.0  1.0
 0.5  0.5
source
SymbolicLongMemorySequences.empirical_trigramFunction
empirical_trigram(seq, alphabet) -> Array{Float64,3}

Estimate trigram probabilities P(X[t+2] | X[t], X[t+1]) over alphabet. Slices with no observations are left as zeros.

Examples

julia> T = empirical_trigram([:a, :b, :a, :b], [:a, :b]);
julia> T[1, 2, :]
2-element Vector{Float64}:
 1.0
 0.0
source
SymbolicLongMemorySequences.bin_countsFunction
bin_counts(marginal, n) -> Vector{Int}

Return integer bin counts for n observations with proportions as close as possible to marginal.

The counts are obtained by flooring n .* marginal and distributing the remaining observations to the largest fractional remainders. Ties are broken by alphabet order, which makes the result deterministic.

Examples

julia> bin_counts([0.2, 0.3, 0.5], 10)
3-element Vector{Int64}:
 2
 3
 5
source
SymbolicLongMemorySequences.rowwise_total_variationFunction
rowwise_total_variation(observed, target) -> Vector{Float64}

Return total variation distance for each row of two transition matrices.

Examples

julia> rowwise_total_variation([0.5 0.5; 0.0 1.0], [1.0 0.0; 0.0 1.0])
2-element Vector{Float64}:
 0.5
 0.0
source
SymbolicLongMemorySequences.validate_transition_matrixFunction
validate_transition_matrix(P, name = "transition_matrix") -> Matrix{Float64}

Convert P to a dense Matrix{Float64} and check that it is square, finite, non-negative, non-empty, and row-stochastic.

Examples

julia> validate_transition_matrix([0.8 0.2; 0.1 0.9])
2×2 Matrix{Float64}:
 0.8  0.2
 0.1  0.9
source
SymbolicLongMemorySequences.stationary_distributionFunction
stationary_distribution(P; maxiter = 10_000, tol = 1e-12) -> Vector{Float64}

Return a stationary distribution for a row-stochastic transition matrix using power iteration.

Examples

julia> round.(stationary_distribution([0.8 0.2; 0.1 0.9]); digits = 3)
2-element Vector{Float64}:
 0.333
 0.667
source
SymbolicLongMemorySequences.lamp_repeat_transitionFunction
lamp_repeat_transition(marginal; repeat_probability = 0.8) -> Matrix{Float64}

Construct a row-stochastic identity/dyad transition matrix for LAMP.

The matrix is

P[i, j] = repeat_probability * 𝟏[i = j] +
          (1 - repeat_probability) * marginal[j]

so larger repeat_probability makes the process more likely to repeat the state selected from history, while the dyad term pulls rows back toward the target marginal.

Examples

julia> P = lamp_repeat_transition([0.25, 0.75]; repeat_probability = 0.8)
2×2 Matrix{Float64}:
 0.85  0.15
 0.05  0.95
source
SymbolicLongMemorySequences.quantize_to_symbolsFunction
quantize_to_symbols(x, alphabet, marginal) -> Vector

Map a real-valued sequence x to symbols from alphabet using rank binning.

The sorted values of x are partitioned into integer bin counts from bin_counts, then mapped back to the original order. This avoids threshold edge cases and makes each finite-sample marginal as close as possible to the requested marginal.

Arguments

  • x::AbstractVector{<:Real}: real-valued input sequence.
  • alphabet: ordered collection of k unique symbols.
  • marginal::AbstractVector{<:Real}: target symbol probabilities.

Examples

julia> x = randn(1000)
julia> s = quantize_to_symbols(x, [:L, :M, :H], [0.25, 0.5, 0.25])
julia> count(==(:M), s) / 1000 ≈ 0.5
true
source
SymbolicLongMemorySequences._fgn_spectralFunction
_fgn_spectral(n, H, rng) -> Vector{Float64}

Generate length-n fractional Gaussian noise with Hurst parameter H using Paxson's (1997) approximate spectral method.

Builds the target power spectrum S(f) ∝ |f|^(1−2H) on the DFT grid, fills with scaled complex Gaussian noise with Hermitian symmetry, then inverse-FFTs. Output is normalised to zero mean and unit standard deviation. Requires n ≥ 4.

Examples

julia> x = SymbolicLongMemorySequences._fgn_spectral(8, 0.75, MersenneTwister(1));
julia> length(x), round(mean(x); digits = 12)
(8, 0.0)
source
SymbolicLongMemorySequences._pareto_sampleFunction
_pareto_sample(rng, alpha, x_min) -> Float64

Draw from a Pareto distribution with shape alpha and scale x_min using Distributions.jl.

Examples

julia> SymbolicLongMemorySequences._pareto_sample(MersenneTwister(1), 1.4, 1.0) >= 1.0
true
source