Closed kahaaga closed 3 years ago
@Datseris This is ready to go. The syntax will remain roughly the same once I've finished up Entropies.jl.
However, I'd like your input on the syntax before I merge. I ended up doing this (similar to what we discussed in an earlier issue).
# General syntax
transferentropy(src, targ, [, cond], emb::EmbeddingTE, est::TransferEntropyEstimator)
# Implemented estimators
transferentropy(src, targ, [, cond], emb::EmbeddingTE, est::VisitationFrequency)
transferentropy(src, targ, [, cond], emb::EmbeddingTE, est::NearestNeighborMI)
transferentropy(src, targ, [, cond], emb::EmbeddingTE, est::SymbolicPerm)
transferentropy(src, targ, [, cond], emb::EmbeddingTE, est::TransferOperatorGrid)
transferentropy(src, targ, [, cond], emb::EmbeddingTE, est::SimplexEstimator)
(the last argument will just be an EntropyEstimator
once Entropies.jl is out.
Here, the EmbeddingTE
instance will contain embedding parameters, and EmbeddingTE()
will give as default the lowest-dimensional embedding.
There will be some other entropy-based causality measures included in CausalityTools that also rely on generalized delay embeddings. Those other functions will the same syntax, except their embeddings are provided using different structs. For example, the predictive asymmetry method will have the syntax:
predictive_asymmetry(src, targ, [, cond], emb::EmbeddingTE, est::VisitationFrequency)
predictive_asymmetry(src, targ, [, cond], emb::EmbeddingTE, est::NearestNeighborMI)
predictive_asymmetry(src, targ, [, cond], emb::EmbeddingTE, est::SymbolicPerm)
# etc...
Exactly how the embeddings for these methods are constructed, how many components they have, and which symbols they have will differ, so I've opted for this struct-based approach to keep the syntax clean.
What do you think?
Yeah, I think this API is fine.
What is EmbeddingTE
? You don't want to re-use GeneralizedEmbedding
from DelayEmbeddings.jl?
the last argument will just be an EntropyEstimator once Entropies.jl is out.
I think it makes sense to have a working draft of Entropies.jl before attempting a v1 release here.
What is
EmbeddingTE
? You don't want to re-useGeneralizedEmbedding
from DelayEmbeddings.jl?
The EmbeddingTE
provides the instructions for how the generalized embedding should be constructed (lags and dimensions for each of the TE marginals - future of target variable, present/past of target variable, and present/past of source variable):
@Base.kwdef struct EmbeddingTE
dS::Union{Int, AbstractVector{Int}, OptimiseDim} = 1
dT::Union{Int, AbstractVector{Int}, OptimiseDim} = 1
d𝒯::Union{Int, AbstractVector{Int}, OptimiseDim} = 1
dC::Union{Int, AbstractVector{Int}, OptimiseDim, Nothing} = 1
τS::Union{Int, AbstractVector{Int}, OptimiseDelay} = -1
τT::Union{Int, AbstractVector{Int}, OptimiseDelay} = -1
τC::Union{Int, AbstractVector{Int}, OptimiseDelay, Nothing} = -1
η𝒯::Union{Int, AbstractVector{Int}, OptimiseDelay} = 1
end
From these instructions, a GeneralizedEmbedding
is constructed, which is then used to compute transfer entropy.
GeneralizedEmbedding
in itself has conceptual connection to the marginals of a state space reconstruction for transfer entropy. This would require the users themselves to construct the embedding manually, which goes way beyond the "easy to use" principle. The EmbeddingTE
struct takes care of the mapping of coordinate axes of the reconstruction to the relevant marginals during entropy computation.
The mapping of state space coordinate axes to marginals might be different for other transfer entropy-related methods. These might share some, but not all marginals, with TE. That is why I here constructed a transfer entropy-specific embedding struct.
Alternatively, one could use the following api:
transferentropy(src, targ, [cond], est::TransferEntropyEstimator; τT = -1, τS = -1, τC = -1, η𝒯 = 1, dT = 1, dS = 1, dC = 1, d𝒯 = 1)
where the lags/dimensions are given explicitly. This serves the same purpose as EmbeddingTE
, but takes away the immediate conceptual part of transfer entropy being computed over the marginals of an embedding, using some entropy estimator. However, I am happy with using either approach.
I think it makes sense to have a working draft of Entropies.jl before attempting a v1 release here.
That makes sense.
Sure, sounds good to me. Both APIs are fine but the first should be the one used internally throughout, while the second is only a "convenience" wrapper.
Version 1.0 stuff in the /src/v1 folder. Keeping the old files for reference until everything's ready.