memoizing decorator for linkage functions.

    Parameters have been hardcoded (no ``*args``, ``**kwargs`` magic), because,
    the way this is coded (interchangingly using sets and frozensets) is true
    for this specific case. For other cases that is not necessarily guaranteed.

def cached(fun):
    """
    memoizing decorator for linkage functions.

    Parameters have been hardcoded (no ``*args``, ``**kwargs`` magic), because,
    the way this is coded (interchangingly using sets and frozensets) is true
    for this specific case. For other cases that is not necessarily guaranteed.
    """

    _cache = {}

    @wraps(fun)
    def newfun(a, b, distance_function):
        frozen_a = frozenset(a)
        frozen_b = frozenset(b)
        if (frozen_a, frozen_b) not in _cache:
            result = fun(a, b, distance_function)
            _cache[(frozen_a, frozen_b)] = result
        return _cache[(frozen_a, frozen_b)]
    return newfun