2013-06-20 3 views
5

Я хотел бы знать, как можно обработать узкое место в данном фрагменте кода.Эффективный метод поиска элементов в матрице MATLAB

%% Points is an Nx3 matrix having the coordinates of N points where N ~ 10^6 
Z = points(:,3) 
listZ = (Z >= a & Z < b); % Bottleneck 
np = sum(listZ); % For later usage 
slice = points(listZ,:); 

В настоящее время для N ~ 10^6, np ~ 1000 и number of calls to this part of code = 1000, утверждение узкого места занимает около 10 секунд, в общей сложности, который представляет собой большой кусок времени по сравнению с остальной частью моего кода.

Profiling Results

Некоторые больше скриншотов кода образца для только заявления индексации в соответствии с просьбой @EitanT

Profiling for sample code Profiling for sample code

+1

Вы уверены, что это узкое место (можете ли вы показать результаты профилирования)? А что такое 'num_calls'? –

+0

@EitanT Да, я проверил его через профилировщик MATLAB, и это утверждение действительно является узким местом – OrangeRind

+0

@EitanT Я добавил результат профилирования – OrangeRind

ответ

8

Если равенство с одной стороны, не важно, вы можете переформулировать его одностороннюю сравнения и получает на порядок быстрее:

Z = rand(1e6,3); 
a=0.5; b=0.6; 
c=(a+b)/2; 
d=abs(a-b)/2; 
tic 
for k=1:100, 
    listZ1 = (Z >= a & Z < b); % Bottleneck 
end 
toc 

tic 
for k=1:100, 
    listZ2 = (abs(Z-c)<d); 
end 
toc 

isequal(listZ1, listZ2) 

возвращается

Elapsed time is 5.567460 seconds. 
Elapsed time is 0.625646 seconds. 

ans = 

    1 
+1

Ах! Это напоминает мне о том, что я спросил в прошлом (http://stackoverflow.com/questions/12137233/matlab-performance-comparison-slower-than-arithmetic). Действительно, я думаю, что это путь. –

+0

Это хорошо! Хотя я получаю немного меньше, чем на порядок в реальной программе, возможно, из-за сложности остальной части кода, но все же я думаю, что что-то еще можно сделать. – OrangeRind

+2

См. Также принятый ответ на [этот недавний вопрос программирования C] (http://stackoverflow.com/a/17095534/1165522). – horchler

1

Попробуйте сделать что-то вроде этого:

for i = 1:1000 
    x = (a >= 0.5); 
    x = (x < 0.6); 
end 

Я нашел это быстрее:

for i = 1:1000 
    x = (a >= 0.5 & a < 0.6); 
end 

примерно 4 секунды:

Elapsed time is 0.985001 seconds. (first one) 
Elapsed time is 4.888243 seconds. (second one) 

Я думаю, что причина для замедления является поэлементно & операции.

+0

Пожалуйста, внимательно прочитайте вопрос. :) – OrangeRind

+0

Я вижу, что вы имеете в виду сейчас. – KronoS

+0

@OrangeRind см. Обновленный ответ. – KronoS

3

Предполагая наихудшего случая:

  • поэлементно & не является коротким замыканием внутри
  • сравнений являются однопоточными

Вы делаете 2*1e6*1e3 = 2e9 сравнения в ~ 10 секунд , Это ~ 200 миллионов сравнений в секунду (~ 200 MFLOPS).

Учитывая, что вы можете сделать 1.7 GFLops on a single core, это действительно кажется довольно низким.

Вы используете Windows 7? Если да, проверили ли вы свои настройки мощности? Вы находитесь на мобильном процессоре, поэтому я ожидаю, что по умолчанию будет существовать некоторая схема потребления низкой мощности. Это позволяет окнам масштабировать скорость обработки, поэтому ... проверьте это.

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

+0

Приятно отметить, что там есть - но я убедился в плане мощности - и во время вычисления turbo boost также срабатывает, так как он работает с одним потоком. Я проверю пропускную способность моего процессора через geekbench и дам вам знать. – OrangeRind