def _test_pw_equal_single_dists(x: np.ndarray, y: np.ndarray,
                                distance_function: Callable,
                                conical_name: str) -> None:
    """Test pairwise result is equal to individual distance.

    Parameters
    ----------
    x: np.ndarray (1d, 2d or 3d array)
        First timeseries
    y: np.ndarray (1d, 2d or 3d array)
        Second timeseries
    distance_function: Callable
        Distance function to test
    conical_name: str
        Name of the metric
    """
    if x.ndim < 2:
        return

    # use euclidean distance so this test will fail
    if conical_name == "lcss" or conical_name == "edr" or conical_name == "erp":
        return
    pw_result = pairwise_distance(x, y, metric=conical_name)

    matrix = np.zeros((len(x), len(y)))
    for i in range(len(x)):
        curr_x = x[i]
        for j in range(len(y)):
            curr_y = y[j]
            matrix[i, j] = distance_function(curr_x, curr_y)

    assert np.array_equal(matrix, pw_result)
Example #2
0
def _pairwise_path(x, y, metric):
    pw_matrix = pairwise_distance(x, y, metric=metric)
    path = []
    for i in range(pw_matrix.shape[0]):
        for j in range(pw_matrix.shape[1]):
            if i == j:
                path.append((i, j))
    return path, pw_matrix.trace(), pw_matrix
Example #3
0
 def _3D_distance(X, X2, **params):
     msg = "X and X2 must be np.ndarray, of dim 1, 2, or 3"
     if not isinstance(X, np.ndarray) or not isinstance(X2, np.ndarray):
         raise TypeError(msg)
     if X.ndim > 3 or X2.ndim > 3 or X.ndim < 1 or X2.ndim < 1:
         raise TypeError(msg)
     if X.ndim < 3 and X2.ndim < 3:
         return distance(X, X2, **params)
     else:
         return pairwise_distance(X, X2, metric=distance, **params)
def _validate_pairwise_result(
    x: np.ndarray,
    y: np.ndarray,
    metric_str: str,
    distance_factory: Callable,
    distance_function: Callable,
    distance_numba_class: NumbaDistance,
    kwargs_dict: dict = None,
):
    """Validate the pairwise distance gives desired result.

    Parameters
    ----------
    x: np.ndarray (1d, 2d or 3d array)
        First timeseries.
    y: np.ndarray (1d, 2d or 3d array)
        Second timeseries.
    metric_str: str
        Metric string name.
    distance_factory: Callable
        Distance factory callable
    distance_function: Callable
        Distance function callable
    distance_numba_class: Callable
        NumbaDistance class
    kwargs_dict: dict
        Extra kwargs
    """
    if kwargs_dict is None:
        kwargs_dict = {}
    metric_str_result = pairwise_distance(x,
                                          y,
                                          metric=metric_str,
                                          **kwargs_dict)

    expected_size = (len(x), len(y))
    if x.ndim <= 1:
        expected_size = (1, 1)

    assert metric_str_result.shape == expected_size, (
        f'The result for a pairwise using the string: {metric_str} as the "metric" '
        f"parameter should be of the shape {expected_size}. "
        f"Instead the result was of shape {metric_str_result.shape}.")

    assert isinstance(metric_str_result, np.ndarray), (
        f"The result for a pairwise using the string: {metric_str} as the "
        f'"metric" parameter should return a 2d numpy array. The return type provided '
        f"is of type {type(metric_str_result)}")

    metric_factory_result = pairwise_distance(x,
                                              y,
                                              metric=distance_factory,
                                              **kwargs_dict)
    metric_numba_class_result = pairwise_distance(x,
                                                  y,
                                                  metric=distance_numba_class,
                                                  **kwargs_dict)
    metric_dist_func_result = pairwise_distance(x,
                                                y,
                                                metric=distance_function,
                                                **kwargs_dict)

    assert isinstance(metric_factory_result, np.ndarray), (
        f"The result for a pairwise using the distance factory: "
        f'{distance_factory} as the "metric" parameter should return a 2d numpy '
        f"The return type provided is of type {type(metric_factory_result)}")

    assert isinstance(metric_numba_class_result, np.ndarray), (
        f"The result for a pairwise using the NumbaDistance class: "
        f'{distance_numba_class} as the "metric" parameter should return a 2d '
        f"numpy The return type provided is of type "
        f"{type(metric_numba_class_result)}")

    assert np.array_equal(metric_str_result, metric_factory_result), (
        f'The result of using the string: {metric_str} as the "metric" parameter'
        f"result does not equal the result of using the distance factory: "
        f'{distance_factory} as the "metric" parameter. These results should be '
        f"equal. The result of the pairwise calculation where metric={metric_str} "
        f"is {distance_factory}. The result of the distance calculation where "
        f"metric={distance_factory} is {metric_factory_result}.")

    assert np.array_equal(metric_str_result, metric_numba_class_result), (
        f'The result of using the string: {metric_str} as the "metric" parameter'
        f"result does not equal the result of using the NumbaDistance class: "
        f'{distance_numba_class} as the "metric" parameter. These results should '
        f"be equal."
        f"The result of the pairwise calculation where metric={metric_str} is "
        f"{metric_str_result}. The result of the distance calculation where "
        f"metric={distance_numba_class} is {metric_numba_class_result}.")

    assert np.array_equal(metric_str_result, metric_dist_func_result), (
        f'The result of using the string: {metric_str} as the "metric" parameter'
        f"result does not equal the result of using a NumbaDistance class: "
        f'{distance_function} as the "metric" parameter. These results should be '
        f"equal."
        f"The result of the pairwise calculation where metric={metric_str} is "
        f"{metric_str_result}. The result of the distance calculation where "
        f"metric={distance_function} is {metric_dist_func_result}.")

    metric_str_result_to_self = pairwise_distance(x,
                                                  x,
                                                  metric=metric_str,
                                                  **kwargs_dict)
    if metric_str != "lcss":
        assert metric_str_result_to_self.trace() == 0, (
            f"The pairwise distance when given two of the same timeseries e.g."
            f"pairwise_distance(x, x, ...), diagonal should equal 0."
            f"(np.trace(result)). Instead for the pairwise metric given where "
            f"metric={metric_str} is {metric_str_result_to_self.trace()}")

    assert _check_symmetric(metric_str_result_to_self) is True, (
        f"The pairwise distance when given two of the same timeseries e.g."
        f"pairwise_distance(x, x, ...), should produce a symmetric matrix. This"
        f"means the left of the center diagonal should equal the right of the "
        f"center diagonal. This criteria is not met for the pairwise metric "
        f"{metric_str}")

    _test_pw_equal_single_dists(x, y, distance_function, metric_str)
Example #5
0
def _plot_path(
    x: np.ndarray,
    y: np.ndarray,
    metric: str,
    dist_kwargs: dict = None,
    title: str = "",
    plot_over_pw: bool = False,
):
    if dist_kwargs is None:
        dist_kwargs = {}
    try:
        path, dist, cost_matrix = distance_alignment_path(
            x, y, metric=metric, return_cost_matrix=True, **dist_kwargs)

        if metric == "lcss":
            _path = []
            for tup in path:
                _path.append(tuple(x + 1 for x in tup))
            path = _path

        if plot_over_pw is True:
            if metric == "lcss":
                pw = pairwise_distance(x, y, metric="euclidean")
                cost_matrix = np.zeros_like(cost_matrix)
                cost_matrix[1:, 1:] = pw
            else:
                pw = pairwise_distance(x, y, metric="squared")
                cost_matrix = pw
    except NotImplementedError:
        path, dist, cost_matrix = _pairwise_path(x, y, metric)

    plt.figure(1, figsize=(8, 8))
    x_size = x.shape[0]

    # definitions for the axes
    left, bottom = 0.01, 0.1
    w_ts = h_ts = 0.2
    left_h = left + w_ts + 0.02
    width = height = 0.65
    bottom_h = bottom + height + 0.02

    rect_s_y = [left, bottom, w_ts, height]
    rect_gram = [left_h, bottom, width, height]
    rect_s_x = [left_h, bottom_h, width, h_ts]

    ax_gram = plt.axes(rect_gram)
    ax_s_x = plt.axes(rect_s_x)
    ax_s_y = plt.axes(rect_s_y)

    _path_mask(cost_matrix, path, ax_gram)
    ax_gram.axis("off")
    ax_gram.autoscale(False)
    # ax_gram.plot([j for (i, j) in path], [i for (i, j) in path], "w-",
    #              linewidth=3.)

    ax_s_x.plot(np.arange(x_size), y, "b-", linewidth=3.0, color="#818587")
    ax_s_x.axis("off")
    ax_s_x.set_xlim((0, x_size - 1))

    ax_s_y.plot(-x, np.arange(x_size), "b-", linewidth=3.0, color="#818587")
    ax_s_y.axis("off")
    ax_s_y.set_ylim((0, x_size - 1))

    ax_s_x.set_title(title, size=10)

    return plt