Function versioning

InDSL comes with the indsl.versioning module, which allows to implement multiple versions of InDSL functions. As a library user, one can then select and execute a specific function version.

Example

In this example, we implement the abs_diff function, which computes the element-wise absolute difference of two time-series. We will first implement a naive version of that function, which we name version 1.0 (versioning in inDSL always starts with 1.0), followed by a more robust version 1.1.

Implementation

Implementation of v1.0

We begin with a simple implementation:

import pandas as pd

from indsl import versioning


@versioning.register(version="1.0", deprecated=True)
def abs_diff(a: pd.Series, b: pd.Series) -> pd.Series:
    return (a - b).abs()

They key in this function definition is the indsl.versioning.register() decorator. This decorator registers the function as a versioned function with name abs_diff and version 1.0. We also mark the function as deprecated, since we will soon implement a new version of the function. This means that we can retrieve and execute this version, even after newer version of the same functions have been registered.

Our, initial implementation is not very robust and results easily in nan outputs. This happens specifically when we apply abs`diff to time-series with non-matching indices:

idx = pd.date_range("2022-01-01", periods=5, freq="1h")
a = pd.Series([1, 2, 3, 4, 5], index=idx)

idx = pd.date_range("2022-01-01", periods=3, freq="2h")
b = pd.Series([1, 3, 5], index=idx)

abs_diff(a, b)
2022-01-01 00:00:00    0.0
2022-01-01 01:00:00    NaN
2022-01-01 02:00:00    0.0
2022-01-01 03:00:00    NaN
2022-01-01 04:00:00    0.0
dtype: float64

Version 1.1 will fix this issue through a more robust implementation.

Implementation of v1.1

Next, we implement the new version of the abs_diff and mark it as version 1.1.

from indsl.resample import reindex_v1  # noqa


@versioning.register(version="1.1")  # type: ignore
def abs_diff(a: pd.Series, b: pd.Series) -> pd.Series:
    a, b = reindex_v1.reindex(a, b)
    return (a - b).abs()

We rely on the build-in function reindex to align the indices of the time-series (using linear-interpolation) before performing the operations.

abs_diff(a, b)
2022-01-01 00:00:00    0.0
2022-01-01 01:00:00    0.0
2022-01-01 02:00:00    0.0
2022-01-01 03:00:00    0.0
2022-01-01 04:00:00    0.0
Freq: h, dtype: float64

Getting versioned functions and their versions

We can get a list of all versioned functions with:

versioning.get_registered_functions()
['reindex', 'reindex_many', 'interpolate', 'resample', 'resample_to_granularity', 'trapezoidal_integration', 'differentiate', 'butterworth', 'ewma', 'lwma', 'sma', 'negative_running_hours_check', 'value_decrease_check', 'drift', 'flow_through_valve', 'wavelet_filter', 'arma_predictor', 'holt_winters_predictor', 'no_op', 'detect_outliers', 'remove_outliers', 'SG_SMOOTHER', 'ALMA_SMOOTHER', 'ARMA_SMOOTHER', 'BTR_SMOOTHER', 'CHB_SMOOTHER', 'EXP_WMA', 'LINEAR_WMA', 'SIMPLE_MA', 'INTERPOLATE', 'RESAMPLE_EXTENDED', 'RESAMPLE', 'POLY_REGRESSOR', 'SHUTIN_CALC', 'PI_CALC', 'PASSTHROUGH', 'OUTLIER_DETECTOR', 'DRIFT_DETECTOR', 'SS_DETECTOR', 'VARIABLE_MA', 'WAVELET_FILTER', 'STATUS_FLAG_FILTER', 'OUTLIERS_REMOVE', 'ROUND', 'FLOOR', 'CEIL', 'SIGN', 'CLIP', 'MAX', 'MIN', 'BIN_MAP', 'SIN', 'COS', 'TAN', 'ARCSIN', 'ARCCOS', 'ARCTAN', 'ARCTAN2', 'DEG2RAD', 'RAD2DEG', 'SINH', 'COSH', 'TANH', 'ARCSINH', 'ARCCOSH', 'ARCTANH', 'ADD', 'SUB', 'MUL', 'DIV', 'POW', 'INV', 'SQRT', 'NEG', 'ABS', 'MOD', 'INTEGRATE', 'DDX', 'EXP', 'LOG', 'LOG2', 'LOG10', 'LOGN', 'versioning_test_op', 'abs_diff']

We can retrieve which versions we have of a function with:

versioning.get_versions("abs_diff")
['1.0', '1.1']

Running versioned functions

We can access and run specific function version with the versioning.get command:

abs_diff_v1 = versioning.get("abs_diff", version="1.0")
abs_diff_v1(a, b)
2022-01-01 00:00:00    0.0
2022-01-01 01:00:00    NaN
2022-01-01 02:00:00    0.0
2022-01-01 03:00:00    NaN
2022-01-01 04:00:00    0.0
dtype: float64

Omitting the version argument will automatically select the latest version

abs_diff_v1_1 = versioning.get("abs_diff")
abs_diff_v1_1(a, b)

# sphinx_gallery_thumbnail_path = '_static/images/versioning_thumbnail.png'
2022-01-01 00:00:00    0.0
2022-01-01 01:00:00    0.0
2022-01-01 02:00:00    0.0
2022-01-01 03:00:00    0.0
2022-01-01 04:00:00    0.0
Freq: h, dtype: float64

Total running time of the script: (0 minutes 0.016 seconds)

Gallery generated by Sphinx-Gallery