Source code for curvesimplify.agarwal

"""Simplification algorithm by Agarwal et al. [1]_.

This is a greedy algorithm, fast but relatively inaccurate.

References
----------
.. [1] Agarwal, Pankaj K., et al. "Near-linear time approximation algorithms for curve
   simplification." Algorithmica 42 (2005): 203-219.
"""

import numpy as np
from curvesimilarities.frechet import decision_problem, fd
from numba import njit

__all__ = [
    "min_num",
    "min_err",
]


EPSILON = np.finfo(np.float64).eps


[docs] @njit(cache=True) def min_num(curve, err, err_type="frechet"): r"""Agarwal min-:math:`\#` simplification. Parameters ---------- curve : ndarray A :math:`p` by :math:`n` array of :math:`p` points in an :math:`n`-dimensional space. err : double Error threshold. err_type : {'frechet'} Error type. Refer to the package docstring. Returns ------- simp : ndarray An :math:`\ell \le p` by :math:`n` array of :math:`\ell` points in an :math:`n`-dimensional space. """ ij = 0 ret = np.empty(len(curve), dtype=np.int_) count = 0 ret[count] = ij count += 1 n = len(curve) if err_type == "frechet": while ij < n - 1: L = 0 high = min(2 ** (L + 1), n - ij - 1) all_ok = False while decision_problem( np.concatenate((curve[ij : ij + 1], curve[ij + high - 1 : ij + high])), curve[ij : ij + high + 1], err, ): if high == n - ij - 1: # stop because all remaining vertices can be skipped all_ok = True break L += 1 high = min(2 ** (L + 1), n - ij - 1) if all_ok: ret[count] = n - 1 count += 1 break low = max(1, high // 2) while low < high - 1: mid = (low + high) // 2 if decision_problem( np.concatenate( (curve[ij : ij + 1], curve[ij + mid - 1 : ij + mid]) ), curve[ij : ij + mid + 1], err, ): low = mid else: high = mid ij += min(low, n - ij - 1) ret[count] = ij count += 1 return curve[ret[:count]]
[docs] @njit(cache=True) def min_err(curve, ell, err_type="frechet"): r"""Agarwal min-:math:`\epsilon` simplification. Parametric search is evoked on :func:`min_num` to find the minimum error satisfying :math:`\ell`. Parameters ---------- curve : ndarray A :math:`p` by :math:`n` array of :math:`p` points in an :math:`n`-dimensional space. ell : double Desired number of vertices of simplification result. err_type : {'frechet'} Error type. Refer to the package docstring. Returns ------- simp : ndarray An :math:`p' \le \ell` by :math:`n` array of :math:`p'` points in an :math:`n`-dimensional space. err : double Simplification error. """ thres_low = 0 shortcut = np.concatenate((curve[:1], curve[:-1])) thres_high = fd(curve, shortcut) # TODO: use cheaper initializer simp_vert = min_num(curve, thres_high, err_type) # may be > 2 while len(simp_vert) > ell: # tolerance too small thres_low = thres_high thres_high *= 2 simp_vert = min_num(curve, thres_high, err_type) # Find adequate threshold by binary search while thres_high - thres_low > EPSILON: thres = (thres_low + thres_high) / 2 if (thres - thres_low < EPSILON) | (thres_high - thres < EPSILON): break simp_vert = min_num(curve, thres, err_type) if len(simp_vert) > ell: thres_low = thres else: thres_high = thres return simp_vert, thres