Vectorisation d'un code Matlab

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je découvre Matlab car je pourrais en avoir besoin pour mon stage de cet été. Je me familiarise pour le moment avec le langage. J’ai donc écrit le petit script suivant :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
clear;

size = 1:100;

for i=size  % Calling size times our function
    y(i) = count_step(15);
end

plot(y);
hold on;
plot(size, ones(length(size), 1) * mean(y), 'linewidth', 1.5);
plot(size, ones(length(size), 1) * median(y), 'linewidth', 1.5);
legend('steps', 'mean', 'median');

% Count the number of steps needed to reach the max_distance
function step = count_step(max_distance)
    step = 0;
    distance = 0;

    while distance < max_distance
        n = randi([0 1], 1, 1);  % Return 1 or 0
        if n == 1
            distance = distance + 2;
        else
            distance = distance - 1;
        end

        step = step + 1;
    end
end

Je vois un peu partout sur internet qu’il faut éviter au maximum les boucles dans Matlab et essayer de vectoriser le code au maximum. Qu’est-ce que ça signifie ? Je viens de C++ et de Python ou on utilise des boucles.

Merci pour votre aide !

Salut,

En matlab, la structure de donnée fondamentale est la matrice de nombre. Matlab est (relativement…) rapide pour multiplier des matrices entre elles, les ajouter, etc. Tu as donc intérêt à écrire au maximum ton code en tant qu’opérations entre des matrices plutôt que d’écrire tes boucles à la main.

Par exemple, mettons que tu veux créer une matrice qui contient la table de multiplication de 0 à 10. Une façon de faire serait de créer une matrice de la bonne taille, puis d’écrire deux boucles for imbriquées et d’assigner les valeurs une par une M(i,j) = i*j. Une autre façon plus maline est de voir que la table de multiplication est le produit externe entre des vecteurs qui contiennent les entiers de 0 à 10, et écrire ça par exemple v=0:10 ; M = v' * v.

Un autre exemple serait si tu as deux vecteurs de donnés, mettons des masses et les vitesses associés, et que tu veux calculer l’énergie cinétique de chaque objet. Une façon de faire est de créer un vecteur de la bonne dimension, faire une boucle et attribuer E(i) = 0.5 * m(i) * v(i)^2. Une autre façon est d’écrire directement E = 0.5 * m .* v.^2 (les opérateurs .X font l’opération X élément par élément). La méthode vectorisée, en plus d’être plus lisible, sera toujours plus rapide que la boucle explicite équivalente. La raison pour ça, c’est que les opérateurs matriciels sont implémentés en langage machine alors que ta boucle va passer par l’interpréteur Matlab.

EDIT : note que si tu fais du calcul en Python, tu as intérêt à utiliser numpy et vectoriser les opérations au maximum entre les tableaux numpy pour les même raisons.

+0 -0

Edit :Grillé par @adri1 !

Salut,

Je ne connais pas trop mathlab, mais en R c’est aussi un conseil qui revient souvent. Normalement ces langages sont capable de manipuler nativement des vecteurs et de réaliser des opérations dessus.

Par exemple en R pour calculer la somme des termes d’un vecteur on peut faire de la façon suivante :

1
2
3
4
#On créer un vecteur
mon_vecteur = c(1, 2, 3, 4)
#On calcul la somme avec la fonction sum 
somme = sum(mon_vecteur)

La fonctionne sum est capable de travailler directement avec le vecteur et de faire "automatiquement" la somme de ses composantes. Pas besoin d’écrire une boucle manuellement pour le faire. Outre le fait qu’une boucle sera plus longue à écrire et moins lisible, les performances seront aussi moins bonnes. En effet les vecteurs/matrices dans ces langages sont des types de données de base, donc leur manipulation est souvent très optimisée. D’où la recommandation d’écrire du code "vectoriel" et non des boucles.

+0 -0
Banni

Salut,

Un peu comme en programmation fonctionnelle on utiliserait des « map » et « filter » au lieu de faire des boucles (mais en moins souple et avec des syntaxes plus spécialisées, et avec l’argument de la performance en plus).

Pour ton exemple, je ne sais pas comment le « vectoriser » car il n’y a pas de limite sur le nombre de pas effectués. J’aimerais savoir si c’est possible, le langage me semble pas assez souple pour ça (même en Python-scipy je ne sais pas comment faire… il faudrait pouvoir manipuler des flux au lieu de vecteurs de tailles fixes). Pour donner l’idée, ce serait quelque chose dans le genre suivant.

1
2
3
4
5
function step = count_step(max_distance)
  steps = randi([0 1], 1, 1000) * 3 - 1;
  pos = [0 cumsum(steps)];
  step = find(pos >= max_distance)(1) - 1;
end

edit D’ailleurs pour faire count_step(2000), en remplaçant le 1000 dans mon code par 10000, ça se voit à l’œil nu que la version que j’ai donnée est plus performante (alors qu’elle fait plein de trucs inutiles).

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte