Basin Classification
Classifying trajectories to identify hidden attractors.
The core goal of this library is determining whether an attractor is hidden or self-excited. This is done by examining the relationship between the attractor’s basin and the system’s unstable equilibria. The basins module provides the tools to perform this classification automatically.
The BasinLabel Enum
Every trajectory integrated by the workflows is ultimately assigned a label from the BasinLabel enumeration:
from hidden_attractors.basins import BasinLabel
print(BasinLabel.SELF_EXCITED) # Trajectory converges to or originates from an equilibrium neighborhood
print(BasinLabel.HIDDEN_CANDIDATE) # Trajectory forms an attractor disconnected from all equilibria
print(BasinLabel.DIVERGENT) # Trajectory escapes to infinity
print(BasinLabel.INCONCLUSIVE) # Numerical errors or NaNs during integration
Basic Classification
If you have integrated a trajectory and just want to classify its final point, use classify_basin(). This is very fast and requires only the last point of the simulation.
from hidden_attractors.basins import classify_basin
from hidden_attractors.models import equilibria_nonsmooth, chua_nonsmooth_parameters
import numpy as np
params = chua_nonsmooth_parameters()
eq = equilibria_nonsmooth(params)
# Assume final_point is the last row of your integration array
final_point = np.array([1.51, 0.02, -1.49])
label = classify_basin(
final_point=final_point,
equilibria=eq,
thresholds={
"self_excited": 0.5, # Distance to be considered "touching" an equilibrium
"divergent": 100.0 # Distance to be considered escaped to infinity
}
)
print(label) # BasinLabel.SELF_EXCITED (it's very close to O+)
Thresholds
The thresholds dictionary controls the geometric boundaries of the classification:
self_excited: If the Euclidean distance between thefinal_pointand any equilibrium is less than this value, it’s classified as self-excited. This defines the “small neighborhood” around the unstable equilibria.divergent: If any coordinate of thefinal_pointexceeds this value, it’s marked divergent.
Strict Trajectory Classification
While classify_basin only looks at the final point, sometimes a trajectory might form a large attractor that doesn’t converge to a point, but does periodically swing very close to an equilibrium. To classify the entire attractor cloud, use classify_trajectory().
from hidden_attractors.basins import classify_trajectory
# x is the full trajectory array of shape (N, 3)
label = classify_trajectory(
trajectory=x,
equilibria=eq,
thresholds={"self_excited": 0.5, "divergent": 100.0}
)
This function computes the minimum distance from any point in the trajectory to any equilibrium. If that minimum distance is less than the self_excited threshold, the entire attractor is considered self-excited, even if the final point happens to be far away at the moment integration stopped.
This is the most robust way to verify a hidden candidate.