Introduzione a Mathematica

Gianluca Gorni
Università di Udine, Dipartimento di Matematica e Informatica

9. Liste e matrici

Ultima modifica: 6 marzo 2018

Range

Una lista consiste di una o più espressioni (anche nessuna) separati da virgole e racchiusi fra graffe:

{a,b,1,Sqrt[2],x<3}

Il comando Range[n] produce una lista dei primi n interi positivi:

Range[1]

Range[5]

Range[0]

Si può anche dire a Range di cominciare da un numero diverso da 1:

Range[-1,2]

Range[4,7]

Range[2,-1]

Il passo di Range non è necessariamente 1:

Range[2,4,1/2]

Range[2,-1,-1]

Range[1,6,2]

Subdivide[4]

Subdivide[10,5]

Subdivide[1,10,5]

Table

Range produce liste in cui la differenza fra i termini successivi è costante. Se vogliamo una lista in cui i termini seguono una qualsiasi altra legge possiamo usare Table. Per esempio i primi 5 numeri quadrati si possono scrivere così:

Table[n^2,{n,5}]

I primi 8 fattoriali:

Table[n!,{n,8}]

I primi 10 numeri primi:

Table[Prime[n],{n,10}]

Analogamente a Range, possiamo cambiare il valore iniziale e il passo del contatore:

Table[Fibonacci[n],{n,-2,10}]

Table[n^3-n^2,{n,-2,2,1/2}]

Una sintassi diversa per Table è di dare una lista dei valori di n, anche spaziati irregolarmente:

Table[(n^3)-(n^2),{n,{-1,1,5}}]

ListPlot

Data una lista di numeri reali, si può disegnarne il grafico con ListPlot:

a=Table[n(-1)^n,{n,5}]

ListPlot[a]

DiscretePlot[n(-1)^n,{n,5}]

Possiamo vedere congiunti i punti del grafico con l'opzione PlotJoined->True:

ListPlot[a,Joined->True]

Oppure possiamo rendere più grandi i punti con l'opzione PlotStyle->{PointSize[.02]}:

ListPlot[a,PlotStyle->{PointSize[0.02]}]

Un grafico della successione di Fibonacci:

ListPlot[Array[Fibonacci,{6}],PlotStyle->PointSize[0.02]]

Un grafico dei rapporti fra i termini successivi della successione di Fibonacci:

ListPlot[Table[((Fibonacci[n+1])/(Fibonacci[n])),{n,10}],Joined->True,PlotRange->{{0,10},{0,2}},AxesOrigin->{0,0}]

ListPlot[Table[((Fibonacci[n+1])/(Fibonacci[n])),{n,10}],Joined->True,PlotRange->{{0,10},{0,2.1}},AxesOrigin->{0,0},Mesh->All]

Quest'ultimo grafico ha diverse opzioni per aggiustare l'effetto visivo: PlotJoined->True l'abbiamo già vista, PlotRange->{{0,10},{0,2}} dice di mostrare le ascisse da 0 a 10 e le ordinate da 0 a 2, e infine AxesOrigin->{0,0} impone che l'incrocio dei due assi sia nell'origine {0,0} (per default l'incrocio degli assi è deciso caso per caso a seconda del grafico).

Liste di liste; matrici

Una lista di liste è ... una lista di liste:

{{1,2},{3,4}}

Possiamo produrre facilmente una lista di liste con Table:

Table[{n,n^2},{n,5}]

Sono permessi tutti i gradi di annidamento:

Table[{n,{n^2,n^3}},{n,4}]

Una matrice, per Mathematica, è semplicemente una lista di liste in cui tutte le liste al primo livello hanno lo stesso numero di elementi, per esempio

matrice={{1,2},{3,4},{5,6}}

è una matrice, come ci conferma il test MatrixQ:

MatrixQ[matrice]

mentre invece la seguente non è una matrice:

MatrixQ[{{1},{1,2}}]

Possiamo vedere una matrice nella forma tradizionale bidimensionale con MatrixForm:

MatrixForm[matrice]

Attenzione: MatrixForm non va usata per i calcoli, ma solo per il display.

MatrixForm formatta delle liste semplici come matrici a una colonna, o vettori colonna:

MatrixForm[{1,2}]

Le due liste {1,2} e {{1},{2}} sono oggetti ben distinti per Mathematica, ma MatrixForm le formatta in modo identico:

MatrixForm[{{1},{2}}]

{{1},{1,2}}//MatrixForm

Grafico di liste di coppie

ListPlot accetta anche liste di coppie di coordinate, oltre che liste di singoli numeri. In questo caso ogni coppia è interpretata come ascissa-ordinata. Per esempio, ecco dieci punti casuali nel quadrato [0,1]×[0,1]:

pt=Table[RandomReal[{0,1},2],{n,20}]

ListPlot[pt,PlotRange->{{0,1},{0,1}},Frame->True,AspectRatio->Automatic]

Notare l'opzione Frame->True: il grafico viene incorniciato, non si disegnano gli assi, e le tacche delle coordinate sono disegnate sulla cornice. AspectRatio->Automatic dice di usare la stessa scala in orizzontale e verticale, in modo che il quadrato di lato 1 non diventi un rettangolo.

Congiungiamo i punti:

ListPlot[pt,Joined->True,PlotRange->{{0,1},{0,1}},Frame->True,AspectRatio->Automatic]

Estrarre elementi da una lista

Data una lista

a={1,2,3,4,5}

possiamo estrarre il primo e l'ultimo elemento con First e Last:

First[a]

Last[a]

Most tralascia l’ultimo termine, mentre Rest tralascia il primo:

Most[a]

Rest[a]

La lunghezza (numero di elementi) di una lista si ottiene con Length:

Length[a]

Più in generale l'n-esimo elemento di una lista si estrae con [[n]]:

a[[2]]

a[[4]]

Si può anche estrarre l'n-esimo elemento contato dalla fine della lista invece che dall'inizio: basta scrivere [[-n]]:

a[[-1]]

a[[-2]]

a[[1;;3]]

a[[2;;3]]

a[[3;;-1]]

Estrarre elementi da una lista di liste

Un elemento di una lista di liste è individuato dalle sue coordinate: l'elemento di coordinate (Subscript[n, 1]),(Subscript[n, 2]),…,(Subscript[n, k]) si trova così: prendere la lista principale ed estrarne l'elemento (Subscript[n, 1])-esimo; di questo estrarre l'elemento (Subscript[n, 2])-esimo, e così via.
Esempio: consideriamo la lista

a={1,2,{3,4,{c,d}},5}

TreeForm[a]

Le coordinate dell'elemento 4 sono 3,2. Quelle dell'elemento c sono 3,3,1. Quelle di d sono 3,3,2.
Per estrarre l'elemento di coordinate (Subscript[n, 1]),(Subscript[n, 2]),…,(Subscript[n, k]) da una lista a si scrive a[[(Subscript[n, 1]),(Subscript[n, 2]),…,(Subscript[n, k])]]. Esempi:

a[[1]]

a[[3]]

a[[3,1]]

a[[3,3,1]]

a[[3,3,2]]

a[[3,3,-2]]

Output bidimensionale: TableForm

MatrixForm è solo per le matrici. Per le altre liste si può usare TableForm:

TableForm[Range[3]]

TableForm[Table[{n,n^2},{n,4}]]

TableForm[Table[Range[n],{n,5}]]

Si possono assegnare dei titoli per le colonne e le righe con l'opzione TableHeadings:

TableForm[Table[{n,n^2},{n,4}],TableHeadings->{None,{"n","(n^2)"}}]

Per altre opzioni di TableForm selezionare TableForm e poi andare su Help>Find Selected Function (notate l'abbreviazione da tastiera). Oppure cliccare il link preimpostato TableForm. Formattazioni più sofisticate di TableForm si possono ottenere con GridBox, per chi fosse interessato.

Come per MatrixForm, TableForm è da usare solo per mostrare i risultati finali, non per i calcoli.

Input bidimensionale per vettori e matrici

L'interfaccia utente di Mathematica permette di scrivere vettori e matrici direttamente in formato bidimensionale invece che ASCII. Vedere il menu Input>Create Table/Matrix/Palette... Esempio:

mat=({{1, 2, 3}, {4, 5, 6}})

(({{1, 2, 3}, {r4, 5, 6}, {7, 7, 8}}))

({{\[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder]}, {\[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder]}, {\[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder]}, {\[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder]}, {\[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder]}, {\[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder]}, {\[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder], \[Placeholder]}})

Non c'è nemmeno bisogno di decidere in anticipo il numero di righe e colonne. Dal menu Edit>Expression Input>Add Row/Add Column (con le rispettive abbreviazioni da tastiera Ctrl, e Ctrl⌤) si possono aggiungere righe e colonne man mano che si scrive la matrice. Ci si sposta per inserire nel posto successivo con ⇥. Ecco un esempio di matrice coi dati inseriti solo parzialmente:

({{1, 2, 3}, {4, \[Placeholder], \[Placeholder]}})

La creazione di matrici in questo modo non si presta a una facile descrizione per iscritto. Si capisce meglio vedendola fare e provando di persona.

Somme di liste, vettori e matrici, e prodotto con uno scalare

Un vettore per Mathematica è semplicemente una lista. Quando due vettori hanno la stessa lunghezza li possiamo sommare:

Clear[a,b,c,x,y,z,u,v];
u={x,y,z};
v={a,b,c};
u+v

Se cerco di sommare vettori di dimensioni diverse ho errore:

{1,2}+{1,2,3}

Allo stesso modo possiamo sommare due matrici delle stesse dimensioni:

a=Table[{n,n^2},{n,3}];
b=Table[{i-1,i+1},{i,3}];
{MatrixForm[a],MatrixForm[b],MatrixForm[a+b]}

Un singolo numero moltiplicato per una lista produce una lista ottenuta moltiplicando i vari elementi per quel numero:

Clear[a,b,c];
3*{a,b,c}

-{2,3}

π*Range[10]

5{{a,b},{c}}

Evitare TableForm e MatrixForm nei calcoli!

Attenzione: MatrixForm e TableForm possono interferire coi calcoli. Per esempio se sommiamo due matrici che hanno attorno una MatrixForm la somma viene lasciata indicata:

a={{1,2},{3,4}};
b={{3,4},{5,6}};

MatrixForm[a]+MatrixForm[b]

Per avere la somma delle due matrici devo sommarle prima di applicare MatrixForm.

MatrixForm[a+b]

Evitare quindi per esempio di assegnare a una variabile un valore in MatrixForm o TableForm, perché non potremo poi inserirlo nei calcoli:

c=TableForm[{1,2}]

d=TableForm[{3,4}]

c+d

Il problema è che così facendo le variabili non sono semplici liste, ma liste racchiuse dall'involucro TableForm:

?d

È innocuo invece mettere l'assegnazione all'interno di TableForm, perché  in tal caso TableForm agisce solo sulla visualizzazione:

Clear[c];
TableForm[c={1,2}]

mentre la variabile c non contiene traccia di TableForm:

?c

Array

Array è una forma abbreviata di Table. Viene comoda per esempio per costruire vettori o matrici "generiche". Con Array[a,n] si produce la lista {a[1],a[2],...,a[n]}:

Clear[a];
Array[a,4]

Con Array[a,{n,m}] si produce una matrice di n righe e m colonne:

Array[a,{4,2}]

MatrixForm[Array[a,{4,2}]]

Invece di un simbolo generico a ci può essere una funzione, che viene calcolata. Ecco la lista delle prime 9 radici quadrate:

Array[Sqrt,9]

La matrice 4×3 che ha i+j al posto (i,j):

f[x_,y_]:=x+y;
Array[f,{4,3}]//MatrixForm

Subscript

Se si vuole qualcosa di più simile alla notazione matematica tradizionale, usare Subscript e Table:

Clear[a];
Table[Subscript[x,n],{n,2}]

Clear[a];
MatrixForm[Table[Subscript[a,n,m],{n,2},{m,2}]]

Invece dell'ascii Subscript[a,i] possiamo usare l'input bidimensionale tramite tavolozza, oppure da tastiera: (Subscript[a, i]) si può scrivere con aCtrl_iCtrl␣. Analogamente (Subscript[a, i,j]) si fa con aCtrl_i,jCtrl␣:

MatrixForm[Table[(Subscript[a, i,j]),{i,3},{j,2}]]

Agire su tutti gli elementi di una lista

Le funzioni che hanno l’attributo Listable si spalmano automaticamente su tutti gli elementi di una lista:

Attributes[Sqrt]

Sqrt[{1,2,3,4}]

Log[{1,2,E,3,4,(E^2)}]

Se abbiamo una funzione definita da noi e vogliamo spalmarla su una lista possiamo usare Map:

f[x_]:=(x^2)-2x+1;
Map[f,{1,2,3,4}]

Per Map si usa spesso la notazione infissa /@:

g/@{1,2,3}

In certe situazioni non si vuole “avvolgere” una funzione f attorno agli elementi di una lista, ma “sostituire la testa” degli elementi con la nuova f. Per esempio, dalla lista di coppie

{{1,2},{3,4},{4,5}}

cioè, internamente,

{List[1,2],List[3,4],List[4,5]}

vorremmo ottenere la lista delle potenze:

{Power[1,2],Power[3,4],Power[4,5]}

Questo lavoro lo fa Apply a livello 1:

Apply[Power,{{1,2},{3,4},{4,5}},1]

Power@@@{{1,2},{3,4},{4,5}}

Esercizi

Cosa succede se si fa TableForm di una lista di liste di liste? Provare per esempio con TableForm[{{1,{{2,3},{4,5}}},{6,7}}].

Fare una tabella in cui nella prima colonna ci sia il binomio (x^n)-1 e nella seconda la sua fattorizzazione, per n=1,…,10.

Fare una lista dei valori di n!(e^n)/(n^n) per n=1,…,20, e disegnarne un grafico. Provare lo stile con punti isolati, con linea spezzata e poi sovrapporre i due.

Consideriamo la funzione f[x_]=4x(1-x) e la successione (Subscript[a, 0])=0.3, (Subscript[a, n_]):=f[(Subscript[a, n-1])].  Disegnare un grafico della successione di punti ((Subscript[a, n]),(Subscript[a, n+1])) per n=1,…,100. I punti si raccolgono su un grafico. Di quale funzione? Cosa succede poi con l'opzione PlotJoined->True? Parrebbe che ci sia una regione in cui le linee si incrociano, e un'altra in cui non si incrociano, e che il confine sia una curva. Interessante, non trovate?

Definire un comando mat[n_] che una volta inserito un intero n (non il simbolo n) produca la matrice (({{1, 1/2, 1/3, ⋯, 1/n}, {2, 2/2, 2/3, …, 2/n}, {⋮, ⋮, ⋮, ⋱, ⋮}, {n, n/2, n/3, ⋯, n/n}})).

A un vettore o  a una matrice del tipo {a[1],a[2]} o  (({{(Subscript[a, 1,1]), (Subscript[a, 1,2])}, {(Subscript[a, 2,1]), (Subscript[a, 2,2])}})) non si può assegnare il nome a stesso. Per esempio il comando a=Array[a,2] genera un ciclo senza fine (provare!).
Il motivo è questo: quando Mathematica legge il comando a=Array[a,2], dapprima genera il vettore {a[1],a[2]}, ma poi prende il risultato {a[1],a[2]} e ci sostituisce dentro {a[1],a[2]} al posto di a, ottendendo {{a[1],a[2]}[1],{a[1],a[2]}[2]}. A questo punto riapplica la regola di sostituire {a[1],a[2]} al posto di a e così via. Per aggirare il problema conviene definire cose del tipo aMat=Array[a,2], oppure mat[a_]=Array[a,{2}].