Source code for dyconnmap.ts.fnn

# -*- coding: utf-8 -*-
""" False Nearest Neighbors


|

-----


.. [Kennel1992] Kennel, M. B., Brown, R., & Abarbanel, H. D. (1992). Determining embedding dimension for phase-space reconstruction using a geometrical construction. Physical review A, 45(6), 3403.
.. [Abarbane2012] Abarbanel, H. (2012). Analysis of observed chaotic data. Springer Science & Business Media.
"""
# Author: Avraam Marimpis <avraam.marimpis@gmail.com>

from typing import Optional
import numpy as np


[docs]def fnn( ts: "np.ndarray[np.float32]", tau: int, max_dim: Optional[int] = 20, neighbors_reduction: Optional[float] = 0.10, rtol: Optional[float] = 15.0, atol: Optional[float] = 2.0, ) -> Optional[int]: """ False Nearest Neighbors Notes ----- The execution stops either when the maxium number of embedding dimensions is reached, or the the number of neighbors is reduced to specific percentage. Parameters ---------- ts : array-like, 1d tau : int Time-delay parameter. max_dim : int Maximum embedding dimension. neighbors_reduction : float Maximum percentage of neighbors reduction. Default '0.10' (10%). rtol : float First threshold, criterion to identify a false neighbor. (Neighborhood size) atol : float Second threshold, criterion to identify a false neighbor. Returns ------- min_dimension : int Minimum embedding dimension. """ ts = ts.flatten() neighbors_perc = neighbors_reduction * 100.0 fnn_ini = 0.0 min_dimension = None Ra = np.std(ts) for dim in range(1, max_dim): min_dimension = dim ed_ts, num_points = __embed_delay(ts, dim, tau) if ed_ts is not None and num_points > 0: distances = np.zeros((num_points, num_points)) for i in range(num_points): distances[i, :] = __euclidean_distance( ed_ts, np.ones((num_points, dim)) * ed_ts[i, :] ) indices = np.argsort(distances) sort_distances = np.sort(distances) all_D = np.abs( ts[np.arange(num_points) + dim * tau] - ts[indices[:, 1] + dim * tau] ) all_R = np.sqrt(np.power(all_D, 2) + np.power(sort_distances[:, 1], 2)) a = all_D / sort_distances[:, 1] b = all_R / Ra fnn_a_or_b = np.where((a > rtol) | (b > atol)) fnn_value = len(fnn_a_or_b[0]) if dim == 1: fnn_ini = fnn_value elif fnn_value < fnn_ini / neighbors_perc: break else: break return min_dimension
def __euclidean_distance(x, y): return np.sqrt(np.sum(np.power(x - y, 2), 1)) def __embed_delay(ts, dim, tau): """ Embed delay, treated for FNN method. For internal use only. """ ts = ts.flatten() new_ts = np.zeros((dim, len(ts))) new_ts[0, :] = ts l = len(ts) m = l - (dim) * tau if dim == 1: m = l - tau if m < 0: return None, m for i in range(1, dim): offset = i - 1 tmp = np.roll(new_ts[offset], l - tau) new_ts[i] = tmp new_ts = new_ts.T y = new_ts[0:m, 0:dim] return y, m