Matrici (F#)
Le matrici sono raccolte a dimensione fissa, in base zero e modificabili di elementi dati consecutivi dello stesso tipo.
Creazione di matrici
È possibile creare matrici in vari modi. È possibile creare una matrice di piccole dimensioni elencando valori consecutivi compresi tra [| e |] e separati da punti e virgola, come mostrato negli esempi indicati di seguito.
let array1 = [| 1; 2; 3 |]
È inoltre possibile posizionare ogni elemento su una riga separata e, in questo caso, l'utilizzo del punto e virgola come separatore è facoltativo.
let array1 =
[|
1
2
3
|]
Il tipo di elementi della matrice viene derivato dai valori letterali utilizzati e deve essere coerente. Il codice seguente genera un errore, in quanto 1.0 è un tipo float, mentre 2 e 3 sono Integer.
// Causes an error.
// let array2 = [| 1.0; 2; 3 |]
È inoltre possibile utilizzare espressioni sequenza per creare matrici. Di seguito è indicato un esempio in cui viene creata una matrice di quadrati di Integer da 1 a 10.
let array3 = [| for i in 1 .. 10 -> i * i |]
Per creare una matrice in cui tutti gli elementi vengono inizializzati su zero, utilizzare Array.zeroCreate.
let arrayOfTenZeroes : int array = Array.zeroCreate 10
Accesso agli elementi
È possibile accedere agli elementi della matrice tramite un operatore punto (.) e parentesi quadre ([ e ]).
array1.[0]
Gli indici di matrice iniziano da zero.
È inoltre possibile accedere agli elementi della matrice mediante la notazione di sezione, che consente di specificare un intervallo secondario della matrice. Di seguito sono disponibili esempi di notazione di sezione.
// Accesses elements from 0 to 2.
array1.[0..2]
// Accesses elements from the beginning of the array to 2.
array1.[..2]
// Accesses elements from 2 to the end of the array.
array1.[2..]
Quando viene utilizzata la notazione di sezione, viene creata una nuova copia della matrice.
Moduli e tipi di matrice
Il tipo di tutte le matrici F# è il tipo .NET Framework Array. Le matrici F# supportano pertanto tutte le funzionalità disponibili in Array.
Il modulo di libreria Microsoft.FSharp.Collections.Array supporta operazioni su matrici unidimensionali. I moduli Array2D, Array3D e Array4D contengono funzioni che supportano le operazioni su matrici rispettivamente a due, tre e quattro dimensioni. È possibile creare matrici a più di 4 dimensioni tramite Array.
Funzioni semplici
Array.get ottiene un elemento. Array.length fornisce la lunghezza di una matrice. Array.set imposta un elemento su un valore specificato. Nell'esempio di codice riportato di seguito viene illustrato l'utilizzo di queste funzioni.
let array1 = Array.create 10 ""
for i in 0 .. array1.Length - 1 do
Array.set array1 i (i.ToString())
for i in 0 .. array1.Length - 1 do
printf "%s " (Array.get array1 i)
L'output è indicato di seguito.
0 1 2 3 4 5 6 7 8 9
Funzioni per la creazione di matrici
Diverse funzioni creano matrici senza la necessità di una matrice esistente. Array.empty crea una nuova matrice che non contiene elementi. Array.create crea una matrice di una dimensione specificata e imposta tutti gli elementi sui valori forniti. Array.init crea una matrice in base a una dimensione e a una funzione specificate per generare gli elementi. Array.zeroCreate crea una matrice in cui tutti gli elementi vengono inizializzati sul valore zero per il tipo della matrice. Nel codice seguente vengono illustrate queste funzioni.
let myEmptyArray = Array.empty
printfn "Length of empty array: %d" myEmptyArray.Length
printfn "Array of floats set to 5.0: %A" (Array.create 10 5.0)
printfn "Array of squares: %A" (Array.init 10 (fun index -> index * index))
let (myZeroArray : float array) = Array.zeroCreate 10
L'output è indicato di seguito.
Length of empty array: 0
Area of floats set to 5.0: [|5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0|]
Array of squares: [|0; 1; 4; 9; 16; 25; 36; 49; 64; 81|]
Array.copy crea una nuova matrice contenente elementi copiati da una matrice esistente. Si tratta di una copia superficiale, ovvero se il tipo di elemento è un tipo di riferimento, viene copiato esclusivamente il riferimento, non l'oggetto sottostante. Questo aspetto è illustrato nell'esempio di codice seguente.
open System.Text
let firstArray : StringBuilder array = Array.init 3 (fun index -> new StringBuilder(""))
let secondArray = Array.copy firstArray
// Reset an element of the first array to a new value.
firstArray.[0] <- new StringBuilder("Test1")
// Change an element of the first array.
firstArray.[1].Insert(0, "Test2") |> ignore
printfn "%A" firstArray
printfn "%A" secondArray
Di seguito è riportato l'output del codice precedente:
[|Test1; Test2; |]
[|; Test2; |]
La stringa Test1 viene visualizzata solo nella prima matrice, poiché l'operazione di creazione di un nuovo elemento sovrascrive il riferimento in firstArray, ma non influisce sul riferimento originale a una stringa vuota ancora presente in secondArray. La stringa Test2 viene visualizzata in entrambe le matrici, poiché l'operazione Insert sul tipo StringBuilder influisce sull'oggetto StringBuilder sottostante, a cui viene fatto riferimento in entrambe le matrici.
Array.sub genera una nuova matrice da un intervallo secondario di una matrice. Un intervallo secondario viene specificato fornendo l'indice iniziale e la lunghezza. Nell'esempio di codice seguente viene illustrato l'utilizzo di Array.sub.
let a1 = [| 0 .. 99 |]
let a2 = Array.sub a1 5 10
printfn "%A" a2
L'output indica che la sottomatrice inizia con l'elemento 5 e contiene 10 elementi.
[|5; 6; 7; 8; 9; 10; 11; 12; 13; 14|]
Array.append crea una nuova matrice combinando due matrici esistenti.
Nell'esempio di codice seguente viene illustrato Array.append.
printfn "%A" (Array.append [| 1; 2; 3|] [| 4; 5; 6|])
Di seguito è indicato l'output del codice precedente.
[|1; 2; 3; 4; 5; 6|]
Array.choose seleziona elementi di una matrice da includere in una nuova matrice. Nell'esempio di codice seguente viene illustrato Array.choose. Il tipo di elemento della matrice non deve necessariamente corrispondere al tipo del valore restituito nel tipo di opzione. In questo esempio il tipo di elemento è int e l'opzione è il risultato di una funzione polinomiale, elem*elem - 1, sotto forma di numero a virgola mobile.
printfn "%A" (Array.choose (fun elem -> if elem % 2 = 0 then
Some(float (elem*elem - 1))
else
None) [| 1 .. 10 |])
Di seguito è indicato l'output del codice precedente.
[|3.0; 15.0; 35.0; 63.0; 99.0|]
Array.collect esegue una funzione specificata su ogni elemento di matrice di una matrice esistente, quindi raccoglie gli elementi generati dalla funzione e li combina in una nuova matrice. Nell'esempio di codice seguente viene illustrato Array.collect.
printfn "%A" (Array.collect (fun elem -> [| 0 .. elem |]) [| 1; 5; 10|])
Di seguito è indicato l'output del codice precedente.
[|0; 1; 0; 1; 2; 3; 4; 5; 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
Array.concat utilizza una sequenza di matrici e le combina in una sola matrice. Nell'esempio di codice seguente viene illustrato Array.concat.
let multiplicationTable max = seq { for i in 1 .. max -> [| for j in 1 .. max -> (i, j, i*j) |] }
printfn "%A" (Array.concat (multiplicationTable 3))
Di seguito è indicato l'output del codice precedente.
[|(1, 1, 1); (1, 2, 2); (1, 3, 3); (2, 1, 2); (2, 2, 4); (2, 3, 6); (3, 1, 3);
(3, 2, 6); (3, 3, 9)|]
Array.filter utilizza una funzione di condizione booleana e genera una nuova matrice contenente solo gli elementi della matrice di input per i quali la condizione è true. Nell'esempio di codice seguente viene illustrato Array.filter.
printfn "%A" (Array.filter (fun elem -> elem % 2 = 0) [| 1 .. 10|])
Di seguito è indicato l'output del codice precedente.
[|2; 4; 6; 8; 10|]
Array.rev genera una nuova matrice invertendo l'ordine di una matrice esistente. Nell'esempio di codice seguente viene illustrato Array.rev.
let stringReverse (s: string) =
System.String(Array.rev (s.ToCharArray()))
printfn "%A" (stringReverse("!dlrow olleH"))
Di seguito è indicato l'output del codice precedente.
"Hello world!"
È possibile combinare agevolmente funzioni nel modulo della matrice che trasformano matrici tramite l'operatore pipeline (|>), come indicato nell'esempio seguente.
[| 1 .. 10 |]
|> Array.filter (fun elem -> elem % 2 = 0)
|> Array.choose (fun elem -> if (elem <> 8) then Some(elem*elem) else None)
|> Array.rev
|> printfn "%A"
L'output è
[|100; 36; 16; 4|]
Matrici multidimensionali
È possibile creare una matrice multidimensionale, ma non è disponibile la sintassi per la scrittura di un valore letterale della matrice multidimensionale. Utilizzare l'operatore array2D per creare una matrice da una sequenza di sequenze di elementi di matrice. Le sequenze possono essere valori letterali della matrice o dell'elenco. Mediante il codice che segue, ad esempio, viene creata una matrice bidimensionale.
let my2DArray = array2D [ [ 1; 0]; [0; 1] ]
È inoltre possibile utilizzare la funzione Array2D.init per inizializzare matrici a due dimensioni e per le matrici a tre e quattro dimensioni sono disponibili funzioni analoghe. Queste funzioni utilizzano una funzione impiegata per creare gli elementi. Per creare una matrice bidimensionale contenente elementi impostati su un valore iniziale anziché specificare una funzione, utilizzare la funzione Array2D.create, disponibile anche per le matrici fino a quattro dimensioni. Nell'esempio di codice seguente viene in primo luogo illustrata la modalità di creazione di una matrice di matrici contenenti gli elementi desiderati, quindi viene utilizzato Array2D.init per generare la matrice bidimensionale desiderata.
let arrayOfArrays = [| [| 1.0; 0.0 |]; [|0.0; 1.0 |] |]
let twoDimensionalArray = Array2D.init 2 2 (fun i j -> arrayOfArrays.[i].[j])
Per le matrici fino a 4 dimensioni sono supportate l'indicizzazione della matrice e la sintassi di sezionamento. Se si specifica un indice in più dimensioni, è necessario utilizzare le virgole per separare gli indici, come illustrato nell'esempio di codice seguente.
twoDimensionalArray.[0, 1] <- 1.0
Il tipo di una matrice bidimensionale viene scritto come <type>[,] (ad esempio, int[,], double[,]), il tipo di una matrice tridimensionale viene scritto come <type>[,,] e così via per le matrici di dimensioni superiori.
Solo un subset delle funzioni disponibile per le matrici unidimensionali è disponibile anche per le matrici multidimensionali. Per ulteriori informazioni, vedere Modulo Collections.Array (F#), Modulo Collections.Array2D (F#), Modulo Collections.Array3D (F#) e Modulo Collections.Array4D (F#).
Sezionamento delle matrici e matrici multidimensionali
In una matrice bidimensionale è possibile estrarre una matrice secondaria specificando gli intervalli e utilizzando un carattere jolly (*) per specificare intere righe o colonne.
// Get rows 1 to N from an NxM matrix (returns a matrix):
matrix.[1.., *]
// Get rows 1 to 3 from a matrix (returns a matrix):
matrix.[1..3, *]
// Get columns 1 to 3 from a matrix (returns a matrix):
matrix.[*, 1..3]
// Get a 3x3 submatrix:
matrix.[1..3, 1..3]
A partire da F# 3.1, è possibile scomporre una matrice multidimensionale in sottomatrici della stessa dimensione o più piccole. Ad esempio, è possibile ottenere un vettore da una matrice specificando una singola riga o colonna.
// Get row 3 from a matrix as a vector:
matrix.[3, *]
// Get column 3 from a matrix as a vector:
matrix.[*, 3]
È possibile utilizzare questa sintassi di sezionamento per i tipi che implementano operatori di accesso elementi e i metodi GetSlice sottoposti a overload. Ad esempio, il codice seguente crea un tipo Matrix che contiene la matrice 2D F#, implementa una proprietà dell'elemento per fornire supporto per l'indicizzazione della matrice e implementa tre versioni di GetSlice. Se è possibile utilizzare questo codice come modello per i tipi di matrice, è possibile utilizzare tutte le operazioni di sezionamento descritte in questa sezione.
type Matrix<'T>(N: int, M: int) =
let internalArray = Array2D.zeroCreate<'T> N M
member this.Item
with get(a: int, b: int) = internalArray.[a, b]
and set(a: int, b: int) (value:'T) = internalArray.[a, b] <- value
member this.GetSlice(rowStart: int option, rowFinish : int option,
colStart: int option, colFinish : int option) =
let rowStart = match rowStart with
| Some(v) -> v
| None -> 0
let rowFinish = match rowFinish with
| Some(v) -> v
| None -> internalArray.GetLength(0) - 1
let colStart = match colStart with
| Some(v) -> v
| None -> 0
let colFinish = match colFinish with
| Some(v) -> v
| None -> internalArray.GetLength(1) - 1
internalArray.[rowStart..rowFinish, colStart..colFinish]
member this.GetSlice(row: int, colStart: int option, colFinish: int option) =
let colStart = match colStart with
| Some(v) -> v
| None -> 0
let colFinish = match colFinish with
| Some(v) -> v
| None -> internalArray.GetLength(1) - 1
internalArray.[row, colStart..colFinish]
member this.GetSlice(rowStart: int option, rowFinish: int option, col: int) =
let rowStart = match rowStart with
| Some(v) -> v
| None -> 0
let rowFinish = match rowFinish with
| Some(v) -> v
| None -> internalArray.GetLength(0) - 1
internalArray.[rowStart..rowFinish, col]
module test =
let generateTestMatrix x y =
let matrix = new Matrix<float>(3, 3);
for i in 0..2 do
for j in 0..2 do
matrix.[i, j] <- float(i) * x - float(j) * y
matrix
let test1 = generateTestMatrix 2.3 1.1
let submatrix = test1.[0..1, 0..1]
printfn "%A" submatrix
let firstRow = test1.[0,*]
let secondRow = test1.[1,*]
let firstCol = test1.[*,0]
printfn "%A" firstCol
Funzioni booleane nelle matrici
Le funzioni Array.exists e Array.exists2 testano gli elementi rispettivamente in una o due matrici. Queste funzioni ricevono una funzione di test e restituiscono true se esiste un elemento (o coppia di elementi per Array.exists2) che soddisfa la condizione.
Nell'esempio di codice seguente viene illustrato l'utilizzo di Array.exists e Array.exists2. In questi esempi le nuove funzioni vengono create applicando solo uno degli argomenti (in questi casi, l'argomento della funzione).
let allNegative = Array.exists (fun elem -> abs (elem) = elem) >> not
printfn "%A" (allNegative [| -1; -2; -3 |])
printfn "%A" (allNegative [| -10; -1; 5 |])
printfn "%A" (allNegative [| 0 |])
let haveEqualElement = Array.exists2 (fun elem1 elem2 -> elem1 = elem2)
printfn "%A" (haveEqualElement [| 1; 2; 3 |] [| 3; 2; 1|])
Di seguito è indicato l'output del codice precedente.
true
false
false
true
In modo analogo, la funzione Array.forall testa una matrice per determinare se ogni elemento soddisfa una condizione booleana. La variazione Array.forall2 si comporta in modo analogo, utilizzando una funzione booleana che utilizza elementi di due matrici di uguale lunghezza. Nel codice riportato di seguito viene illustrato l'utilizzo di queste funzioni.
let allPositive = Array.forall (fun elem -> elem > 0)
printfn "%A" (allPositive [| 0; 1; 2; 3 |])
printfn "%A" (allPositive [| 1; 2; 3 |])
let allEqual = Array.forall2 (fun elem1 elem2 -> elem1 = elem2)
printfn "%A" (allEqual [| 1; 2 |] [| 1; 2 |])
printfn "%A" (allEqual [| 1; 2 |] [| 2; 1 |])
Di seguito è riportato l'output di questi esempi.
false
true
true
false
Ricerche nelle matrici
Array.find utilizza una funzione booleana e restituisce il primo elemento per cui la funzione restituisce true o genera un'eccezione KeyNotFoundException se non viene rilevato alcun elemento che soddisfi la condizione. Array.findIndex è analogo a Array.find, ad eccezione del fatto che restituisce l'indice dell'elemento anziché l'elemento stesso.
Il codice seguente utilizza Array.find e Array.findIndex per individuare un numero che sia un quadrato perfetto e un cubo perfetto.
let arrayA = [| 2 .. 100 |]
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
let element = Array.find (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
let index = Array.findIndex (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
printfn "The first element that is both a square and a cube is %d and its index is %d." element index
L'output è indicato di seguito.
The first element that is both a square and a cube is 64 and its index is 62.
Array.tryFind è analogo a Array.find, ad eccezione del fatto che il risultato è un tipo di opzione e restituisce None se non viene rilevato alcun elemento. Qualora si ignori se un elemento corrispondente si trova nella matrice, è opportuno utilizzare Array.tryFind anziché Array.find. In modo simile, Array.tryFindIndex è analogo a Array.findIndex, ad eccezione del fatto che il tipo di opzione è il valore restituito. Se non viene rilevato alcun elemento, l'opzione è None.
Nell'esempio di codice seguente viene illustrato l'utilizzo di Array.tryFind. Questo codice dipende dal codice precedente.
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
let lookForCubeAndSquare array1 =
let result = Array.tryFind (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1
match result with
| Some x -> printfn "Found an element: %d" x
| None -> printfn "Failed to find a matching element."
lookForCubeAndSquare [| 1 .. 10 |]
lookForCubeAndSquare [| 100 .. 1000 |]
lookForCubeAndSquare [| 2 .. 50 |]
L'output è indicato di seguito.
Found an element: 1
Found an element: 729
Utilizzare Array.tryPick se è necessario trasformare un elemento, oltre a rilevarlo. Il risultato è il primo elemento per il quale la funzione restituisce l'elemento trasformato come valore di opzione o None se non viene trovato alcun elemento.
Nell'esempio di codice riportato di seguito viene illustrato come utilizzare Array.tryPick. In questo caso, per semplificare il codice vengono definite diverse funzioni di supporto locali, anziché un'espressione lambda.
let findPerfectSquareAndCube array1 =
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
// intFunction : (float -> float) -> int -> int
// Allows the use of a floating point function with integers.
let intFunction function1 number = int (round (function1 (float number)))
let cubeRoot x = System.Math.Pow(x, 1.0/3.0)
// testElement: int -> (int * int * int) option
// Test an element to see whether it is a perfect square and a perfect
// cube, and, if so, return the element, square root, and cube root
// as an option value. Otherwise, return None.
let testElement elem =
if isPerfectSquare elem && isPerfectCube elem then
Some(elem, intFunction sqrt elem, intFunction cubeRoot elem)
else None
match Array.tryPick testElement array1 with
| Some (n, sqrt, cuberoot) -> printfn "Found an element %d with square root %d and cube root %d." n sqrt cuberoot
| None -> printfn "Did not find an element that is both a perfect square and a perfect cube."
findPerfectSquareAndCube [| 1 .. 10 |]
findPerfectSquareAndCube [| 2 .. 100 |]
findPerfectSquareAndCube [| 100 .. 1000 |]
findPerfectSquareAndCube [| 1000 .. 10000 |]
findPerfectSquareAndCube [| 2 .. 50 |]
L'output è indicato di seguito.
Found an element 1 with square root 1 and cube root 1.
Found an element 64 with square root 8 and cube root 4.
Found an element 729 with square root 27 and cube root 9.
Found an element 4096 with square root 64 and cube root 16.
Esecuzione di calcoli sulle matrici
La funzione Array.average restituisce la media di ogni elemento in una matrice. È limitata a tipi di elemento che supportano l'esatta divisione per un numero intero, che include tipi a virgola mobile ma non tipi integrali. La funzione Array.averageBy restituisce la media dei risultati derivanti dalla chiamata a una funzione su ogni elemento. Per una matrice di tipo integrale, è possibile utilizzare Array.averageBy e fare in modo che la funzione converta ogni elemento in un tipo a virgola mobile per il calcolo.
Utilizzare Array.max o Array.min per ottenere l'elemento massimo o minimo, se supportato dal tipo di elemento. In modo analogo, Array.maxBy e Array.minBy consentono l'esecuzione preliminare di una funzione, ad esempio per trasformarla in un tipo che supporta il confronto.
Array.sum aggiunge gli elementi di una matrice e Array.sumBy chiama una funzione su ogni elemento, sommando quindi i risultati.
Per eseguire una funzione su ogni elemento in una matrice senza archiviare i valori restituiti, utilizzare Array.iter. Per una funzione che interessa due matrici di uguale lunghezza, utilizzare Array.iter2. Se è inoltre necessario mantenere una matrice dei risultati della funzione, utilizzare Array.map o Array.map2 che agisce su due matrici contemporaneamente.
Le variazioni Array.iteri e Array.iteri2 consentono l'inclusione dell'indice dell'elemento nel calcolo. Ciò vale anche per Array.mapi e Array.mapi2.
Le funzioni Array.fold, Array.foldBack, Array.reduce, Array.reduceBack, Array.scan e Array.scanBack eseguono algoritmi che coinvolgono tutti gli elementi di una matrice. In modo analogo, le variazioni Array.fold2 e Array.foldBack2 eseguono calcoli su due matrici.
Queste funzioni per l'esecuzione di calcoli corrispondono alle funzioni denominate in modo analogo nel modulo List. Per alcuni esempi di utilizzo, vedere Elenchi (F#).
Modifica di matrici
Array.set imposta un elemento su un valore specificato. Array.fill imposta un intervallo di elementi in una matrice su un valore specificato. Nel codice riportato di seguito viene fornito un esempio di Array.fill.
let arrayFill1 = [| 1 .. 25 |]
Array.fill arrayFill1 2 20 0
printfn "%A" arrayFill1
L'output è indicato di seguito.
[|1; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 23; 24; 25|]
È possibile utilizzare Array.blit per copiare una sottosezione di una matrice in un'altra matrice.
Conversione da e verso altri tipi
Array.ofList crea una matrice da un elenco. Array.ofSeq crea una matrice da una sequenza. Array.toList e Array.toSeq eseguono la conversione in questi altri tipi di raccolta dal tipo di matrice.
Ordinamento di matrici
Utilizzare Array.sort per ordinare una matrice mediante la funzione di confronto generica. Utilizzare Array.sortBy per specificare una funzione che genera un valore, a cui si fa riferimento come chiave, da ordinare mediante la funzione di confronto generica sulla chiave. Utilizzare Array.sortWith se si desidera fornire una funzione di confronto personalizzata. Array.sort, Array.sortBy e Array.sortWith restituiscono tutte la matrice ordinata come nuova matrice. Le variazioni Array.sortInPlace, Array.sortInPlaceBye Array.sortInPlaceWith modificano la matrice esistente anziché restituirne una nuova.
Matrici e tuple
Le funzioni Array.zip e di Array.unzip convertono matrici di coppie di tuple in tuple di matrici e viceversa. Array.zip3 e Array.unzip3 sono simili, ad eccezione del fatto che utilizzano tuple di tre elementi o di tre matrici.
Calcoli paralleli sulle matrici
Il modulo Array.Parallel contiene funzioni per l'esecuzione di calcoli paralleli sulle matrici. Il modulo non è disponibile nelle applicazioni indirizzate a versioni precedenti a .NET Framework 4.