Удовольствие в зависимости от порядка подпрограмм и значений в аккумуляторе

В accumarray() первое примечание о «подписках», впервые появившееся в в R14sp3 документах MATLAB говорится:

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

Мне непонятно, что считать отсортированным. Предполагать:

subs = [1 1
        2 1
        1 2
        2 2];
  1. должен subs быть отсортирован в смысле issorted(subs,'rows'), или ...
  2. в линейном индексировании смысл, т.е. issorted(sub2ind([2 2],subs(:,1), subs(:,2)))

Хочу положиться на:

accumarray(subs,val,[], @(x) x(end))

Если бы кто-то также мог предоставить примеры / тесты из более старых выпусков (для проверки обратной совместимости), где, например, 1) ложно, а 2) верно, это было бы здорово.

PS. Меня в основном не интересуют альтернативы accumarray, если они не очень краткие и не используют те же subs и val.


person Oleg    schedule 08.07.2013    source источник


Ответы (1)


Хорошо, я провел несколько тестов и думаю, что "отсортировано" в цитате означает в линейном индексировании смысл. (Я использую R2013a, если это важно)

Чтобы понять, как accumarray вызывает указанную функцию, я воспользуюсь приемом группировки значений в подвал, указав fun = @(x) {x} в качестве применяемой функции.

1) 1D индексы

Сначала давайте создадим некоторые индексы и значения

N = 10; sz = 4;
subs = randi([1 sz], [N 1]);
vals = (1:N)'*100;

Теперь мы вызываем ACCUMARRAY для несортированных индексов (несколько раз)

C = cell(5,1);
for i=1:5
    C{i} = accumarray(subs, vals, [], @(x){x});
end

Порядок значений, передаваемых в функцию, произвольный, но все же согласованный для нескольких запусков:

>> assert(isequal(C{:}))
>> celldisp(C{1})
ans{1} =
   800
   900
   700
ans{2} =
   300
ans{3} =
        1000
         200
         100
ans{4} =
   400
   600
   500

Вот почему документация предупреждает вас, что fun не должен зависеть от порядка передаваемых ему значений.

Теперь, если предварительно отсортировать индексы:

[~,ord] = sort(subs);
C = cell(5,1);
for i=1:5
    C{i} = accumarray(subs(ord), vals(ord), [], @(x){x});
end
assert(isequal(C{:}))
celldisp(C{1})

мы увидим, что значения передаются в отсортированную функцию:

ans{1} =
   700
   800
   900
ans{2} =
   300
ans{3} =
         100
         200
        1000
ans{4} =
   400
   500
   600

2) 2D индексы

Я пробовал то же самое в случае индексов 2D-индекса. Сначала мы начнем со случайных данных:

%# some 2d subscripts and corresponding values
N = 10; sz = 2;
subs = randi([1 sz], [N 2]);
vals = (1:N)*100;
  • Вот случай с несортированными индексами:

    C = cell(5,1);
    for i=1:5
        C{i} = accumarray(subs, vals, [], @(x){x});
    end
    assert(isequal(C{:}))
    celldisp(C{1})
    
  • Вот когда я попробовал "сортировку по строкам":

    [~,ord] = sortrows(subs, [1 2]);
    C = cell(5,1);
    for i=1:5
        C{i} = accumarray(subs(ord,:), vals(ord), [], @(x){x});
    end
    assert(isequal(C{:}))
    celldisp(C{1})
    
  • И, наконец, вот когда мы сортируем по "линейному индексу":

    [~,ord] = sort(sub2ind([sz sz], subs(:,1), subs(:,2)));
    C = cell(5,1);
    for i=1:5
        C{i} = accumarray(subs(ord,:), vals(ord), [], @(x){x});
    end
    assert(isequal(C{:}))
    celldisp(C{1})
    

Я опущу длинный вывод и сообщу, что только в последнем случае, когда значения были переданы в функцию order. Итак, я прихожу к выводу, что «отсортированные» критерии основаны на линейных показателях.

ans{1,1} =
     []
ans{2,1} =
   200
   600
   700
ans{1,2} =
         100
         300
         400
         500
        1000
ans{2,2} =
   800
   900

Бонус:

Вместо этого попробуйте использовать следующую функцию:

function out = fun(x)
    out = {x};
    disp('[')
    disp(x)
    disp(']')
end

вы увидите, что функция вызывается непредсказуемым образом, даже с некоторым дублированием! Возможно, вам придется увеличить размер данных, чтобы увидеть такое поведение ...


Что касается обратной совместимости, документация упоминает это примечание полностью назад в MATLAB R14sp3, но не R14sp2 . Учитывая тот факт, что это было задокументировано с 2005, я бы сказал, что можно с уверенностью полагаться по этой функции (я сомневаюсь, что кто-то, использующий такие старые версии, ожидает, что новый код все равно будет работать!)

person Amro    schedule 08.07.2013
comment
+ 1 Отличные новости для меня! Хотя мне бы очень хотелось узнать, сможет ли кто-нибудь запустить ваш набор тестов на более старых версиях, чтобы проверить обратную совместимость (не могли бы вы сделать «линейную индексацию» в первом предложении жирным шрифтом?) - person Oleg; 09.07.2013
comment
Подпрограммы в смысле линейной индексации также на R14sp3. Протестировано с: N = 1000; sz = 2; subs = [ceil(N/10.*rand(N,1)) ceil(sz.*rand(N,1))]; vals = (1:N)*100; [ord,ord] = sort(sub2ind([N sz], subs(:,1), subs(:,2))); C = cell(5,1); for i=1:5 C{i} = accumarray(subs(ord,:), vals(ord), [], @(x){x}); end isequal(C{:}) all(cellfun(@issorted,C{1})) - person Oleg; 10.07.2013
comment
Отлично. Вы должны действительно позаботиться об обратной совместимости! Если бы я был на вашем месте, я бы проверил тестовую версию MATLAB в своем коде и выдал бы ошибку, если он для меня слишком старый тест :) - person Amro; 10.07.2013