Matlab: более быстрое нахождение 1D линейных узлов интерполяции и весов для каждого элемента в матрице ND - PullRequest
2 голосов
/ 02 апреля 2020

В проблеме, над которой я сейчас работаю, я вычисляю некоторые значения в матрице x, а затем для каждого элемента в x необходимо найти индекс ближайшего элемента ниже в монотонно возрастающем векторе X а также относительная близость элементов x к первым элементам с обеих сторон. (По сути, это линейная интерполяция без фактической интерполяции.) Я делаю это по-разному, так что я действительно очень заинтересован в том, чтобы это было как можно быстрее.

Я написал функцию locate, которую я Можно вызвать с некоторыми примерами данных:

X = linspace(5, 300, 40)';
x = randi(310, 5, 6, 7);

[ii, weights] = locate(x, X);

Я написал две версии locate. Первый - для экспозиции, а второй - моя лучшая попытка ускорить вычисления. Есть ли у вас какие-либо предложения или альтернативные подходы для дальнейшего повышения производительности?

1. Экспозиция

function [ii, weights] = locate(x, X)
    % LOCATE Locate first node on grid below a given value.
    %
    %   [ii, weights] = locate(x, X) returns the first node in X that is below
    %   each element in x and the relative proximities to the two closest nodes.
    %
    %   X must be a monotonically increasing vector. x is a matrix (of any
    %   order).

    % Preallocate
    ii = ones(size(x));  % Indices of first node below (or 1 if no nodes below)
    weights = zeros([2, size(x)]);  % Relative proximity of the two closest nodes

    % Find indices and compute weights
    for ix = 1:numel(x)
        if x(ix) <= X(1)
            ii(ix) = 1;
            weights(:, ix) = [1; 0];
        elseif x(ix) >= X(end)
            ii(ix) = length(X) - 1;
            weights(:, ix) = [0; 1];
        else
            ii(ix) = find(X <= x(ix), 1, 'last');
            weights(:, ix) = ...
                [X(ii(ix) + 1) - x(ix); x(ix) - X(ii(ix))] / (X(ii(ix) + 1) - X(ii(ix)));
        end
    end
end

2. Лучшая попытка

function [ii, weights] = locate(x, X)
    % LOCATE Locate first node on grid below a given value.
    %
    %   [ii, weights] = locate(x, X) returns the first node in X that is below
    %   each element in x and the relative proximities to the two closest nodes.
    %
    %   X must be a monotonically increasing vector. x is a matrix (of any
    %   order).

    % Preallocate
    ii = ones(size(x));  % Indices of first node below (or 1 if no nodes below)
    weights = zeros([2, size(x)]);  % Relative proximity of the two closest nodes

    % Find indices
    for iX = 1:length(X) - 1
        ii(X(iX) <= x) = iX;
    end

    % Find weights
    below = x <= X(1);
    weights(1, below) = 1;  % All mass on the first node
    weights(2, below) = 0;

    above = x >= X(end);
    weights(1, above) = 0;
    weights(2, above) = 1;  % All mass on the last node

    interior = ~below & ~above;
    xInterior = x(interior)';
    iiInterior = ii(interior);
    XBelow = X(iiInterior)';
    XAbove = X(iiInterior + 1)';
    weights(:, interior) = ...
        [XAbove - xInterior; xInterior - XBelow] ./ (XAbove - XBelow);
end

1 Ответ

1 голос
/ 04 апреля 2020

Оформить заказ на мою polylineinterp функцию в Brain2Me sh toolbox .

https://github.com/fangq/brain2mesh/blob/master/polylineinterp.m

делает это почти точно, за исключением вход polylen похож на разность вашего X.

в общем случае, векторизация этого вида операции должна использовать histc(), как эта строка

https://github.com/fangq/brain2mesh/blob/master/polylineinterp.m#L52

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...