Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
95f8b94
Generalized `self_information` function
kahaaga Jun 9, 2024
58b80e6
Some generalied self-informations
kahaaga Jun 9, 2024
f5d5b87
Self-information for Shannon extropy
kahaaga Jun 9, 2024
805b60f
Update `FluctuationComplexity` docstring
kahaaga Jun 9, 2024
785cb6c
Merge branch 'main' into fluctuation_complexity_formal
kahaaga Jun 10, 2024
0d8abd7
use self_info
kahaaga Jun 16, 2024
bb2712f
Add Anteneodo-Plastino self-info and update syntax
kahaaga Jun 17, 2024
1d4f326
Docs
kahaaga Jun 17, 2024
e3c4d39
Merge branch 'main' into fluctuation_complexity_formal
kahaaga Jun 17, 2024
780176b
Update src/information_measure_definitions/fluctuation_complexity.jl
kahaaga Jun 18, 2024
ba6b73b
wip...
kahaaga Jun 23, 2024
bb1aa37
Merge branch 'fluctuation_complexity_formal' into sequential_categori…
kahaaga Jun 23, 2024
0e7a2d1
wip..
kahaaga Jun 23, 2024
0132c05
Merge branch 'sequential_categorical_encoding' into fluctuation_compl…
kahaaga Jun 23, 2024
6c26097
Merge branch 'main' into fluctuation_complexity_formal
kahaaga Jun 24, 2024
30a82f7
Update docs
kahaaga Jun 24, 2024
ddea888
self_information for identification entropy
kahaaga Jun 25, 2024
d00ffdf
Merge branch 'main' into fluctuation_complexity_formal
kahaaga Aug 11, 2026
3f58888
fix formula
kahaaga Aug 11, 2026
dd9628b
fix formula
kahaaga Aug 11, 2026
84ad0d5
make tests consistent with paper
kahaaga Aug 11, 2026
ebd3820
fix fallbacks to shannon and log func calls
kahaaga Aug 11, 2026
045bceb
include constant k
kahaaga Aug 11, 2026
38478fe
Apply base consistently to measures and enhance self_information
kahaaga Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions src/core/information_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,17 @@ function information(::InformationMeasure, ::DifferentialInfoEstimator, args...)
end

"""
self_information(measure::InformationMeasure, pᵢ)
self_information(measure::InformationMeasure, p, N::Int)

Compute the "self-information"/"surprisal" of a single probability `pᵢ` under the given
information measure.
Compute the "self-information"/"surprisal" of a single probability `p` under the given
information measure, assuming that `p` is part of a length-`N` probability distribution.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I don't agree with the latest change of requiring N. It seems simpler, and more reasonable, to simply not allow Curado to be part of this interface. The opposite, defining the information unit as depending on N, doesn't make much sense at least not with how Shannon introduced it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Datseris Curado is not the only information measure whose surprisal/self-information depends explicitly on N, when following the definition of an information measure as a probability weighted average of the surprisal (as I do in the paper).

The opposite, defining the information unit as depending on N, doesn't make much sense at least not with how Shannon introduced it.

In the context of Shannon information unit alone, I agree. But the point of this interface is to generalize the Shannon information unit. This inevitably introduces N as a parameter.

Can we discuss the final API when I'm done with writing up the paper? I'm not too far from finishing it; I just need to generate a few example applications. Since I am using this PR for the paper analyses, it would be nice to not change anything in this draft PR until the paper is ready.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative is to have information_content/information_unit which dispatches to a subset of InformationMeasures, and then generalized_information_content/generalized_information_unit which dispatches to those InformationMeasures whose generalization of information unit depends on N. But that kind of defeats the purpose of having an interface to begin with - since we're back at defining multiple functions with different names for things that are fundamentally identical (modulo the parameter N).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS: I sent you a link to the paper draft, @Datseris


This function assumes `pᵢ > 0`, so make sure to pre-filter your probabilities.
For some `measure`s, the information content is independent of `N`, while for others
it depends on `N`. For consistency, we require that you always provide `N` (`N` will be
ignored if not relevant).

This function requires `p > 0`; giving `0` can yield `Inf` or `NaN` for certain
`measure`s.

## Definition

Expand All @@ -302,12 +307,12 @@ sum of the self-information equals the information measure.

!!! note "Motivation for this definition"
This definition is motivated by the desire to compute generalized
[`FluctuationComplexity`](@ref), which is a measure of fluctuations of local self-information
[`InformationFluctuation`](@ref), which is a measure of fluctuations of local self-information
relative to some information-theoretic summary statistic of a distribution. Defining
these self-information functions has, as far as we know, not been treated in the literature
before, and will be part of an upcoming paper we're writing!
"""
function self_information(measure::InformationMeasure, pᵢ)
function self_information(measure::InformationMeasure, pᵢ, N = nothing)
throw(ArgumentError(
"""`InformationMeasure` $(typeof(measure)) does not implement `self_information`."""
))
Expand Down
2 changes: 1 addition & 1 deletion src/core/information_measures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ for usage examples.
- [`RenyiExtropy`](@ref).
- [`TsallisExtropy`](@ref).
- [`ShannonExtropy`](@ref), which is a subcase of the above two in the limit `q → 1`.
- [`FluctuationComplexity`](@ref).
- [`InformationFluctuation`](@ref).

## Estimators

Expand Down
5 changes: 5 additions & 0 deletions src/information_measure_definitions/curado.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ function information_maximum(e::Curado, L::Int)
# Maximized for the uniform distribution, which for distribution of length L is
return L * (1 - exp(-b/L)) + exp(-b) - 1
end

function self_information(e::Curado, p, N::Int)
b = e.b
return exp(-b*p)/p + (exp(-b) - 1)/N
end
60 changes: 41 additions & 19 deletions src/information_measure_definitions/fluctuation_complexity.jl
Original file line number Diff line number Diff line change
@@ -1,62 +1,84 @@
export FluctuationComplexity
export InformationFluctuation

"""
FluctuationComplexity <: InformationMeasure
FluctuationComplexity(; definition = Shannon())
InformationFluctuation <: InformationMeasure
InformationFluctuation(; definition = Shannon())

The "fluctuation complexity" quantifies the standard deviation of the information content of the states
The information fluctuation quantifies the standard deviation of the information content of the states
``\\omega_i`` around some summary statistic ([`InformationMeasure`](@ref)) of a PMF. Specifically, given some
outcome space ``\\Omega`` with outcomes ``\\omega_i \\in \\Omega``
and a probability mass function ``p(\\Omega) = \\{ p(\\omega_i) \\}_{i=1}^N``, it is defined as

```math
\\sigma_I_Q(p) := \\sqrt{\\sum_{i=1}^N p_i(I_Q(p_i) - H_*)^2}
\\sigma_I_Q(p) := \\sqrt{\\sum_{i=1}^N p_i(I_Q(p_i) - F_Q)^2}
```

where ``I_Q(p_i)`` is the [`self_information`](@ref) of the i-th outcome with respect to the information
measure of type ``Q`` (controlled by `definition`).
where ``I_Q(p_i)`` is the [`information_content`](@ref) of the i-th outcome with respect to the information
measure ``F_Q`` (controlled by `definition`).

## Compatible with

- [`Shannon`](@ref)
- [`Tsallis`](@ref)
- [`Curado`](@ref)
- [`StretchedExponential`](@ref)
- [`ShannonExtropy`](@ref)

If `definition` is the [`Shannon`](@ref) entropy, then we recover the
[Shannon-type "information fluctuation complexity"](https://en.wikipedia.org/wiki/Information_fluctuation_complexity)
from [Bates1993](@cite).

## Properties

If `definition` is the [`Shannon`](@ref) entropy, then we recover the
[Shannon-type information fluctuation complexity](https://en.wikipedia.org/wiki/Information_fluctuation_complexity)
from [Bates1993](@cite). Then the fluctuation complexity is zero for PMFs with only a single non-zero element, or
Then the information fluctuation is zero for PMFs with only a single non-zero element, or
for the uniform distribution.

If `definition` is not Shannon entropy, then the properties of the measure varies, and does not necessarily share the
properties [Bates1993](@cite).
## Examples

```julia
using ComplexityMeasures
using Random; rng = Xoshiro(55543)

# Information fluctuation for a time series encoded by ordinal patterns
x = rand(rng, 10000)
def = Tsallis(q = 2) # information measure definition
pest = RelativeAmount() # probabilities estimator
o = OrdinalPatterns(m = 3) # outcome space / discretization method
information(InformationFluctuation(definition = def), pest, o, x)
```

!!! note "Potential for new research"
As far as we know, using other information measures besides Shannon entropy for the
fluctuation complexity hasn't been explored in the literature yet. Our implementation, however, allows for it.
We're currently writing a paper outlining the generalizations to other measures. For now, we verify
correctness of the measure through numerical examples in our test-suite.
"""
struct FluctuationComplexity{M <: InformationMeasure, I <: Integer} <: InformationMeasure
struct InformationFluctuation{M <: InformationMeasure, I <: Integer} <: InformationMeasure
definition::M
base::I

function FluctuationComplexity(; definition::D = Shannon(base = 2), base::I = 2) where {D, I}
if D isa FluctuationComplexity
throw(ArgumentError("Cannot use `FluctuationComplexity` as the summary statistic for `FluctuationComplexity`. Please select some other information measures, like `Shannon`."))
function InformationFluctuation(; definition::D = Shannon(base = 2), base::I = 2) where {D, I}
if D isa InformationFluctuation
throw(ArgumentError("Cannot use `InformationFluctuation` as the summary statistic for `InformationFluctuation`. Please select some other information measures, like `Shannon`."))
end
return new{D, I}(definition, base)
end
end

# Fluctuation complexity is zero when p_i = 1/N or when p = (1, 0, 0, ...).
function information(e::FluctuationComplexity, probs::Probabilities)
function information(e::InformationFluctuation, probs::Probabilities)
def = e.definition
non0_probs = Iterators.filter(!iszero, vec(probs))
h = information(def, probs)
return sqrt(sum(pᵢ * (self_information(def, pᵢ, length(probs)) - h)^2 for pᵢ in non0_probs))
end

function information_normalized(e::InformationFluctuation, probs::Probabilities)
def = e.definition
non0_probs = Iterators.filter(!iszero, vec(probs))
h = information(def, probs)
s = self_information(def, probs)
return sqrt(sum(pᵢ * (s - h)^2 for pᵢ in non0_probs))
info_fluct = sqrt(sum(pᵢ * (self_information(def, pᵢ, length(probs)) - h)^2 for pᵢ in non0_probs))
return info_fluct / h
end

# The maximum is not generally known.
2 changes: 1 addition & 1 deletion src/information_measure_definitions/kaniadakis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function information_maximum(e::Kaniadakis, L::Int)
throw(ErrorException("information_maximum not implemeted for Kaniadakis entropy yet"))
end

function self_information(e::Kaniadakis, pᵢ)
function self_information(e::Kaniadakis, pᵢ, N = nothing)
κ = e.κ
return (pᵢ^(-κ) - pᵢ^κ) / (2κ)
end
2 changes: 1 addition & 1 deletion src/information_measure_definitions/shannon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function information(e::Shannon, probs::Probabilities)
return -sum(x*logf(x) for x in non0_probs)
end

function self_information(e::Shannon, pᵢ)
function self_information(e::Shannon, pᵢ, N)
return -log(e.base, pᵢ)
end

Expand Down
2 changes: 1 addition & 1 deletion src/information_measure_definitions/shannon_extropy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ function information_maximum(e::ShannonExtropy, L::Int)
return (L - 1) * log(e.base, L / (L - 1))
end

function self_information(e::ShannonExtropy, pᵢ)
function self_information(e::ShannonExtropy, pᵢ, N = nothing)
return -log(e.base, 1 - pᵢ)
end
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function information_maximum(e::StretchedExponential, L::Int)
L * gamma_inc(x, log(e.base, L))[2] * Γx - Γx
end

function self_information(e::StretchedExponential, pᵢ)
function self_information(e::StretchedExponential, pᵢ, N)
η, base = e.η, e.base
Γ₁ = gamma((η + 1) / η, -log(base, pᵢ))
Γ₂ = gamma((η + 1) / η)
Expand Down
2 changes: 1 addition & 1 deletion src/information_measure_definitions/tsallis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ function information_maximum(e::Tsallis, L::Int)
end
end

function self_information(e::Tsallis, pᵢ)
function self_information(e::Tsallis, pᵢ, N = nothing)
return (1 - pᵢ^(e.q- 1)) / (e.q - 1)
end
16 changes: 9 additions & 7 deletions test/infomeasures/infomeasure_types/fluctuation_complexity.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Examples from https://en.wikipedia.org/wiki/Information_fluctuation_complexity
# for the Shannon fluctuation complexity.
p = Probabilities([2//17, 2//17, 1//34, 5//34, 2//17, 2//17, 2//17, 4//17])
def = Shannon(base = 2)
c = FluctuationComplexity(definition = def, base = 2)
@test round(information(c, p), digits = 2) ≈ 0.56
# Zero both for uniform and single-element PMFs.
@test information(c, Probabilities([0.2, 0.2, 0.2, 0.2, 0.2])) == 0.0
@test information(c, Probabilities([1.0, 0.0])) == 0.0
@testset "fluctuation_complexity" begin
probs = Probabilities([2//17, 2//17, 1//34, 5//34, 2//17, 2//17, 2//17, 4//17])
def = Shannon(base = 2)
c = FluctuationComplexity(definition = def, base = 2)
@test round(information(c, probs), digits = 2) ≈ 0.56
# Zero both for uniform and single-element PMFs.
@test information(c, Probabilities([0.2, 0.2, 0.2, 0.2, 0.2])) == 0.0
@test information(c, Probabilities([1.0, 0.0])) == 0.0
end