Автоматически уменьшать кусочно-функциональные компоненты - Pyomo - PullRequest
0 голосов
/ 16 февраля 2019

В pyomo у меня есть кусочно-линейное ограничение, определенное через pyomo.environ.Piecewise.Я продолжаю получать предупреждение в соответствии с

Piecewise component '<component name>' has detected slopes of consecutive piecewise segments to be within <tolerance> of one another. Refer to the Piecewise help documentation for information on how to disable this warning.

Я знаю, что мог бы увеличить терпимость и избавиться от предупреждения, но мне интересно, есть ли общий подход (через Pyomo или numpy) куменьшите количество «сегментов», если два последовательных уклона ниже заданного допуска.

Я, очевидно, мог бы реализовать это сам, но я бы хотел избежать повторного изобретения колеса.

1 Ответ

0 голосов
/ 17 февраля 2019

Хорошо, это то, что я придумал.Определенно не оптимизирован для производительности, но мой случай зависит от нескольких моментов.Также не хватает дополнительных проверок на входах (например, x сортируется и уникален).

def reduce_piecewise(x, y, abs_tol):
    """
    Remove unnecessary points from piece-wise curve.

    Points are remove if the slopes of consecutive segments
    differ by less than `abs_tol`.

    x points must be sorted and unique.
    Consecutive y points can be the same though!

    Parameters
    ----------
    x : List[float]
        Points along x-axis.
    y : List[float]
    abs_tol : float
        Tolerance between consecutive segments.

    Returns
    -------
    (np.array, np.array)
        x and y points - reduced.
    """
    if not len(x) == len(y):
        raise ValueError("x and y must have same shape")

    x_reduced = [x[0]]
    y_reduced = [y[0]]

    for i in range(1, len(x) - 1):
        left_slope  = (y[i] - y_reduced[-1])/(x[i] - x_reduced[-1])
        right_slope = (y[i+1] - y[i])/(x[i+1] - x[i])
        if abs(right_slope - left_slope) > abs_tol:
            x_reduced.append(x[i])
            y_reduced.append(y[i])

    x_reduced.append(x[-1])
    y_reduced.append(y[-1])

    return np.array(x_reduced), np.array(y_reduced)

И вот несколько примеров:

>>> x = np.array([0, 1, 2, 3])
>>> y = np.array([0, 1, 2, 3])
>>> reduce_piecewise(x, y, 0.01)
(array([0, 3]), array([0, 3]))
>>> x = np.array([0, 1, 2, 3, 4, 5])
>>> y = np.array([0, 2, -1, 3, 4.001, 5]) # 4.001 should be removed
>>> reduce_piecewise(x, y, 0.01)
(array([0, 1, 2, 3, 5]), array([ 0.,  2., -1.,  3.,  5.]))
...