Pragmastat / Python

Copy-pastable NumPy-based implementation:

from typing import Sequence, Union
import numpy as np
from numpy.typing import NDArray


def center(x: Union[Sequence[float], NDArray]) -> float:
    x = np.asarray(x)
    n = len(x)
    if n == 0:
        raise ValueError("Input array cannot be empty")
    pairwise_averages = np.add.outer(x, x) / 2
    indices = np.triu_indices(n, k=0)
    return float(np.median(pairwise_averages[indices]))


def spread(x: Union[Sequence[float], NDArray]) -> float:
    x = np.asarray(x)
    n = len(x)
    if n == 0:
        raise ValueError("Input array cannot be empty")
    if n == 1:
        return 0.0
    pairwise_diffs = np.subtract.outer(x, x)
    pairwise_abs_diffs = np.abs(pairwise_diffs)
    indices = np.triu_indices(n, k=1)
    return float(np.median(pairwise_abs_diffs[indices]))


def volatility(x: Union[Sequence[float], NDArray]) -> float:
    center_val = center(x)
    if center_val == 0:
        raise ValueError("Volatility is undefined when Center equals zero")
    return spread(x) / abs(center_val)


def precision(x: Union[Sequence[float], NDArray]) -> float:
    x = np.asarray(x)
    n = len(x)
    if n == 0:
        raise ValueError("Input array cannot be empty")
    return 2 * spread(x) / np.sqrt(n)


def med_shift(x: Union[Sequence[float], NDArray], y: Union[Sequence[float], NDArray]) -> float:
    x = np.asarray(x)
    y = np.asarray(y)
    if len(x) == 0 or len(y) == 0:
        raise ValueError("Input arrays cannot be empty")
    pairwise_shifts = np.subtract.outer(x, y)
    return float(np.median(pairwise_shifts))


def med_ratio(x: Union[Sequence[float], NDArray], y: Union[Sequence[float], NDArray]) -> float:
    x = np.asarray(x)
    y = np.asarray(y)
    if len(x) == 0 or len(y) == 0:
        raise ValueError("Input arrays cannot be empty")
    if np.any(y <= 0):
        raise ValueError("All values in y must be strictly positive")
    pairwise_ratios = np.divide.outer(x, y)
    return float(np.median(pairwise_ratios))


def med_spread(x: Union[Sequence[float], NDArray], y: Union[Sequence[float], NDArray]) -> float:
    x = np.asarray(x)
    y = np.asarray(y)
    n = len(x)
    m = len(y)
    if n == 0 or m == 0:
        raise ValueError("Input arrays cannot be empty")
    spread_x = spread(x)
    spread_y = spread(y)
    return (n * spread_x + m * spread_y) / (n + m)


def med_disparity(x: Union[Sequence[float], NDArray], y: Union[Sequence[float], NDArray]) -> float:
    med_spread_val = med_spread(x, y)
    if med_spread_val == 0:
        return float('inf')
    return med_shift(x, y) / med_spread_val