/// <summary> /// Costruttore /// (da migliorare, T : IClonable) /// </summary> /// <param name="m">Matrice di partenza</param> /// <param name="copy">Ricopia i dati se true</param> public MatrixBase(MatrixBase <T> m, bool copy) // Costruttore (se true, ricopia i dati) { row = m.row; // Copia le dimensioni col = m.col; if ((row > 0) && (col > 0)) { dat = new T[row, col]; // Alloca nuovi dati if (copy) // Se richiesto... { // ...copia il contenuto int r, c; for (r = 0; r < row; r++) { for (c = 0; c < col; c++) { dat[r, c] = m.dat[r, c]; // Nota (*) : usa l'operatore = ma dovrebbe usare Clone() } } // Opportuno mettere un controllo su T, se ICloneable // Ma Clone() fa una copia superficiale come object } } else { dat = null; } }
/// <summary> /// Confronta dimensioni /// </summary> /// <param name="m">Matrice da confrontare</param> /// <returns>true se stesse dimensioni</returns> public bool SameSize(MatrixBase <T> m) { if ((this.Col == m.Col) && (this.Row == m.Row)) { return(true); } return(false); }
/// <summary> /// Trasposta /// </summary> /// <param name="m"></param> /// <returns></returns> public static MatrixBase <T> operator !(MatrixBase <T> m) // Trasposta { MatrixBase <T> res = new MatrixBase <T>(m.Col, m.Row); // Crea matrice con dimensioni scambiate int ir, ic; for (ir = 0; ir < m.row; ir++) // Ricopia i valori, scambiandone le posizioni { for (ic = 0; ic < m.col; ic++) { res.dat[ic, ir] = m.dat[ir, ic]; } } return(res); }
/* * RILASSAMENTO * Da scrivere dopo aver completato Bisezione, PassoFisso e Grossolana */ /* * STEEPEST * Da scrivere dopo aver completato Bisezione, PassoFisso e Grossolana */ /* * PASSOFISSO * Analoga a Bisezione (stessi parametri o quasi...) * Usa pero` il gradiente come condizione di uscita al posto della distanza (oltre alla f) */ /// <summary> /// Incrementa contatori /// </summary> /// <param name="contatori">Colonna (n,1) con i contatori</param> /// <param name="passi">Colonna (n,1) con i passi massimi</param> /// <param name="indIncrementato">Indice incrementato, oppure -1 se variato piu` di uno</param> /// <returns>true se ha incrementato un indice, false se era gia` l'ultimo passo</returns> public static bool Incrementa(ref MatrixBase <int> contatori, MatrixBase <int> passi, ref int indIncrementato) { bool fine = false; // Flag finale int n; // Dimensione dei vettori n = contatori.Row; if ((passi.Row != n) || (passi.Col != 1) || (contatori.Col != 1)) { return(fine); // Verifica gli indici } int indice = 0; // Inizia con il primo indice indIncrementato = 0; // Indice da ricalcolare (-1 se tutti) while (indice < n) { int c; c = contatori.Get(indice, 0) + 1; // Calcola indice incrementato if (c < passi.Get(indice, 0)) // Se entro i limiti... { contatori.Set(indice, 0, c); // Aggiorna indice if (indIncrementato != -1) // Lo salva, per aggiornamento calcoli... { indIncrementato = indice; // ... ma solo se non erano gia` cambiati piu` indici } fine = true; // Raggiunta uscita prima della fine break; // Esce dal ciclo while } else { // ...se superato i limiti contatori.Set(indice, 0, 0); // Azzera contatore indice += 1; // Passa all'indice successivo indIncrementato = -1; continue; // Continua il ciclo while } } // Se esce normalmente dal while, fine resta true if (indice >= n) { fine = false; // Se superato ultimo indice: ultimo passo, false } return(fine); }
/// <summary> /// Restituisce una riga /// Se indice errato o matrice nulla: ArgumentOutOfRangeException /// </summary> /// <param name="irow"></param> /// <returns></returns> public MatrixBase <T> GetRow(int irow) // Restituisce una riga { MatrixBase <T> m; int i; if ((irow < 0) || (irow >= row)) // Se indici non corretti o matrice iniziale con dimensione nulla... { throw new ArgumentOutOfRangeException(Error.OutOfRange.ToString()); } else if (col <= 0) { throw new ArgumentOutOfRangeException(Error.NullMatrix.ToString()); } m = new MatrixBase <T>(1, col); // Crea matrice con una riga a tante colonne quanto la matrice dipartenza for (i = 0; i < col; i++) // Ricopia i valori della riga irow per tutte le colonne i { m.dat[0, i] = dat[irow, i]; } return(m); // Restituisce il riferimento all'oggetto allocato }
/// <summary> /// Restituisce una colonna /// Se indice errato o matrice nulla: ArgumentOutOfRangeException /// </summary> /// <param name="icol"></param> /// <returns></returns> public MatrixBase <T> GetCol(int icol) // Restituisce una colonna { MatrixBase <T> m; int i; if ((icol < 0) || (icol >= col)) // Se indici non corretti o matrice iniziale con dimensione nulla... { throw new ArgumentOutOfRangeException(Error.OutOfRange.ToString()); } else if (row <= 0) { throw new ArgumentOutOfRangeException(Error.NullMatrix.ToString()); } m = new MatrixBase <T>(row, 1); // Crea matrice con una colonna a tante righe quanto la matrice dipartenza for (i = 0; i < row; i++) // Ricopia i valori della colonna icol per tutte le righe i { m.dat[i, 0] = dat[i, icol]; } return(m); // Restituisce il riferimento all'oggetto allocato }
public bool Factor(Matrix A) // Fattorizza la matrice A con il metodo di Gauss con pivoting parziale { int n; // Dimensione matrice if (A.Row != A.Col) // Verifica che A sia quadrata { return(false); } n = A.Row; // Legge dimensione if (n < 1) // Verifica dimensione { return(false); } pivot = new MatrixBase <int>(n - 1, 1); // Inizializza dimensioni matrici a = new Matrix(A, true); // Crea nuova matrice idntica ad A if (n == 1) // Se di ordine 1... { det = a[0, 0]; if (System.Math.Abs(det) <= LinearSys.Epsilon) // Se det nullo, esce con errore { return(false); } return(true); // Se det non nullo, esce regolarmente } int k, i, io, j; // Ciclo di calcolo double amax; double tmp; for (io = 0, det = Matrix.One, k = 0; k < n - 1; k++) // Ciclo 1 { for (amax = 0.0, i = k; i < n; i++) // Cerca la riga io con il massimo amax sulla colonna k { if (System.Math.Abs(a[i, k]) >= amax) { io = i; amax = System.Math.Abs(a[i, k]); } } pivot[k, 0] = io; if (amax <= LinearSys.Epsilon) // Se amax è nullo, esce con errore { det = 0.0; return(false); } if (io != k) // Se l'indice non è k... { for (j = k; j < n; j++) // Scambia le righe k e io { tmp = a[k, j]; a[k, j] = a[io, j]; a[io, j] = tmp; } det = -det; // e cambia segno al determinante } for (i = k + 1; i < n; i++) // Ciclo 2 { a[i, k] = -a[i, k] / a[k, k]; for (j = k + 1; j < n; j++) { a[i, j] = a[i, j] + a[i, k] * a[k, j]; } } // Fine ciclo 2 det = det * a[k, k]; } // Fine ciclo 1 if (System.Math.Abs(a[n - 1, n - 1]) <= LinearSys.Epsilon) { det = 0.0; return(false); } det = det * a[n - 1, n - 1]; return(true); }
/// <summary> /// Confronta dimensioni /// </summary> /// <param name="m1">Prima matrice</param> /// <param name="m2">Seconda matrice</param> /// <returns>true se stesse dimensioni</returns> public static bool SameSize(MatrixBase <T> m1, MatrixBase <T> m2) { return(m1.SameSize(m2)); }
/* * * NOTA GENERALE. * * I metodi precedenti, steepest descent, rilassamento (per la scelta delle direzioni) e * passo fisso e bisezione (per la ricerca del minimo (o del massimo) * non sono sufficienti da soli. * * E' ragionevole scrivere prima alcune funzioni che lavorino separatamente. * Tutte sono incluse nella classe Fmin e hanno gia` implicito il delegate alla funzione * Tutte devono prima verificare che il delegate non sia nullo. * */ /// <summary> /// Ricerca per punti /// </summary> /// <param name="xk">Punto centrale</param> /// <param name="range">Meta` ampiezza di ricerca (ammessi valori nulli)</param> /// <param name="passiU">Numero di passi unilaterali (almeno 1)</param> /// <param name="xmin">Punto con il valore minore</param> /// <param name="cicli">Numero di punti calcolati</param> /// <returns></returns> public bool Campionamento(Matrix xk, Matrix range, MatrixBase <int> passiU, ref Matrix xmin, ref int cicli) { bool found = false; int n; // Dimensioni dei vettori int i; // Contatore n = xk.Row; if ((range.Row != n) || (passiU.Row != n) || (xmin.Row != n) || (xk.Col != 1) || (range.Col != 1) || (passiU.Col != 1) || (xmin.Col != 1)) { return(found); // Verifica indici } for (i = 0; i < n; i++) // Verifica intervalli (ammessi valori nulli) { if (range.Get(i, 0) < 0.0) { return(found); } } for (i = 0; i < n; i++) // Verifica passi (almeno 1 per lato) { if (passiU.Get(i, 0) < 1) { return(found); } } MatrixBase <int> passi = new MatrixBase <int>(n, 1); // Matrice dei passi for (i = 0; i < n; i++) // Calcola i passi effettivi (segmenti, non punti) { passi.Set(i, 0, passiU.Get(i, 0) * 2); } Matrix step = new Matrix(n, 1); for (i = 0; i < n; i++) // Calcola i passi effettivi { step.Set(i, 0, range.Get(i, 0) / passi.Get(i, 0)); } Matrix xo = new Matrix(n, 1); for (i = 0; i < n; i++) // Calcola i punti di partenza { xo.Set(i, 0, xk.Get(i, 0) - step.Get(i, 0) * passiU.Get(i, 0)); } MatrixBase <int> contatori = new MatrixBase <int>(n, 1, 0); // Vettore dei contatotri (tutti a 0) Matrix x = new Matrix(n, 1); // Vettore dei valori effettivi int iinc = -1; double minimo = double.MaxValue; double f; cicli = 0; bool fine = false; while (!fine) { if (iinc >= 0) // ricalcola nuovo vettore x { x.Set(iinc, 0, xo.Get(iinc, 0) + step.Get(iinc, 0) * contatori.Get(iinc, 0)); } else { for (i = 0; i < n; i++) { x.Set(i, 0, xo.Get(i, 0) + step.Get(i, 0) * contatori.Get(i, 0)); } } f = Funzione(x); // Calcola la f del punto x attuale if (f < minimo) // Vede se e` minima (rispetto ai valori trovati finora) { minimo = f; xmin = x.Copy(); found = true; } fine = !Incrementa(ref contatori, passi, ref iinc); cicli++; } return(found); }