예제 #1
0
        /// <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(ArrayMatrix b)
        {
            if (!IsLowerTriangular()) throw new InvalidOperationException("Cannot perform forward insertion for matrix not being lower triangular.");

            if ( /*this.Determinant*/DiagProd() == 0) throw new InvalidOperationException("Warning: Matrix is nearly singular.");

            var n = RowCount;

            if (b.VectorLength() != n) throw new ArgumentException("Parameter must vector of the same height as matrix.");

            for (var j = 1; j <= n - 1; j++)
            {
                b[j] /= this[j, j];

                for (var i = 1; i <= n - j; i++) b[j + i] -= b[j]*this[j + i, j];
            }

            b[n] /= this[n, n];
        }
예제 #2
0
        public static ArrayMatrix HorizontalConcat(ArrayMatrix[] A)
        {
            if (A == null) throw new ArgumentNullException();
            else if (A.Length == 1) return A[0];
            else
            {
                var C = HorizontalConcat(A[0], A[1]);

                for (var i = 2; i < A.Length; i++) C = HorizontalConcat(C, A[i]);

                return C;
            }
        }
예제 #3
0
        /// <summary>
        /// Creates n by n matrix filled with random values in [0,1].
        /// </summary>
        /// <param name="m"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static ArrayMatrix Random(int n)
        {
            var M = new ArrayMatrix(n);
            var r = new Random();

            for (var i = 1; i <= n; i++) for (var j = 1; j <= n; j++) M[i, j] = new Complex(r.NextDouble());

            return M;
        }
예제 #4
0
        /// <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(ArrayMatrix v, ArrayMatrix w)
        {
            var m = v.VectorLength();
            var 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.");

            var buf = Complex.Zero;

            for (var i = 1; i <= m; i++) buf += v[i]*w[i];

            return buf;
        }
예제 #5
0
        /// <summary>
        /// Returns the shortest path between two given vertices i and j as
        /// int array.
        /// </summary>
        /// <param name="P">Path matrix as returned from Floyd().</param>
        /// <param name="i">One-based index of start vertex.</param>
        /// <param name="j">One-based index of end vertex.</param>
        /// <returns></returns>
        public static ArrayList FloydPath(ArrayMatrix P, int i, int j)
        {
            if (!P.IsSquare()) throw new ArgumentException("Path matrix must be square.");
            else if (!P.IsReal()) throw new ArgumentException("Adjacence matrices are expected to be real.");

            var path = new ArrayList();
            path.Add(i);

            //int borderliner = 0;
            //int n = P.Size()[0] + 1; // shortest path cannot have more than n vertices!

            while (P[i, j] != 0)
            {
                i = Convert.ToInt32(P[i, j]);
                path.Add(i);

                //borderliner++;

                //if (borderliner == n)
                //    throw new FormatException("P was not a Floyd path matrix.");
            }

            path.Add(j);

            return path;
        }
예제 #6
0
        /// <summary>
        /// Creates m by n chessboard matrix with interchangíng ones and zeros.
        /// 
        /// </summary>        
        /// <param name="n">Number of columns.</param>
        /// <param name="even">Indicates, if matrix entry (1,1) equals zero.</param>
        /// <returns></returns>
        public static ArrayMatrix ChessboardMatrix(int n, bool even)
        {
            var M = new ArrayMatrix(n);

            if (even) for (var i = 1; i <= n; i++) for (var j = 1; j <= n; j++) M[i, j] = KroneckerDelta((i + j)%2, 0);
            else for (var i = 1; i <= n; i++) for (var j = 1; j <= n; j++) M[i, j] = KroneckerDelta((i + j)%2, 1);

            return M;
        }
예제 #7
0
        /// <summary>
        /// Generates diagonal matrix
        /// </summary>
        /// <param name="diag_vector">column vector containing the diag elements</param>
        /// <returns></returns>
        public static ArrayMatrix Diag(ArrayMatrix diag_vector)
        {
            var dim = diag_vector.VectorLength();

            if (dim == 0) throw new ArgumentException("diag_vector must be 1xN or Nx1");

            var M = new ArrayMatrix(dim, dim);

            for (var i = 1; i <= dim; i++) M[i, i] = diag_vector[i];

            return M;
        }
예제 #8
0
        /// <summary>
        /// Executes the QR iteration.
        /// </summary>
        /// <param name="max_iterations"></param>
        /// <returns></returns>
        public ArrayMatrix QRIterationBasic(int max_iterations)
        {
            if (!IsReal()) throw new InvalidOperationException("Basic QR iteration is possible only for real matrices.");

            var T = Clone();
            var QR = new ArrayMatrix[2];

            for (var i = 0; i < max_iterations; i++)
            {
                QR = T.QRGramSchmidt();
                T = QR[1]*QR[0];
            }

            return T;
        }
예제 #9
0
        /// <summary>
        /// Returns the matrix of the real parts of the entries of this matrix.
        /// </summary>
        /// <returns></returns>
        public ArrayMatrix Re()
        {
            var M = new ArrayMatrix(RowCount, ColumnCount);

            for (var i = 1; i <= RowCount; i++) for (var j = 1; j <= ColumnCount; j++) M[i, j] = new Complex(this[i, j].Real);

            return M;
        }
예제 #10
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(ArrayMatrix row, int i)
        {
            var 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 (var k = 1; k <= size; k++) ((ArrayList) Values[i]).Add(row[k]);

            // fill w/ zeros if vector row is too short
            for (var k = size; k < ColumnCount; k++) ((ArrayList) Values[i]).Add(Complex.Zero);
        }
예제 #11
0
        /// <summary>
        /// Gram-Schmidtian orthogonalization of an m by n matrix A, such that
        /// {Q, R} is returned, where A = QR, Q is m by n and orthogonal, R is
        /// n by n and upper triangular matrix.
        /// </summary>
        /// <returns></returns>
        public ArrayMatrix[] QRGramSchmidt()
        {
            var m = RowCount;
            var n = ColumnCount;

            var A = Clone();

            var Q = new ArrayMatrix(m, n);
            var R = new ArrayMatrix(n, n);

            // the first column of Q equals the first column of this matrix
            for (var i = 1; i <= m; i++) Q[i, 1] = A[i, 1];

            R[1, 1] = Complex.One;

            for (var k = 1; k <= n; k++)
            {
                R[k, k] = new Complex(A.Column(k).Norm());

                for (var i = 1; i <= m; i++) Q[i, k] = A[i, k]/R[k, k];

                for (var j = k + 1; j <= n; j++)
                {
                    R[k, j] = Dot(Q.Column(k), A.Column(j));

                    for (var i = 1; i <= m; i++) A[i, j] = A[i, j] - Q[i, k]*R[k, j];
                }
            }

            return new ArrayMatrix[] {Q, R};
        }
예제 #12
0
        /// <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(ArrayMatrix col, int j)
        {
            var 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 (var k = 0; k < size; k++) ((ArrayList) Values[k]).Insert(j, col[k + 1]);

            // fill w/ zeros if vector col too short
            for (var k = size; k < RowCount; k++) ((ArrayList) Values[k]).Insert(j, 0);
        }
예제 #13
0
 /// <summary>
 /// Inserts a sub matrix M at row i and column j.
 /// </summary>
 /// <param name="i">One-based row number to insert.</param>
 /// <param name="j">One-based column number to insert.</param>
 /// <param name="M">Sub matrix to insert.</param>
 public void Insert(int i, int j, ArrayMatrix M)
 {
     for (var m = 1; m <= M.RowCount; m++) for (var n = 1; n <= M.ColumnCount; n++) this[i + m - 1, j + n - 1] = M[m, n];
 }
예제 #14
0
        /// <summary>
        /// Performs Hessenberg-Householder reduction, where {H, Q}
        /// is returned, with H Hessenbergian, Q orthogonal and H = Q'AQ.
        /// </summary>
        /// <returns></returns>
        public ArrayMatrix[] HessenbergHouseholder()
        {
            //throw new NotImplementedException("Still buggy!");

            if (!IsSquare())
                throw new InvalidOperationException(
                    "Cannot perform Hessenberg Householder decomposition of non-square matrix.");

            var n = RowCount;
            var Q = Identity(n);
            var H = Clone();
            ArrayMatrix I, N, R, P;
            var vbeta = new ArrayMatrix[2];
            int m;

            // don't try to understand from the code alone.
            // this is pure magic to me - mathematics, reborn as code.
            for (var k = 1; k <= n - 2; k++)
            {
                vbeta = HouseholderVector(H.Extract(k + 1, n, k, k));
                I = Identity(k);
                N = Zeros(k, n - k);

                m = vbeta[0].VectorLength();
                R = Identity(m) - vbeta[1][1, 1]*vbeta[0]*vbeta[0].Transpose();

                H.Insert(k + 1, k, R*H.Extract(k + 1, n, k, n));
                H.Insert(1, k + 1, H.Extract(1, n, k + 1, n)*R);

                P = BlockMatrix(I, N, N.Transpose(), R);

                Q = Q*P;
            }

            return new ArrayMatrix[] {H, Q};
        }
예제 #15
0
        public static ArrayMatrix operator *(Complex x, ArrayMatrix A)
        {
            var B = new ArrayMatrix(A.RowCount, A.ColumnCount);

            for (var i = 1; i <= A.RowCount; i++) for (var j = 1; j <= A.ColumnCount; j++) B[i, j] = A[i, j]*x;

            return B;
        }
예제 #16
0
        /// <summary>
        /// Retrieves row with one-based index i.
        /// </summary>
        /// <param name="i"></param>
        /// <returns>i-th row...</returns>
        public ArrayMatrix Row(int i)
        {
            if (i <= 0 || i > RowCount) throw new ArgumentException("Index exceed matrix dimension.");

            //return (new Matrix((Complex[])((ArrayList)Values[i - 1]).ToArray(typeof(Complex)))).Transpose();

            var buf = new ArrayMatrix(ColumnCount, 1);

            for (var j = 1; j <= ColumnCount; j++) buf[j] = this[i, j];

            return buf;
        }
예제 #17
0
        /// <summary>
        /// Constructs block matrix [A, B; C, D].
        /// </summary>
        /// <param name="A">Upper left sub matrix.</param>
        /// <param name="B">Upper right sub matrix.</param>
        /// <param name="C">Lower left sub matrix.</param>
        /// <param name="D">Lower right sub matrix.</param>
        /// <returns></returns>
        public static ArrayMatrix BlockMatrix(ArrayMatrix A, ArrayMatrix B, ArrayMatrix C, ArrayMatrix D)
        {
            if (A.RowCount != B.RowCount || C.RowCount != D.RowCount
                || A.ColumnCount != C.ColumnCount || B.ColumnCount != D.ColumnCount) throw new ArgumentException("Matrix dimensions must agree.");

            var R = new ArrayMatrix(A.RowCount + C.RowCount, A.ColumnCount + B.ColumnCount);

            for (var i = 1; i <= R.RowCount; i++)
                for (var j = 1; j <= R.ColumnCount; j++)
                    if (i <= A.RowCount)
                        if (j <= A.ColumnCount) R[i, j] = A[i, j];
                        else R[i, j] = B[i, j - A.ColumnCount];
                    else if (j <= C.ColumnCount) R[i, j] = C[i - A.RowCount, j];
                    else R[i, j] = D[i - A.RowCount, j - C.ColumnCount];

            return R;
        }
예제 #18
0
        /// <summary>
        /// Splits matrix into its row vectors.
        /// </summary>
        /// <returns>Array of row vectors.</returns>
        public ArrayMatrix[] RowVectorize()
        {
            var buf = new ArrayMatrix[RowCount];

            for (var i = 1; i <= buf.Length; i++) buf[i] = Row(i);

            return buf;
        }
예제 #19
0
        /// <summary>
        /// Performs depth-first search for a graph given by its adjacence matrix.
        /// </summary>
        /// <param name="adjacence_matrix">A[i,j] = 0 or +infty, if there is no edge from i to j; any non-zero value otherwise.</param>
        /// <param name="root">The vertex to begin the search.</param>
        /// <returns>Adjacence matrix of the computed spanning tree.</returns>
        public static ArrayMatrix DFS(ArrayMatrix adjacence_matrix, int root)
        {
            if (!adjacence_matrix.IsSquare()) throw new ArgumentException("Adjacence matrices are expected to be square.");
            else if (!adjacence_matrix.IsReal()) throw new ArgumentException("Adjacence matrices are expected to be real.");

            var n = adjacence_matrix.RowCount;

            if (root < 1 || root > n) throw new ArgumentException("Root must be a vertex of the graph, e.i. in {1, ..., n}.");

            var spanTree = new ArrayMatrix(n);

            var marked = new bool[n + 1];

            var todo = new Stack();
            todo.Push(root);
            marked[root] = true;

            // adajacence lists for each vertex
            var A = new ArrayList[n + 1];

            for (var i = 1; i <= n; i++)
            {
                A[i] = new ArrayList();

                for (var j = 1; j <= n; j++) if (adjacence_matrix[i, j].Real != 0 && adjacence_matrix[i, j].Imag != double.PositiveInfinity) A[i].Add(j);
            }

            int v, w;

            while (todo.Count > 0)
            {
                v = (int) todo.Peek();

                if (A[v].Count > 0)
                {
                    w = (int) A[v][0];

                    if (!marked[w])
                    {
                        marked[w] = true; // mark w
                        spanTree[v, w].Real = 1; // mark vw
                        todo.Push(w); // one more to search
                    }

                    A[v].RemoveAt(0);
                }
                else todo.Pop();
            }

            return spanTree;
        }
예제 #20
0
        /// <summary>
        /// Solves equation this*x = b via conjugate gradient method.
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        public ArrayMatrix SolveCG(ArrayMatrix b)
        {
            //throw new NotImplementedException("Still buggy!");

            if (!IsSymmetricPositiveDefinite()) throw new InvalidOperationException("CG method only works for spd matrices.");
            else if (!IsReal()) throw new InvalidOperationException("CG method only works for real matrices.");

            var n = RowCount;
            var max_iterations = 150;
            var tolerance = 1e-6;

            var x = Ones(n, 1); // x will contain the solution
            var r = b - this*x; // residual approaches zero as x converges to the solution
            var d = r; // dir = direction of descence
            var delta = r.Norm(); // delta denotes the current error
            delta *= delta;
            tolerance *= tolerance;

            var h = Zeros(n, 1);
            double alpha, gamma;
            double old_delta;

            if (delta <= tolerance) return x;
            else
            {
                for (var i = 0; i < max_iterations; i++)
                {
                    h = this*d;
                    gamma = Dot(h, d).Real;

                    if (Math.Abs(gamma) <= tolerance) return x;

                    alpha = delta/gamma;

                    x += alpha*d; // compute new approximation of solution
                    r -= alpha*h; // compute new residual

                    old_delta = delta; // buffer delta

                    delta = r.Norm();
                    delta *= delta;

                    if (delta <= tolerance) return x;

                    d = r + delta/old_delta*d; // compute new direction of descence
                }

                return x;
            }
        }
예제 #21
0
        /// <summary>
        /// Generates diagonal matrix
        /// </summary>
        /// <param name="diag_vector">column vector containing the diag elements</param>
        /// <returns></returns>
        public static ArrayMatrix Diag(ArrayMatrix diag_vector, int offset)
        {
            var 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.");

            var M = new ArrayMatrix(dim + Math.Abs(offset), dim + Math.Abs(offset));
            dim = M.RowCount;

            if (offset >= 0) for (var i = 1; i <= dim - offset; i++) M[i, i + offset] = diag_vector[i];
            else for (var i = 1; i <= dim + offset; i++) M[i - offset, i] = diag_vector[i];

            return M;
        }
예제 #22
0
        /// <summary>
        /// Swaps each matrix entry A[i, j] with A[j, i].
        /// </summary>
        /// <returns>A transposed matrix.</returns>
        public ArrayMatrix Transpose()
        {
            var M = new ArrayMatrix(ColumnCount, RowCount);

            for (var i = 1; i <= ColumnCount; i++) for (var j = 1; j <= RowCount; j++) M[i, j] = this[j, i];

            return M;
        }
예제 #23
0
        /// <summary>
        /// Computes all shortest distance between any vertices in a given graph.
        /// </summary>
        /// <param name="adjacence_matrix">Square adjacence matrix. The main diagonal
        /// is expected to consist of zeros, any non-existing edges should be marked
        /// positive infinity.</param>
        /// <returns>Two matrices D and P, where D[u,v] holds the distance of the shortest
        /// path between u and v, and P[u,v] holds the shortcut vertex on the way from
        /// u to v.</returns>
        public static ArrayMatrix[] Floyd(ArrayMatrix adjacence_matrix)
        {
            if (!adjacence_matrix.IsSquare()) throw new ArgumentException("Expected square matrix.");
            else if (!adjacence_matrix.IsReal()) throw new ArgumentException("Adjacence matrices are expected to be real.");

            var n = adjacence_matrix.RowCount;

            var D = adjacence_matrix.Clone(); // distance matrix
            var P = new ArrayMatrix(n);

            double buf;

            for (var k = 1; k <= n; k++)
                for (var i = 1; i <= n; i++)
                    for (var j = 1; j <= n; j++)
                    {
                        buf = D[i, k].Real + D[k, j].Real;
                        if (buf < D[i, j].Real)
                        {
                            D[i, j].Real = buf;
                            P[i, j].Real = k;
                        }
                    }

            return new ArrayMatrix[] {D, P};
        }
예제 #24
0
        /// <summary>
        /// Computes the Householder vector.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        static ArrayMatrix[] HouseholderVector(ArrayMatrix x)
        {
            //throw new NotImplementedException("Supposingly buggy!");

            //if (!x.IsReal())
            //    throw new ArgumentException("Cannot compute housholder vector of non-real vector.");

            var n = x.VectorLength();

            if (n == 0) throw new InvalidOperationException("Expected vector as argument.");

            var y = x/x.Norm();
            var buf = y.Extract(2, n, 1, 1);
            var s = Dot(buf, buf);

            var v = Zeros(n, 1);
            v[1] = Complex.One;

            v.Insert(2, 1, buf);

            double beta = 0;

            if (s != 0)
            {
                var mu = Complex.Sqrt(y[1]*y[1] + s);
                if (y[1].Real <= 0) v[1] = y[1] - mu;
                else v[1] = -s/(y[1] + mu);

                beta = 2*v[1].Real*v[1].Real/(s.Real + v[1].Real*v[1].Real);
                v = v/v[1];
            }

            return new ArrayMatrix[] {v, new ArrayMatrix(beta)};
        }
예제 #25
0
        public static ArrayMatrix HorizontalConcat(ArrayMatrix A, ArrayMatrix B)
        {
            var C = A.Row(1);

            for (var i = 2; i <= A.RowCount; i++) C.InsertRow(A.Row(i), i);

            for (var i = 1; i <= B.RowCount; i++) C.InsertRow(B.Row(i), C.RowCount + 1);

            return C;
        }
예제 #26
0
        /// <summary>
        /// Givens product. Internal use for QRGivens.
        /// </summary>
        /// <param name="c"></param>
        /// <param name="s"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        ArrayMatrix GivProd(ArrayMatrix c, ArrayMatrix s, int n)
        {
            var n1 = n - 1;
            var n2 = n - 2;

            var Q = Eye(n);
            Q[n1, n1] = c[n1];
            Q[n, n] = c[n1];
            Q[n1, n] = s[n1];
            Q[n, n1] = -s[n1];

            for (var k = n2; k >= 1; k--)
            {
                var k1 = k + 1;
                Q[k, k] = c[k];
                Q[k1, k] = -s[k];
                var q = Q.Extract(k1, k1, k1, n);
                Q.Insert(k, k1, s[k]*q);
                Q.Insert(k1, k1, c[k]*q);
            }

            return Q;
        }
예제 #27
0
        /// <summary>
        /// Creates n by n matrix filled with ones.
        /// </summary>        
        /// <param name="n">Number of columns.</param>
        /// <returns>n by n matrix filled with ones.</returns>        
        public static ArrayMatrix Ones(int n)
        {
            var M = new ArrayMatrix(n);

            for (var i = 0; i < n; i++) for (var j = 0; j < n; j++) ((ArrayList) M.Values[i])[j] = Complex.One;

            return M;
        }
예제 #28
0
        public static ArrayMatrix operator *(ArrayMatrix A, ArrayMatrix B)
        {
            if (A.ColumnCount != B.RowCount) throw new ArgumentException("Inner matrix dimensions must agree.");

            var C = new ArrayMatrix(A.RowCount, B.ColumnCount);

            for (var i = 1; i <= A.RowCount; i++) for (var j = 1; j <= B.ColumnCount; j++) C[i, j] = Dot(A.Row(i), B.Column(j));

            return C;
        }
예제 #29
0
        /// <summary>
        /// Creates m by n matrix filled with random values in {lo,...,hi-1}.
        /// </summary>
        ///<param name="lo">Inclusive lower bound.</param>
        /// <param name="hi">Exclusive upper bound</param>
        /// <param name="m">Number of rows.</param>
        /// <param name="n">Number of columns.</param>
        /// <returns></returns>
        public static ArrayMatrix Random(int m, int n, int lo, int hi)
        {
            var M = new ArrayMatrix(m, n);
            var r = new Random();

            for (var i = 1; i <= m; i++) for (var j = 1; j <= n; j++) M[i, j] = new Complex((double) r.Next(lo, hi));

            return M;
        }
예제 #30
0
        /// <summary>
        /// Extracts upper trapeze matrix of this matrix.
        /// </summary>
        /// <returns></returns>
        public ArrayMatrix ExtractUpperTrapeze()
        {
            var buf = new ArrayMatrix(RowCount, ColumnCount);

            for (var i = 1; i <= RowCount; i++) for (var j = i; j <= ColumnCount; j++) buf[i, j] = this[i, j];

            return buf;
        }