¿La indexación de vectores en MATLAB es ineficiente?

Fondo

Mi pregunta está motivada por observaciones simples, que socavan un poco las creencias / suposiciones que a menudo sostienen / hacen los usuarios experimentados de MATLAB:

MATLAB está muy bien optimizado cuando se trata de las funciones integradas y las características fundamentales del lenguaje, como la indexación de vectores y matrices.Los bucles en MATLAB son lentos (a pesar del JIT) y, por lo general, deben evitarse si el algoritmo se puede expresar de forma nativa "vectorizada".

El resultado final: la funcionalidad básica de MATLAB es eficiente y tratar de superarla utilizando el código MATLAB es difícil, si no imposible.

Investigando el rendimiento de la indexación vectorial

Los códigos de ejemplo que se muestran a continuación son tan fundamentales como son: Asigno un valor escalar a todas las entradas de vectores. Primero, asigno un vector vacíox:

tic; x = zeros(1e8,1); toc
Elapsed time is 0.260525 seconds.

Teniendox Me gustaría establecer todas sus entradas al mismo valor. En la práctica, lo harías de manera diferente, por ejemplo,x = value*ones(1e8,1), pero el punto aquí es investigar el rendimiento de la indexación vectorial. La forma más sencilla es escribir:

tic; x(:) = 1; toc
Elapsed time is 0.094316 seconds.

Llamémoslo método 1 (del valor asignado ax). Parece ser muy rápido (más rápido al menos que la asignación de memoria). Como lo único que hago aquí es operar en la memoria, puedo estimar la eficiencia de este código calculando los resultados obtenidos.ancho de banda efectivo de la memoria y comparándolo con elancho de banda de memoria de hardware de mi computadora:

eff_bandwidth = numel(x) * 8 bytes per double * 2 / time

En lo anterior, multiplico por2 porque a menos que se use la transmisión por secuencias de SSE, la configuración de valores en la memoria requiere que el vector se lea y se escriba en la memoria. En el ejemplo anterior:

eff_bandwidth(1) = 1e8*8*2/0.094316 = 17 Gb/s

Ancho de banda de memoria de STREAM Mi computadora tiene alrededor de 17.9 Gb / s, por lo que, en este caso, ¡MATLAB ofrece un rendimiento casi máximo! Hasta ahora tan bueno.

Método 1 es adecuado si desea establecertodos Elementos vectoriales a algún valor. Pero si quieres acceder a elementos cadastep entradas, necesitas sustituir el: con por ejemplo,1:step:end. A continuación se muestra una comparación directa de velocidad con el método 1:

tic; x(1:end) = 2; toc
Elapsed time is 0.496476 seconds.

Si bien no esperaría que funcionara de manera diferente, el método 2 es claramente un gran problema: la desaceleración del factor 5 sin ninguna razón. Mi sospecha es que en este caso MATLAB asigna explícitamente el vector de índice (1:end). Esto se confirma de alguna manera usando un tamaño de vector explícito en lugar deend:

tic; x(1:1e8) = 3; toc
Elapsed time is 0.482083 seconds.

Los métodos 2 y 3 son igualmente malos.

Otra posibilidad es crear explícitamente un vector índice.id y usarlo para indexarx. Esto le da las capacidades de indexación más flexibles. En nuestro caso:

tic;
id = 1:1e8; % colon(1,1e8);
x(id) = 4;
toc
Elapsed time is 1.208419 seconds.

Ahora eso es realmente algo - ¡12 veces más lento en comparación con el método 1! Entiendo que debería funcionar peor que el método 1 debido a la memoria adicional utilizada paraid, pero ¿por qué es mucho peor que los métodos 2 y 3?

Intentemos probar los bucles, por desesperado que parezca.

tic;
for i=1:numel(x)
    x(i) = 5;
end
toc
Elapsed time is 0.788944 seconds.

Una gran sorpresa - un bucle vence a unvectorized método 4, pero aún es más lento que los métodos 1, 2 y 3. Resulta que, en este caso particular, puedes hacerlo mejor:

tic;
for i=1:1e8
    x(i) = 6;
end
toc
Elapsed time is 0.321246 seconds.

Y ese es probablemente el resultado más extraño de este estudio:un bucle MATLAB escrito supera significativamente la indexación de vectores nativos. Eso ciertamente no debería ser así. Tenga en cuenta que el bucle JIT'ed sigue siendo 3 veces más lento que el pico teórico casi obtenido por el método 1. Por lo tanto, todavía hay mucho margen de mejora. Es simplemente sorprendente (una palabra más fuerte sería más adecuada) que la indexación "vectorizada" habitual (1:end) es aún más lento.

Preguntas

Es simple indexación en MATLAB.muy ineficiente (los métodos 2, 3 y 4 son más lentos que el método 1), o me perdí algo?por qué es el método 4(mucho) más lento que los métodos 2 y 3?¿Por qué usar1e8 en lugar denumel(x) ¿Como un bucle de límite acelera el código por factor 2?

Editar Después de leer el comentario de Jonas, aquí hay otra forma de hacerlo usando índices lógicos:

tic;
id = logical(ones(1, 1e8));
x(id) = 7;
toc
Elapsed time is 0.613363 seconds.

Mucho mejor que el método 4.

Por conveniencia:

function test

tic; x = zeros(1,1e8); toc

tic; x(:) = 1; toc
tic; x(1:end) = 2; toc
tic; x(1:1e8) = 3; toc

tic;
id = 1:1e8; % colon(1,1e8);
x(id) = 4;
toc

tic;
for i=1:numel(x)
    x(i) = 5;
end
toc

tic;
for i=1:1e8
    x(i) = 6;
end
toc

end

Respuestas a la pregunta(2)

Su respuesta a la pregunta