Skip to content

base

base #

What a distance function is: extract features, compare them pairwise.

Every metric implements two vectorized steps — extract turns values into numeric features, pairwise turns two feature sets into a matrix of distances — and inherits the scalar __call__ and the full matrix from them.

Missing data has one rule, applied here: an absent value extracts as nan features, so every pair involving it has nan distance. A combination drops its nan terms, and is itself nan only when no term survives; select_sessions never offers a candidate whose distance is nan.

DistanceFunction #

Bases: ABC

A statistical distance between two values along one dimension.

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
class DistanceFunction[T](ABC):
    """A statistical distance between two values along one dimension."""

    @abstractmethod
    def extract(self, values: cg.Array) -> np.ndarray:
        """The numeric features of each value, one row each (``nan`` when absent)."""
        ...

    @abstractmethod
    def pairwise(self, features_a: np.ndarray, features_b: np.ndarray) -> np.ndarray:
        """The ``len(a) × len(b)`` distances between two extracted feature sets."""
        ...

    def __call__(self, a: T, b: T) -> float:
        """The distance between two values (``nan`` when they cannot be compared)."""
        return float(self.matrix(cg.Array([a]), cg.Array([b]))[0, 0])

    def matrix(self, values_a: cg.Array, values_b: cg.Array | None = None) -> np.ndarray:
        """The pairwise distances between two value sets (``values_a`` against itself)."""
        features_a = self.extract(values_a)
        features_b = features_a if values_b is None else self.extract(values_b)
        return self.pairwise(features_a, features_b)

    def defined(self, values: cg.Array) -> np.ndarray:
        """Which values this metric can compare at all, as a boolean mask."""
        return np.array([not np.isnan(self(value, value)) for value in values], dtype=bool)

__call__(a, b) #

The distance between two values (nan when they cannot be compared).

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
def __call__(self, a: T, b: T) -> float:
    """The distance between two values (``nan`` when they cannot be compared)."""
    return float(self.matrix(cg.Array([a]), cg.Array([b]))[0, 0])

defined(values) #

Which values this metric can compare at all, as a boolean mask.

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
def defined(self, values: cg.Array) -> np.ndarray:
    """Which values this metric can compare at all, as a boolean mask."""
    return np.array([not np.isnan(self(value, value)) for value in values], dtype=bool)

extract(values) abstractmethod #

The numeric features of each value, one row each (nan when absent).

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
@abstractmethod
def extract(self, values: cg.Array) -> np.ndarray:
    """The numeric features of each value, one row each (``nan`` when absent)."""
    ...

matrix(values_a, values_b=None) #

The pairwise distances between two value sets (values_a against itself).

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
def matrix(self, values_a: cg.Array, values_b: cg.Array | None = None) -> np.ndarray:
    """The pairwise distances between two value sets (``values_a`` against itself)."""
    features_a = self.extract(values_a)
    features_b = features_a if values_b is None else self.extract(values_b)
    return self.pairwise(features_a, features_b)

pairwise(features_a, features_b) abstractmethod #

The len(a) × len(b) distances between two extracted feature sets.

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
@abstractmethod
def pairwise(self, features_a: np.ndarray, features_b: np.ndarray) -> np.ndarray:
    """The ``len(a) × len(b)`` distances between two extracted feature sets."""
    ...

as_distance(function) #

function as a [DistanceFunction][], wrapping a plain callable as one.

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
def as_distance(function: Callable[[Any, Any], float]) -> DistanceFunction:
    """``function`` as a [DistanceFunction][], wrapping a plain callable as one."""
    if isinstance(function, DistanceFunction):
        return function
    return _CallableDistance(function)

numeric(values, *fields) #

Each value's fields as a row of floats — the value itself when none are named.

Parameters:

Name Type Description Default
values Array

The values to read.

required
fields str

The field names to read from each value, in column order.

()

Returns:

Type Description
ndarray

A len(values) × max(len(fields), 1) array; an absent value or field

ndarray

reads nan.

Source code in capturegraph-lib/capturegraph/scheduling/distance/base.py
def numeric(values: cg.Array, *fields: str) -> np.ndarray:
    """Each value's ``fields`` as a row of floats — the value itself when none are named.

    Args:
        values: The values to read.
        fields: The field names to read from each value, in column order.

    Returns:
        A ``len(values) × max(len(fields), 1)`` array; an absent value or field
        reads ``nan``.
    """
    rows = [
        [_number(access(value, field)) for field in fields] if fields else [_number(value)]
        for value in values
    ]
    return np.array(rows, dtype=np.float64).reshape(len(values), len(fields) or 1)