как векторизовать операцию XOR в Matlab - PullRequest
0 голосов
/ 01 февраля 2012

Я запустил следующий код в Profiler в Matlab, и для меня очень важно векторизовать этот код, так как я считаю, что это ненужный цикл for.

У меня есть 2 матрицы G и source_data. каждый столбец в G будет определять строки, которые мне нужно выбрать из source_data и совместно их записать.

Я создаю G и source_data, используя следующий фрагмент кода

for i=1:10
 source_data(i,:)=rand(1,20)<.8;
end 

for i=1:15
 G(:,i)=rand(10,1)<.9;
end

Я выполняю операцию xor, используя цикл for ниже:

z=1;
while(i<=15) 
for j=1:10
    if(G(j,i)==1)
       intersum(z+1,:)=xor(intersum(z,:), source_data(j,:));
        z=z+1;
    end
end
C(i,:)=intersum(z,:);
i=i+1;
end

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

Спасибо

Бхавья

1 Ответ

1 голос
/ 01 февраля 2012

Предполагая, что:

  • i начинается с 1
  • intersum начинается с нуля

Вот векторизованная форма вашего кода, который производит точно такой жерезультат как ваш оригинал:

function C = version_a()
  source_data = rand(10,20)<.8;
  G = rand(10,15)<.9;

  intersum = zeros(1, size(source_data,2));
  z = 1;
  i = 1;
  while i <= 15
    for j=1:10
        if(G(j,i)==1)
           intersum(z+1,:)=xor(intersum(z,:), source_data(j,:));
            z=z+1;
        end
    end

    C(i,:)=intersum(z,:);
    i=i+1;
  end
  ret = C;
end

function C = version_b()
  source_data = rand(10,20)<.8; % Can initialize in a single call
  G = rand(10,15)<.9;           % Same here
  C = zeros(size(G,2),size(source_data,2));

  C(1,:) = mod(sum(source_data(G(:,1),:)),2);
  for i = 2:15
    C(i,:) = mod(C(i-1,:) + sum(source_data(G(:,i),:)),2);
  end
end

Чтобы проверить синхронизацию обеих версий, я использовал эту тестовую функцию:

function ret = xor_test()
  ret = 0;

  seed = 123456789;
  laps = 10000;

  tic
  for i = 1:laps
    RandStream.getDefaultStream.reset(seed);
    a = version_a();
  end
  toc

  tic
  for i = 1:laps
    RandStream.getDefaultStream.reset(seed);
    b = version_b();
  end
  toc

  ret = ret + sum(sum(b ~= a));
end

И я получил следующие тайминги на моей машине:

Elapsed time is 13.537738 seconds.
Elapsed time is 2.302747 seconds.
ans =
     0

Теперь о том, почему я изменил его таким образом ...

Операция xor над массивом из logical s в значительной степени проверяет четность суммы (обрабатывает true значениякак 1).Furhtermore, intersum используется в качестве аккумулятора, поэтому есть чьи значения, которые в конечном итоге заканчиваются на C, поэтому мы пропускаем его полностью.Взятие строк, для которых G(j,i) равно 1, может быть выполнено с помощью логического индексирования .

И, наконец, даже если вам не нравится эта предложенная версия, я рекомендую предварительно выделить вашC и intersum векторов (если вы этого еще не сделали).Это имело большое значение для меня в прошлом.

...