kinamax.integration.core

Time-integration orbit-finding, clustering, and result post-processing utilities.

class kinamax.integration.core.Container[source]

Bases: object

Base container exposing NumPy/Polars export helpers for array-like fields.

as_dict(flatten=True)[source]

Convert container fields to a NumPy-backed dictionary.

Parameters:

flatten (bool)

Return type:

dict[str, ndarray]

as_polars(repeat=0)[source]

Convert the container to a Polars DataFrame.

Parameters:

repeat (int)

Return type:

DataFrame

kinamax.integration.core.namedtuple_repr(name, values)[source]

Render a compact Polars-backed repr for NamedTuple-style containers.

Parameters:
  • name (str)

  • values (Mapping[str, Any])

Return type:

str

class kinamax.integration.core.AttractorFinderConfig(init_time=Array(0., dtype=float32), init_time_step=Array(0.001, dtype=float32), convergence_tol=Array(1.e-06, dtype=float32), target_frequency=50.0, subharmonic_factor=10.0)[source]

Bases: NamedTuple

Configuration values driving the shooting-based attractor search.

Examples

>>> config = AttractorFinderConfig(
...     target_frequency=50.0,
...     init_time=0.0,
...     init_time_step=1.0e-3,
...     convergence_tol=1.0e-10,
...     subharmonic_factor=10.0,
... )
>>> print(config)
AttractorFinderConfig
...
│ init_time          ┆ scalar ┆ float64 ┆ 0.0...
│ init_time_step     ┆ scalar ┆ float64 ┆ 0.001...
│ convergence_tol    ┆ scalar ┆ float64 ┆ 1e-10...
│ target_frequency   ┆ scalar ┆ float64 ┆ 50.0...
│ subharmonic_factor ┆ scalar ┆ float64 ┆ 10.0...
...
Parameters:
  • init_time (Array)

  • init_time_step (Array)

  • convergence_tol (Array)

  • target_frequency (float)

  • subharmonic_factor (float)

init_time: Array

Alias for field number 0

init_time_step: Array

Alias for field number 1

convergence_tol: Array

Alias for field number 2

target_frequency: float

Alias for field number 3

subharmonic_factor: float

Alias for field number 4

kinamax.integration.core.convert_subharmonics_flags(subharmonics_flags, final_flags, targetted_subharmonics)[source]

Collapse per-target boolean flags into detected subharmonic orders.

For rows flagged as converged (final_flags == 1), the first active entry in subharmonics_flags selects the matching order from targetted_subharmonics. Rows without convergence keep value 0.

Parameters:
  • subharmonics_flags (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • final_flags (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • targetted_subharmonics (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

Return type:

ndarray[tuple[Any, …], dtype[int32]]

class kinamax.integration.core.AttractorFinderSolution(attractors, detected_subharmonic, subharmonic_residual, minimum_residual, simulated_periods, simulated_time, final_flag, simulated_iterations, converged)[source]

Bases: Container

Structured output produced by AttractorFinder.find_attractors.

Parameters:
  • attractors (Array)

  • detected_subharmonic (Array)

  • subharmonic_residual (Array)

  • minimum_residual (Array)

  • simulated_periods (Array)

  • simulated_time (Array)

  • final_flag (Array)

  • simulated_iterations (Array)

  • converged (Array)

attractors: Array
detected_subharmonic: Array
subharmonic_residual: Array
minimum_residual: Array
simulated_periods: Array
simulated_time: Array
final_flag: Array
simulated_iterations: Array
converged: Array
as_dict(state_vector_labels=None)[source]

Flatten attractor-finder outputs to a tabular NumPy dictionary.

Parameters:

state_vector_labels (Sequence[str] | None)

Return type:

dict[str, ndarray]

get_subharmonics()[source]

Return the detected subharmonic order for each flattened attractor row.

Return type:

ndarray

as_polars(state_vector_labels=None)[source]

Convert the solution object to a Polars DataFrame.

Parameters:

state_vector_labels (Sequence[str] | None)

Return type:

DataFrame

class kinamax.integration.core.AttractorFinder[source]

Bases: object

Namespace holding attractor-finder data layouts and static helpers.

class Params(residuals_per_period=10, targetted_subharmonics=array([1, 3, 5]), max_periods=1000, controller=PIDController(rtol=1e-07, atol=1e-09), solver=Tsit5())[source]

Bases: NamedTuple

Static settings for the shooting-based attractor search.

Examples

>>> import jax.numpy as jnp
>>> from diffrax import PIDController, Tsit5
>>> finder = AttractorFinder.Params(
...     residuals_per_period=20,
...     targetted_subharmonics=jnp.array([1, 2, 3, 5]),
...     max_periods=2000,
...     controller=PIDController(rtol=1e-8, atol=1e-9),
...     solver=Tsit5(),
... )
>>> print(finder)
AttractorFinder.Params
...
│ residuals_per_period   ┆ scalar ┆ int64         ┆ 20...
│ targetted_subharmonics ┆ (4,)   ┆ int32         ┆ [1, 2, 3, 5]...
│ max_periods            ┆ scalar ┆ int64         ┆ 2000...
│ controller             ┆ scalar ┆ PIDController ┆ PIDController(rtol=1e-08, atol...
│ solver                 ┆ scalar ┆ Tsit5         ┆ Tsit5()...
...
Parameters:
  • residuals_per_period (int)

  • targetted_subharmonics (ndarray[tuple[Any, ...], dtype[int64]])

  • max_periods (int)

  • controller (PIDController)

  • solver (Tsit5)

residuals_per_period: int

Alias for field number 0

targetted_subharmonics: ndarray[tuple[Any, ...], dtype[int64]]

Alias for field number 1

max_periods: int

Alias for field number 2

controller: PIDController

Alias for field number 3

solver: Tsit5

Alias for field number 4

static get_max_subharmonic(finder)[source]

Return the largest targeted subharmonic order.

Parameters:

finder (Params)

Return type:

int

static get_time_steps_number(finder)[source]

Return the number of saved samples for one shooting window.

Parameters:

finder (Params)

Return type:

int

static get_max_shooting_iterations(finder)[source]

Return the maximum number of shooting windows to integrate.

Parameters:

finder (Params)

Return type:

int

static calculate_subharmonic_atomic_residual(pos, args)[source]

Accumulate one term of the weighted shooting residual.

Parameters:
  • pos (int)

  • args (tuple[Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray, int, Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray, Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray])

Return type:

tuple[Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray, int, Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray, Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray]

static calculate_subharmonic_residual(subharmonic, X, residuals_per_period, state_weights)[source]

Calculate the weighted shooting residual for one candidate subharmonic.

Parameters:
  • subharmonic (int)

  • X (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • residuals_per_period (int)

  • state_weights (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

Return type:

Array

static integrate_and_check_convergence(finder, init_conditions, start_time, end_time, steps_number, problem_definition, problem, init_time_step, targetted_subharmonics, residuals_per_period)[source]

Integrate one shooting window and evaluate residuals for each target.

Parameters:
  • finder (Params)

  • init_conditions (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • start_time (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • end_time (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • steps_number (int)

  • problem_definition (Any | None)

  • problem (Any)

  • init_time_step (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • targetted_subharmonics (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • residuals_per_period (int)

Return type:

tuple[Array, Array, Array, Array]

static find_attractors(finder, problem_definition_or_problem, problem_or_init_conditions, init_conditions_or_finder_config, finder_config=None)[source]

Integrate until convergence and then sample the attractor over one orbit.

This function accepts either the legacy call shape find_attractors(finder, problem, init_conditions, finder_config) or the data-oriented shape find_attractors(finder, problem_definition, problem, init_conditions, finder_config).

Examples

>>> import jax.numpy as jnp
>>> from diffrax import PIDController, Tsit5
>>> from kinamax.integration.models import H46Problem
>>> problem = H46Problem.Params(fd=jnp.array(50.0), Ad=jnp.array(2.5))
>>> x0 = jnp.array([0.0, 0.0, 0.0])
>>> finder = AttractorFinder.Params(
...     residuals_per_period=20,
...     targetted_subharmonics=jnp.array([1, 2, 3, 5]),
...     max_periods=2000,
...     controller=PIDController(rtol=1e-8, atol=1e-9),
...     solver=Tsit5(),
... )
>>> config = AttractorFinderConfig(
...     target_frequency=50.0,
...     init_time=0.0,
...     init_time_step=1.0e-3,
...     convergence_tol=1.0e-10,
...     subharmonic_factor=10.0,
... )
>>> problem, config, x0, solution = AttractorFinder.find_attractors(
...     finder, H46Problem, problem, x0, config
... )
Parameters:
Return type:

tuple[P, AttractorFinderConfig, Array, AttractorFinderSolution]

kinamax.integration.core.post_process_attractor_finder_results(problem_class, problems, finder_configs, init_conditions, solutions, target_subharmonics, solution_state_labels)[source]

Flatten batched attractor-finder outputs to one balanced result table.

The returned table contains one row per retained attractor sample. For a detected subharmonic Hk, only the first k attractor rows are kept per simulation so different simulations can be compared with a consistent layout.

Examples

>>> import jax.numpy as jnp
>>> from diffrax import PIDController, Tsit5
>>> from kinamax.integration.models import H46Problem
>>> problem = H46Problem.Params(fd=jnp.array(50.0), Ad=jnp.array(2.5))
>>> x0 = jnp.array([0.0, 0.0, 0.0])
>>> finder = AttractorFinder.Params(
...     residuals_per_period=20,
...     targetted_subharmonics=jnp.array([1, 2, 3, 5]),
...     max_periods=2000,
...     controller=PIDController(rtol=1e-8, atol=1e-9),
...     solver=Tsit5(),
... )
>>> config = AttractorFinderConfig(
...     target_frequency=50.0,
...     init_time=0.0,
...     init_time_step=1.0e-3,
...     convergence_tol=1.0e-10,
...     subharmonic_factor=10.0,
... )
>>> problem, config, x0, solution = AttractorFinder.find_attractors(
...     finder, H46Problem, problem, x0, config
... )
>>> table = post_process_attractor_finder_results(
...     problem_class=H46Problem,
...     problems=problem,
...     finder_configs=config,
...     init_conditions=x0,
...     solutions=solution,
...     target_subharmonics=jnp.array([1, 2, 3, 5]),
...     solution_state_labels=["xa", "dotxa", "Eha"],
... )
Parameters:
  • problem_class (Any)

  • problems (Any)

  • finder_configs (Any)

  • init_conditions (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • solutions (AttractorFinderSolution)

  • target_subharmonics (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • solution_state_labels (Sequence[str])

Return type:

DataFrame

kinamax.integration.core.cluster_points(points, weights, distance_threshold=0.01, method='dbscan')[source]

Cluster weighted points and return labels with centroids in original space.

Parameters:
  • points (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • weights (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray)

  • distance_threshold (float)

  • method (str)

Return type:

tuple[int, ndarray, ndarray]

kinamax.integration.core.detect_orbits(problem_class, simulations, ode_params_labels, attractor_state_vec_labels, state_vec_labels, distance_threshold=0.01, clustering_method='dbscan')[source]

Cluster attractor samples per configuration and map them to orbit IDs.

Workflow:

  1. Group rows by ODE parameters, detected subharmonic, and target frequency so each configuration is processed independently.

  2. Cluster the recorded attractor points in the weighted state space to estimate unique attractors for the group.

  3. Assign globally unique attractor labels and record which simulations share the same attractor tuple (one orbit).

  4. Return tidy Polars DataFrames for attractors and the simulation->orbit map.

Parameters:
  • problem_class (Any)

  • simulations (DataFrame)

  • ode_params_labels (Sequence[str])

  • attractor_state_vec_labels (Sequence[str])

  • state_vec_labels (Sequence[str])

  • distance_threshold (float)

  • clustering_method (str)

Return type:

tuple[DataFrame, DataFrame]