Vettori e Matrici

Octave salva normalmente i dati in strutture orientate a rappresentare matrici . Anche quando una variabile contiene uno scalare si tratta solo di un caso particolare, anche se poi Octave in un espressione tratterà questa struttura diversamente da una matrice vera e propria.

Creazione di una matrice

Una matrice può essere scritta da linea di comando digitandola riga per riga separando ogni riga con il carattere ";" (punto-e-virgola)

>> matrice=[1 2 -3; -4 5 -6; 7 -8 9]
matrice =

   1   2  -3
  -4   5  -6
   7  -8   9
Le righe di una matrice devono avere un numero consistente di elementi. Se la prima riga è stata definita avere N elementi, così dovranno essere anche tutte le altre righe, mentre il numero di colonne non è vincolato al numero di righe. Se una matrice ha un numero di righe pari al numero di colonne è detta quadrata .

Operazioni tra matrici

Addizione

Prima di tutto osserviamo qual'è l'effetto della moltiplicazione di uno scalare per una matrice

>> A=[1 -5.4 3; 2 2.8 9; 12 5 3];
>> A*2
ans =

    2.0000  -10.8000    6.0000
    4.0000    5.6000   18.0000
   24.0000   10.0000    6.0000

>> -A
ans =

   -1.0000    5.4000   -3.0000
   -2.0000   -2.8000   -9.0000
  -12.0000   -5.0000   -3.0000
La forma -A ha lo stesso effetto della moltiplicazione -1*A , quindi ogni considerazione sulla somma vale in senso relativo inglobando in essa anche la sottrazione.

Vediamo l'effetto degli operatori aritmetici in operazioni tra matrici. Calcoliamo la somma di 2 matrici

>> B=[2 6 8.3; -3 4 5.6; 1 1.2 -2.5];
>> A+B
ans =

    3.00000    0.60000   11.30000
   -1.00000    6.80000   14.60000
   13.00000    6.20000    0.50000
Riconoscete la logica usata nella definizione dell'operazione di somma?
Cosa accadrebbe se le matrici fossero di diversa dimensione?

Composizione di matrici da matrici più piccole

La sintassi del linguaggio di Octave/Matlab permette di costruire matrici componendo tra loro matrici di dimensioni opportune. Un caso elementare è quello di composizione di un vettore aggiungendo ad un vettore dato nuovi scalari

% il primo comando crea un uno scalare che può
% essere visto come una matrice 1x1

v = 1;

% uno scalare viene aggiunto così

v = [v 2]
v =

   1   2

v = [v 3]
v =

   1   2   3

Il procedimento funziona anche per costruire una colonna, ma in questo caso si deve usare il carattere ; (punto e virgola) per forzare l'incolonnamento. Nel caso di matrici aventi dimensioni maggiori di 1 su entrambi gli indici si usano le stesse regole:

  • Il carattere di spazio permette la composizione lungo l'indice di colonna (la matrice che viene aggiunta deve avere lo stesso numero di righe)
  • Il carattere di ; compone lungo l'indice di riga (la matrice che viene concatenata deve avere lo stesso numero di righe)
a = [1 2; 3 4]
a =

   1   2
   3   4

b = [11 12 13; 21 22 23]
b =

   11   12   13
   21   22   23

m = [a b]
m =

    1    2   11   12   13
    3    4   21   22   23

c = [5 6; 7 8]
c =

   5   6
   7   8

d = [31 32 33; 41 42 43]
d =

   31   32   33
   41   42   43

m = [m; c d]
m =

    1    2   11   12   13
    3    4   21   22   23
    5    6   31   32   33
    7    8   41   42   43

Moltiplicazione

L'operatore "*" quando applicato a 2 matrici esegue il prodotto righe per colonne

>> A*B
ans =

    21.2000   -12.0000   -29.4400
     4.6000    34.0000     9.7800
    12.0000    95.6000   120.1000

Mentre ha un interpretazione più intuitiva l'operatore di moltiplicazione elemento per elemento

>> A.*B
ans =

    2.0000  -32.4000   24.9000
   -6.0000   11.2000   50.4000
   12.0000    6.0000   -7.5000

L'operatore .* può essere usato per eseguire il masking di un'immagine (selezione di una porzione di un'immagine). Esempio: della matrice A selezioniamo gli elementi della diagonale

>> diagonale=diag(ones(1,3))
diagonale =

Diagonal Matrix

   1   0   0
   0   1   0
   0   0   1

>> A.*diagonale
ans =

   1.00000  -0.00000   0.00000
   0.00000   2.80000   0.00000
   0.00000   0.00000   3.00000

Una caratteristica importante di Octave è quella di generare matrici logiche composte da elementi booleani che sono 1 (vero) dove una condizione è verificata e altrimenti zero (falso) dove non lo è. Esempio: della matrice risultato del prodotto righe per colonne A*B possiamo ottenere la maschera (mask) di elementi che sono compresi tra 10 e 30

>> P=(A*B)
P =

    21.2000   -12.0000   -29.4400
     4.6000    34.0000     9.7800
    12.0000    95.6000   120.1000

>> P > 10
ans =

   1   0   0
   0   1   0
   1   1   1

>> P < 30
ans =

   1   1   1
   1   0   1
   1   0   0

>> (P > 10) .* (P < 30)
ans =

   1   0   0
   0   0   0
   1   0   0

Dove la moltiplicazione realizza l'operatore booleano AND

Sequenze e Vettori

I vettori sono matrici particolari che di dimensione Nx1 o 1xN. E' semplice costruire vettori basati su sequenze regolari con passo costante. La forma [start:increment:end] definisce una sequenza da start fino a end con incremento increment . Non è necessario che questi siano numeri interi, l'unico vincolo è che l'incremento sia positivo se end > start o negativo se vale la condizione opposta.

>> [0.5:sqrt(2):9.3]
ans =

   0.50000   1.91421   3.32843   4.74264   6.15685   7.57107   8.98528

E' la sequenza di valori compresi tra 0.5 e 9.3 con incremento sqrt(2) (radice quadrata di 2). Notare che l'elemento finale non è detto sia parte della sequenza generata perchè l'incremento è arbitrario.

Altra funzione è linspace che genera una sequenza di N punti compresi tra due estremi con la garanzia che gli estremi siano il primo e l'ultimo elemento del vettore

>> sequenza=linspace(0.5,9.3,10)
sequenza =

   0.50000   1.47778   2.45556   3.43333   4.41111   5.38889   6.36667   7.34444   8.32222   9.30000