mappy_ds.root.trace_local_bf_arclength#

mappy_ds.root.trace_local_bf_arclength(diffeo, y0, params, bf_param_key, theta, cnt_param_key, *, period=1, direction=1, bounds=None, step=0.01, step_min=1e-06, step_max=0.1, max_steps=1000, show_progress=False, callback=None)#

Follow a local-bifurcation curve by pseudo-arclength continuation.

The bifurcation conditions of find_local_bf(),

\[T^n(\bm y) - \bm y = 0, \qquad \det\parens{DT^n(\bm y) - e^{i\theta} I} = 0 \;(\text{real and imaginary parts}),\]

are \(d + 2\) equations in the \(d + 3\) unknowns \(u = (\bm y, \lambda_{\mathrm{bf}}, \theta, \lambda_{\mathrm{cnt}})\), so their solutions form a curve: the bifurcation curve in the \((\lambda_{\mathrm{cnt}}, \lambda_{\mathrm{bf}})\) plane together with the periodic point and the argument of the critical multiplier. The curve is followed with arclength_continuation(), so it may turn back in \(\lambda_{\mathrm{cnt}}\) (as a fold curve does at a cusp) without stopping. The Jacobian of the system is fully analytic (jac, hes, jac_p, hes_p).

Events between consecutive points are recorded in info["events"] of the later point:

  • "fold" — the curve turns back in \(\lambda_{\mathrm{cnt}}\) (for a fold curve this happens at a cusp);

  • "resonance_1_1", "resonance_1_2", "resonance_1_3", "resonance_1_4" — on a Neimark–Sacker curve, \(\theta\) passes \(0\), \(\pi\), \(2\pi/3\) or \(\pi/2\) (strong resonances);

  • "second_multiplier_crossing" — the number of multipliers outside the unit circle changes, i.e. another bifurcation curve is crossed (fold–flip, flip–Neimark–Sacker, … points).

Parameters:
diffeoMap

The map.

y0array_like

Periodic point at the starting bifurcation point (e.g. from find_local_bf()); it is corrected first with both parameters held fixed.

paramsmapping

Parameters at the start; params[bf_param_key] is the bifurcation value, params[cnt_param_key] the start of the continuation. Not modified.

bf_param_key, cnt_param_keystr

Keys of the bifurcation parameter (solved along the curve) and of the continuation parameter (the direction/bounds coordinate).

thetafloat

Argument of the critical multiplier at the start (0 fold, pi period doubling, otherwise Neimark–Sacker).

periodint, optional

Period of the cycle, by default 1.

directionint, optional

+1 to start with \(\lambda_{\mathrm{cnt}}\) increasing, -1 decreasing; by default 1.

boundstuple of float, optional

Stop when \(\lambda_{\mathrm{cnt}}\) leaves [lo, hi].

step, step_min, step_maxfloat, optional

Arclength step in the \(u\) space; see arclength_continuation().

max_stepsint, optional

Maximum number of points after the first, by default 1000.

show_progressbool, optional

Print one line per accepted point to standard error.

callbackcallable, optional

Called with each accepted ContinuationStep.

Returns:
list of ContinuationStep

One step per accepted point along the curve. y is the periodic point, params holds both parameters at their values on the curve, and info holds theta, eigvals, eigvecs, tangent (unit vector in the \(u\) space), step, newton_iterations and events.

Raises:
ValueError

If the two keys coincide or the map depends on neither.

See also

trace_local_bf

Natural-parameter continuation of the same curve.

trace_cycle_arclength

The same method for branches of periodic points.

Examples

The cusp normal form x ↦ x + λ₁ + λ₂ x - x³ has the fold curve λ₂ = 3x², λ₁ = -2x³, which turns back in λ₂ at the cusp (0, 0). Starting on the upper branch and decreasing λ₂, the continuation passes the cusp onto the lower branch:

>>> import numpy as np
>>> from mappy_ds import Diffeomorphism, mapping
>>> from mappy_ds.root import trace_local_bf_arclength
>>> @mapping(1)
... def cusp(x, p):
...     return x + p["l1"] + p["l2"] * x - x**3
>>> steps = trace_local_bf_arclength(
...     Diffeomorphism(cusp), [0.5], {"l1": -0.25, "l2": 0.75}, "l1", 0.0,
...     "l2", direction=-1, step=0.1, step_max=0.2, bounds=(-1.0, 0.75),
... )
>>> any("fold" in s.info["events"] for s in steps)
True
>>> steps[-1].y[0] < 0 and steps[-1].params["l1"] > 0
True