Conversation
|
is there any paper in the literature that has generalized the transfer operator like this? Among other outcome spaces? if not, perhaps you can consider making this a paper. |
At least I am not aware of any such paper. Would be a cool contribution for sure! |
|
@rusandris Thanks for the PR! I am super busy at the moment, so I'm not able to review this in detail yet. I'll try to get to it within the next couple of weeks.
I'll have to do a thorough review dig deeper to understand this issue. I'll ping you when I've tested this out a bit, @rusandris. |
Just to be clear: i have no capacity to be involved in such a paper, but it is worth discussing with your supervisor Andras. |
I looked inside julia> probabilities(TransferOperator(),op,x;N=5,tolerance=1e-12)
distribution = [0.28892942757860407 0.7110705724213959]
distribution = [0.7110705724213959 0.28892942757860407]
distance = 0.7778172853930047
distribution = [0.28892942757860407 0.7110705724213959]
distance = 0.7778172853930047
distribution = [0.7110705724213959 0.28892942757860407]
distance = 0.7778172853930047
distribution = [0.28892942757860407 0.7110705724213959]
distance = 0.7778172853930047
distribution = [0.7110705724213959 0.28892942757860407]
distance = 0.7778172853930047
Probabilities{Float64,1} over 2 outcomes
Outcome(1) 0.7110705724213959
Outcome(2) 0.28892942757860407reveals of course that it works as it should. Since the transition matrix looks like this to.transfermatrix
2×2 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
⋅ 1.0
1.0 ⋅ the iterative method keeps flipping the initial random values inside the distribution. This wouldn't converge, unless the initial distribution is already given as probabilities(RelativeAmount(),op,x)
Probabilities{Float64,1} over 2 outcomes
Outcome(1) 0.5
Outcome(2) 0.5 |
|
I've seeen some new commits here, but it's been more than a year since i've looked at this and have forgotten many things, let me know if there is something in particular you'd like help with, or to discuss, and I'll bring myself back up to speed! |
|
Thanks, great to hear! I'm still working on it, but in short logistic_rule(x, p, n) = SVector{1}(p[1] * x[1] * (1.0 - x[1]))
p = [r]
ds = DeterministicIteratedMap(logistic_rule, [0.4], p)
x, t = trajectory(ds, 10^3; Ttr=10^4)
b = ValueBinning(FixedRectangularBinning(range(0,1;length=11)))
probabilities(TransferOperator(),b,x)through The eigenvector method can be better for example when the time series is periodic: ds = DeterministicIteratedMap(logistic_rule, [0.4], [3.84])
x, t = trajectory(ds, 10^3; Ttr=10^4)
probabilities(TransferOperator(),b,x;method=:iterate)
Probabilities{Float64,1} over 3 outcomes
2 0.09340928604503983
5 0.23372777459244914
10 0.6728629393625111
probabilities(TransferOperator(),b,x;method=:eigen)
Probabilities{Float64,1} over 3 outcomes
2 0.33333333333333337
5 0.3333333333333334
10 0.33333333333333326Let me know how this looks for you. |
|
@rusandris, great stuff! 🤘Super nice that the eigenvector approach works well for periodic time series. This is a major improvement which may have advantages in e.g. reducing false negatives in settings where e.g. extensive pseudoperiodic surrogate testing is done for some statistic. For that reason I vote for keeping the dependency. One comment though: following the convention from the test of the packaged: any keywords that controls the probabilities estimation should be part of the discretization type ('TransferOperator'), not as a keyword to the 'probabilities' function. |
My thinking was the following (and I'm sure there are some workarounds/better ways to do this): the seemed too verbose and difficult. These types are supposed to be internal and are only used once which is what you mean, right? |
|
@rusandris Thanks again for your great work! I'll do a thorough review of this in the coming days. In order to not give conflicting feedback here, I want to familiarize myself properly with the changes before I respond in detail. But in short: Breaking changesI see that there is a breaking change (converting Internal dispatch
Something like that! For consistency with the rest of the code base, I think the following would work: probabilities(probest::TransferOperatorApproximation(::ApproximationMethod), o::OutcomeSpace, x)where probabilities(::TransferOperatorApproximationIterative,outcome_space,x)
probabilities(::TransferOperatorApproximationEigen,outcome_space,x)I just need to see how it relates to the manual extraction of the transfer matrix in your suggested code. Why we don't want extra keywords in the functionWe want the base functions like If we were to break with this convention for the transfer operator, then there would be hundreds of possible ways to discretize and estimate probabilities from data using one unified syntax, EXCEPT for the transfer operator approximation, which has an extra keyword for We set reasonable, well-documented default behaviours, but leave the user the option to be as granular as they want. |
|
Thanks for the suggestions! Now it's starting to shape up nicely, I would say. x = rand(10000)
op = OrdinalPatterns{3}()
probabilities(TransferOperatorEstimator(),op,x)where an probabilities(TransferOperatorEstimator(ApproximationIterative()),op,x)
Probabilities{Float64,1} over 6 outcomes
3 0.16324623547971576
2 0.1591237693781441
6 0.16384218566116265
5 0.17197826172205205
4 0.16785579628202602
1 0.17395375147689937
probabilities(TransferOperatorEstimator(ApproximationEigen()),op,x)
Probabilities{Float64,1} over 6 outcomes
3 0.16324623516644013
2 0.15912376937533454
6 0.16384218587939298
5 0.17197826206173342
4 0.1678557962706277
1 0.17395375124647128
Still work in progress though, it needs to be moved to |
|
Now the tests pass, finally. |
|
All right so here is a quick summary of the changes: Basic usage goes like: x = rand(10000)
op = OrdinalPatterns{3}()
probabilities(TransferOperator(),op,x)where TransferOperator, with 2 fields:
approximation_method = ApproximationIterative(200, 1.0e-8, 1.0e-8, Random.TaskLocalRNG())
boundary_condition = none
The approximation method can be of two types ( probabilities(TransferOperator(ApproximationIterative()),op,x)
Probabilities{Float64,1} over 6 outcomes
3 0.16324623547971576
2 0.1591237693781441
6 0.16384218566116265
5 0.17197826172205205
4 0.16785579628202602
1 0.17395375147689937
probabilities(TransferOperator(ApproximationEigen()),op,x)
Probabilities{Float64,1} over 6 outcomes
3 0.16324623516644013
2 0.15912376937533454
6 0.16384218587939298
5 0.17197826206173342
4 0.1678557962706277
1 0.17395375124647128
Under the hood, the method transferoperator(o::OutcomeSpace,x; boundary_condition = :none,
approximation_method=ApproximationIterative())creates a TransferOperatorApproximation{OC<:OutcomeSpace,AM<:ApproximationMethod}from the time series approximation_method
outcome_space
outcomes
transfermatrixThis is passed onto I'm sure I missed some things, but that's the essence of it. A more general Transition probabilites can be useful in Markov chain based estimator methods as well (see here for example ). I probably left some type annotations out from some constructors here and there but those can be corrected later. We also need to check if this breaks something in other packages (I'm thinking of Associations.jl). |
|
hi @rusandris , this looks fantastic. Thank you for putting in the work to finish this. We are very close to the finish line, but as you pointed out already, documentation is crucial before attempting to do the final review and merge. Please tag me here once you have added documentation (this includes both docstrings and a new usage example in the examples as this is a substantial new feature). |
|
Oh, also: do we need to do anything for backwards compatibility in this PR? This way we won't have to worry about breaking stuff. You can likely still extend the old methods that only use binning in the |
So far the old methods x = rand(1000)
b = RectangularBinning(4)
est = TransferOperator(b)
transferoperator(x, b)are added in |
|
probably worth adding in the deprecations a method that where |
|
@Datseris I have finally managed to put together a working version of the code and the docs. I disabled link checking in the docs for now (some of the references are not found apparently), so it can build. |
First draft PR. I tried to follow the design ideas mentioned here #424 .
TransferOperatorbecomes aProbabilitiesEstimator.First results:
which returns a
TransferOperatorApproximation <: ProbabilitiesEstimator.OP example:
Most important field is the
transfermatrixprobabilitiesfunction does work formally in that it gives an output:but for some reason, for this particular example, the iterative method used in
invariant_measuredoes not converge.the correct probabs of course would be
[0.5,0.5]as the eigenvector corresponding to eigenvalue 1 is[1,1]. This might be a separate issue though.Let me know what you think.