/// <summary> /// Generates tri-diagonal square matrix with overloaded vectors /// as main and secondary diagonals. The dimension of the output /// matrix is determined by the length of d. /// </summary> /// <param name="l">Lower secondary diagonal vector.</param> /// <param name="d">Main diagonal vector.</param> /// <param name="u">Upper secondary diagonal vector.</param> /// <returns></returns> public static Matrix TriDiag(Matrix l, Matrix d, Matrix u) { int sizeL = l.VectorLength(); int sizeD = d.VectorLength(); int sizeU = u.VectorLength(); if (sizeL * sizeD * sizeU == 0) throw new ArgumentException("At least one of the paramter matrices is not a vector."); if (sizeL != sizeU) throw new ArgumentException("Lower and upper secondary diagonal must have the same length."); if (sizeL + 1 != sizeD) throw new ArgumentException("Main diagonal must have exactly one element more than the secondary diagonals."); return Diag(l, -1) + Diag(d) + Diag(u, 1); }
/// <summary> /// Implements the dot product of two vectors. /// </summary> /// <param name="v">Row or column vector.</param> /// <param name="w">Row or column vector.</param> /// <returns>Dot product.</returns> public static Complex Dot(Matrix v, Matrix w) { int m = v.VectorLength(); int n = w.VectorLength(); if (m == 0 || n == 0) throw new ArgumentException("Arguments need to be vectors."); else if (m != n) throw new ArgumentException("Vectors must be of the same length."); Complex buf = Complex.Zero; for (int i = 1; i <= m; i++) { buf += v[i] * w[i]; } return buf; }
/// <summary> /// Generates diagonal matrix /// </summary> /// <param name="diag_vector">column vector containing the diag elements</param> /// <returns></returns> public static Matrix Diag(Matrix diag_vector) { int dim = diag_vector.VectorLength(); if(dim == 0) throw new ArgumentException("diag_vector must be 1xN or Nx1"); Matrix M = new Matrix(dim, dim); for (int i = 1; i <= dim; i++) { M[i, i] = diag_vector[i]; } return M; }
/// <summary> /// Generates diagonal matrix /// </summary> /// <param name="diag_vector">column vector containing the diag elements</param> /// <returns></returns> public static Matrix Diag(Matrix diag_vector, int offset) { int dim = diag_vector.VectorLength(); if(dim == 0) throw new ArgumentException("diag_vector must be 1xN or Nx1."); //if (Math.Abs(offset) >= dim) // throw new ArgumentException("Absolute value of offset must be less than length of diag_vector."); Matrix M = new Matrix(dim + Math.Abs(offset), dim + Math.Abs(offset)); dim = M.RowCount; if (offset >= 0) { for (int i = 1; i <= dim - offset; i++) { M[i, i + offset] = diag_vector[i]; } } else { for (int i = 1; i <= dim + offset; i++) { M[i - offset, i] = diag_vector[i]; } } return M; }
/// <summary> /// Performs backward insertion for regular upper triangular matrix /// and right side b, such that the solution is saved right within b. /// The matrix is not changed. /// </summary> /// <param name="b">Vector of height n, if matrix is n by n.</param> public void BackwardInsertion(Matrix b) { if (!this.IsUpperTriangular()) throw new InvalidOperationException("Cannot perform backward insertion for matrix not being upper triangular."); if (/*this.Determinant*/this.DiagProd() == 0) throw new InvalidOperationException("Warning: Matrix is nearly singular."); int n = rowCount; if (b.VectorLength() != n) throw new ArgumentException("Parameter must vector of the same height as matrix."); for (int j = n; j >= 2; j--) { b[j] /= this[j, j]; for (int i = 1; i <= j - 1; i++) b[i] -= b[j] * this[i, j]; } b[1] /= this[1, 1]; }
/// <summary> /// Performs forward insertion for regular lower triangular matrix /// and right side b, such that the solution is saved right within b. /// The matrix is not changed. /// </summary> /// <param name="b">Vector of height n, if matrix is n by n.</param> public void ForwardInsertion(Matrix b) { if (!this.IsLowerTriangular()) throw new InvalidOperationException("Cannot perform forward insertion for matrix not being lower triangular."); if (/*this.Determinant*/this.DiagProd() == 0) throw new InvalidOperationException("Warning: Matrix is nearly singular."); int n = rowCount; if (b.VectorLength() != n) throw new ArgumentException("Parameter must vector of the same height as matrix."); for (int j = 1; j <= n - 1; j++) { b[j] /= this[j, j]; for (int i = 1; i <= n - j; i++) b[j + i] -= b[j] * this[j + i, j]; } b[n] /= this[n, n]; }
/// <summary> /// Inserts column at specified index. /// </summary> /// <param name="col">Vector to insert</param> /// <param name="j">One-based index at which to insert</param> public void InsertColumn(Matrix col, int j) { int size = col.VectorLength(); if (size == 0) throw new InvalidOperationException("Row must be a vector of length > 0."); if (j <= 0) throw new ArgumentException("Row index must be positive."); if (j > columnCount) { this[size, j] = Complex.Zero; } else columnCount++; if (size > rowCount) { this[size, j] = Complex.Zero; } j--; for (int k = 0; k < size; k++) { ((ArrayList)Values[k]).Insert(j, col[k + 1]); } // fill w/ zeros if vector col too short for (int k = size; k < rowCount; k++) { ((ArrayList)Values[k]).Insert(j, 0); } }
/// <summary> /// Inserts row at specified index. /// </summary> /// <param name="row">Vector to insert</param> /// <param name="i">One-based index at which to insert</param> public void InsertRow(Matrix row, int i) { int size = row.VectorLength(); if (size == 0) throw new InvalidOperationException("Row must be a vector of length > 0."); if (i <= 0) throw new ArgumentException("Row index must be positive."); if (i > rowCount) this[i, size] = Complex.Zero; else if (size > columnCount) { this[i, size] = Complex.Zero; rowCount++; } else rowCount++; Values.Insert(--i, new ArrayList(size)); //Debug.WriteLine(Values.Count.ToString()); for (int k = 1; k <= size; k++) { ((ArrayList)Values[i]).Add(row[k]); } // fill w/ zeros if vector row is too short for (int k = size; k < columnCount; k++) { ((ArrayList)Values[i]).Add(Complex.Zero); } }
/// <summary> /// Computes the Householder vector. /// </summary> /// <param name="x"></param> /// <returns></returns> private static Matrix[] HouseholderVector(Matrix x) { //throw new NotImplementedException("Supposingly buggy!"); //if (!x.IsReal()) // throw new ArgumentException("Cannot compute housholder vector of non-real vector."); int n = x.VectorLength(); if (n == 0) throw new InvalidOperationException("Expected vector as argument."); Matrix y = x / x.Norm(); Matrix buf = y.Extract(2, n, 1, 1); Complex s = Dot(buf, buf); Matrix v = Zeros(n, 1); v[1] = Complex.One; v.Insert(2, 1, buf); double beta = 0; if (s != 0) { Complex mu = Complex.Sqrt(y[1] * y[1] + s); if (y[1].Re <= 0) v[1] = y[1] - mu; else v[1] = -s / (y[1] + mu); beta = 2 * v[1].Re * v[1].Re / (s.Re + v[1].Re * v[1].Re); v = v / v[1]; } return new Matrix[] { v, new Matrix(beta) }; }