Source code for ecal.calculators.preprocessing_flops

"""FLOP calculators for data preprocessing steps (normalization, min-max
scaling, and Gramian Angular/Difference Field encoding)."""

from abc import ABC, abstractmethod
from typing import Dict, Union


[docs] class PreprocessingFLOPCalculator(ABC): """Abstract base class for data-preprocessing FLOP calculators."""
[docs] @abstractmethod def calculate_flops(self, data_size: int) -> Dict[str, Union[int, Dict]]: """Calculate FLOPs required to preprocess a batch of data. Args: data_size: Total number of scalar data points to preprocess. Returns: Dict[str, Union[int, Dict]]: ``"total_flops"`` and ``"data_shape"``. """ pass
[docs] class NormalizationCalculator(PreprocessingFLOPCalculator): """FLOP calculator for z-score normalization (mean/std standardization)."""
[docs] def calculate_flops(self, data_size: int) -> Dict[str, Union[int, Dict]]: """Calculate FLOPs for z-score normalization of ``data_size`` points. Accounts for computing the mean, standard deviation, and applying ``(x - mean) / std`` to every point. Args: data_size: Total number of scalar data points to normalize. Returns: Dict[str, Union[int, Dict]]: ``"total_flops"`` (``6 * data_size + 1``) and ``"data_shape"`` (``None``, shape is unchanged by normalization). """ # calculating mean: # 1. add all data points -> data_size - 1 # 2. divide by data_size -> 1 # Mean calculation FLOPS: data_size - 1 + 1 = data_size # ------------------------------------------------------------ # calculating std: # 1. subtract mean from each data point -> data_size # 2. square the result -> data_size # 3. add the squares -> data_size - 1 # 4. divide by data_size -> 1 # 5. take the square root -> 1 # Std. calculation FLOPS: data_size + data_size + (data_size - 1) + 1 + 1 = 3 * data_size + 1 # ------------------------------------------------------------ # normalization: # 1. subtract mean from each data point -> data_size # 2. divide by std -> data_size # normalization FLOPS: data_size + data_size = 2 * data_size # ------------------------------------------------------------ # FINAL total FLOPS calculation: data_size + 3 * data_size + 1 + 2 * data_size = 6 * data_size + 1 total_flops = (6 * data_size) + 1 return {"total_flops": total_flops, "data_shape": None }
[docs] class MinMaxScalingCalculator(PreprocessingFLOPCalculator): """FLOP calculator for min-max scaling."""
[docs] def calculate_flops(self, data_size: int) -> Dict[str, Union[int, Dict]]: """Calculate FLOPs for min-max scaling of ``data_size`` points. Accounts for computing ``max - min`` once and applying ``(x - min) / (max - min)`` to every point. Args: data_size: Total number of scalar data points to scale. Returns: Dict[str, Union[int, Dict]]: ``"total_flops"`` (``2 * data_size + 1``) and ``"data_shape"`` (``None``, shape is unchanged by scaling). """ # Min-Max scaling: # 0. find max and min -> 0 # 1. calculate max-min -> 1 # 1. subtract min from each data point -> data_size # 2. divide by (max - min) -> data_size # Total FLOPS: 1 + data_size + data_size = 2 * data_size + 1 scaling_flops = data_size * 2 + 1 # return {"total_flops": scaling_flops, "data_shape": None }
[docs] class GramianDifferenceFieldCalculator(PreprocessingFLOPCalculator): """FLOP calculator for Gramian Angular/Difference Field (GADF) encoding, following the pyts implementation's FLOP profile."""
[docs] def calculate_flops(self, data_size: int, time_steps: int) -> Dict[str, Union[int, Dict]]: """Calculate FLOPs for GADF encoding of time-series data. Accounts for two min-max scaling passes over the data followed by the pairwise GADF computation across time steps. Args: data_size: Number of independent time-series samples. time_steps: Number of time steps per sample. Returns: Dict[str, Union[int, Dict]]: ``"total_flops"`` and ``"data_shape"`` (``(data_size, time_steps, time_steps)``, the shape of the resulting GADF matrices). """ # # 1. perform minmax 2 times -> 2 * data_size +1 # 2. compute GADF flops based on pyTS implementation - > (5 * time_steps + time_steps * time_steps) * data_size minmax_calculator = MinMaxScalingCalculator() minmax_flops = minmax_calculator.calculate_flops(data_size * time_steps)["total_flops"] gadf_flops = (5 * time_steps + time_steps * time_steps) * data_size total_flops = minmax_flops + gadf_flops return { "total_flops": total_flops, "data_shape": (data_size, time_steps, time_steps) }