Skip to content

Commit fa14e1f

Browse files
authored
Allow initial conditions to depend on parameters during a global continuation (#183)
* allow parameter-dependent continuation * versions * add test for the new feature
1 parent a43ae24 commit fa14e1f

File tree

6 files changed

+98
-17
lines changed

6 files changed

+98
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v1.27
2+
3+
- It is now possible to specify initial conditions that depend on the parameters during a global continuation. See `PerParameterInitialConditions`.
4+
15
# v1.26
26

37
- **Brand new, ground-breaking functionality** for finding (almost) all stability

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name = "Attractors"
22
uuid = "f3fd9213-ca85-4dba-9dfd-7fc91308fec7"
33
authors = ["George Datseris <[email protected]>", "Kalel Rossi", "Alexandre Wagemakers"]
44
repo = "https://github.com/JuliaDynamics/Attractors.jl.git"
5-
version = "1.26.4"
5+
version = "1.27.0"
66

77

88
[deps]

src/continuation/continuation_ascm_generic.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ function global_continuation(acam::AttractorSeedContinueMatch, pcurve, ics;
128128
# first parameter is run in isolation, as it has no prior to seed from
129129
set_parameters!(referenced_dynamical_system(mapper), pcurve[1])
130130
if ics isa Function
131-
fs = basins_fractions(mapper, ics; show_progress = false, N = samples_per_parameter)
131+
fs = basins_fractions(mapper, ics; show_progress = false, N)
132+
elseif ics isa PerParameterInitialConditions
133+
u0s = ics.generator(pcurve[1], N)
134+
fs, = basins_fractions(mapper, u0s; show_progress = false)
132135
else # we ignore labels in this continuation algorithm
133136
fs, = basins_fractions(mapper, ics; show_progress = false)
134137
end
@@ -152,7 +155,7 @@ function global_continuation(acam::AttractorSeedContinueMatch, pcurve, ics;
152155
fs = if allows_mapper_u0(mapper)
153156
seed_attractors_to_fractions_individual(mapper, prev_attractors, ics, N, acam.seeding)
154157
else
155-
seed_attractors_to_fractions_grouped(mapper, prev_attractors, ics, N, acam.seeding)
158+
seed_attractors_to_fractions_grouped(mapper, prev_attractors, ics, N, acam.seeding, p)
156159
end
157160
current_attractors = deepcopy(extract_attractors(mapper))
158161
# we don't match attractors here, this happens directly at the end.
@@ -196,7 +199,7 @@ function seed_attractors_to_fractions_individual(mapper, prev_attractors, ics, N
196199
return fs
197200
end
198201

199-
function seed_attractors_to_fractions_grouped(mapper, prev_attractors, ics, N, seeding)
202+
function seed_attractors_to_fractions_grouped(mapper, prev_attractors, ics, N, seeding, parameters)
200203
# what makes this version different is that we can't just use `mapper(u0)`,
201204
# so we need to store the seeded initial conditions and then combine them with
202205
# the the ones generated from `ics`.
@@ -212,6 +215,8 @@ function seed_attractors_to_fractions_grouped(mapper, prev_attractors, ics, N, s
212215
for _ in 1:N
213216
push!(u0s, copy(ics()))
214217
end
218+
elseif ics isa PerParameterInitialConditions
219+
append!(u0s, ics.generator(parameters, N))
215220
else
216221
append!(u0s, vec(ics))
217222
end

src/continuation/continuation_grouping.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,12 @@ function _get_features_pcurve(mapper::AttractorsViaFeaturizing, ics, n, spp, pcu
8787
# Collect features
8888
for (i, p) in enumerate(pcurve)
8989
set_parameters!(mapper.ds, p)
90-
current_features = extract_features(mapper, ics; show_progress, N = spp)
90+
if ics isa PerParameterInitialConditions
91+
u0s = ics.generator(p, spp)
92+
else
93+
u0s = ics
94+
end
95+
current_features = extract_features(mapper, u0s; show_progress, N = spp)
9196
features[((i - 1)*spp + 1):i*spp] .= current_features
9297
ProgressMeter.next!(progress)
9398
end

src/continuation/global_continuation_api.jl

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export global_continuation, GlobalContinuationAlgorithm, continuation_series, stability_measures_along_continuation
2+
export PerParameterInitialConditions
23

34
"""
45
GlobalContinuationAlgorithm
@@ -17,9 +18,22 @@ abstract type GlobalContinuationAlgorithm end
1718
global_continuation(gca::GlobalContinuationAlgorithm, pcurve, ics; kwargs...)
1819
1920
Find and continue attractors (or representations of attractors)
20-
and the fractions of their basins of attraction across a parameter range `pcurve`
21+
and the fractions of their basins of attraction across a parameter curve `pcurve`
2122
by sampling given initial conditions `ics` according to algorithm `gca`.
2223
24+
Possible subtypes of a `GlobalContinuationAlgorithm` are:
25+
26+
- [`AttractorSeedContinueMatch`](@ref)
27+
- [`FeaturizeGroupAcrossParameter`](@ref)
28+
29+
`ics` are the initial conditions to use when sampling the state space.
30+
They can be specified in one of three ways:
31+
32+
1. A set vector of initial conditions (vector of vectors).
33+
2. A 0-argument function that generates random initial conditions.
34+
3. The special type [`PerParameterInitialConditions`](@ref) that allows
35+
different initial conditions for different parameter values.
36+
2337
Return:
2438
2539
1. `fractions_cont::Vector{Dict{Int, Float64}}`. The fractions of basins of attraction.
@@ -57,27 +71,31 @@ across the parameter range `prange`, for the parameter of the system with index
5771
traditional continuation (see online Tutorial for a comparison), global continuation
5872
can be performed over arbitrary user-defined curves in parameter space.
5973
The second call signature with `pcurve` allows for this possibility. In this case
60-
`pcurve` is a vector of iterables, where each itereable maps parameter indices
74+
`pcurve` is a vector of iterables, where each iterable maps parameter indices
6175
to parameter values. These iterables can be dictionaries, named tuples, `Vector{Pair}`,
62-
etc., and the sequence of the iterables defines a curve in parameter space.
76+
anything that can be given in `set_parameters!`.
77+
The sequence of the iterables defines a curve in parameter space.
6378
In fact, the version with `prange, pidx` simply defines
6479
`pcurve = [[pidx => p] for p in prange]` and calls the second method.
65-
66-
`ics` are the initial conditions to use when globally sampling the state space.
67-
Like in [`basins_fractions`](@ref) it can be either a set vector of initial conditions,
68-
or a 0-argument function that generates random initial conditions.
69-
70-
Possible subtypes of `GlobalContinuationAlgorithm` are:
71-
72-
- [`AttractorSeedContinueMatch`](@ref)
73-
- [`FeaturizeGroupAcrossParameter`](@ref)
7480
"""
7581
function global_continuation(alg::GlobalContinuationAlgorithm, prange::AbstractVector, pidx, sampler; kw...)
7682
# everything is propagated to the curve setting
7783
pcurve = [[pidx => p] for p in prange]
7884
return global_continuation(alg, pcurve, sampler; kw...)
7985
end
8086

87+
"""
88+
PerParameterInitialConditions(generator)
89+
90+
Wrapper around a function `generator`, to be called as
91+
`generator(parameter_pairs, N::Int)`.
92+
It inputs the current parameter(s) of a [`global_continuation`](@ref)
93+
(elements of `pcurve`), and generates a vector of `N` initial conditions.
94+
"""
95+
struct PerParameterInitialConditions{F}
96+
generator::F
97+
end
98+
8199

82100
"""
83101
continuation_series(continuation_info, fillval = NaN)

test/continuation/seed_continue_generic.jl

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,53 @@ using Random
8585
end
8686
end
8787

88+
end
89+
90+
@testset "parameter dependent ic" begin
91+
# fake map with two equlibria at (-r, r) and (r, r)
92+
function dumb_map2(dz, z, p, n)
93+
x, y = z
94+
r = p[1]
95+
96+
if y < r - 1
97+
dz[1] = dz[2] = 0.0
98+
else
99+
if x < 0.0
100+
dz[1] = -1.0
101+
dz[2] = r
102+
else
103+
dz[1] = 1.0
104+
dz[2] = r
105+
end
106+
end
107+
return nothing
108+
end
109+
110+
rs = [0, 2.0, 4.0]
111+
ds = DeterministicIteratedMap(dumb_map2, [0., 0.], [1.0])
112+
N = 5
113+
114+
function make_ics(parameters, n)
115+
I = parameters[1].second
116+
@show I
117+
N = round(Int, sqrt(n))
118+
grid = (range(-1.0, 1.0; length = N), range(-0.5, 0.5; length = N))
119+
ics = [SVector(v, w + I) for w in grid[2] for v in grid[1]]
120+
return ics
121+
end
122+
icsgen = PerParameterInitialConditions(make_ics)
123+
124+
featurizer(A, t) = A[end]
125+
gconfig = GroupViaPairwiseComparison(threshold = 0.25, rescale_features = false)
126+
mapper = AttractorsViaFeaturizing(ds, featurizer, gconfig; Ttr = 1, T = 1)
127+
gca = AttractorSeedContinueMatch(mapper; seeding = A -> [])
128+
129+
pcurve = [[1 => r] for r in rs]
130+
fractions_cont, attractors_cont = global_continuation(gca, pcurve, icsgen; samples_per_parameter = 25)
131+
132+
# all times 2 attractors, never the 0.0 attractor
133+
@test all(A -> length(A) == 2, attractors_cont)
134+
for attractors in attractors_cont
135+
@test all(A -> A[end][1] != 0, values(attractors))
136+
end
88137
end

0 commit comments

Comments
 (0)