1 Problem Set 1

1.1 Item 1: Show that a matrix and its transpose don’t commute in general

We begin by demonstrating that \[A^{T}A \neq AA^T\] by considering a small 2x2 counterexample.

Let \(A\) be the matrix \[A = \left[ \begin{array}{rr} 0 & 0 \\ 1 & 2 \end{array} \right] \text{ and } A^T = \left[ \begin{array}{rr} 0 & 1 \\ 0 & 2 \\ \end{array} \right]\]

We now compute the product of the matrix with its transpose in both orders.

\[ A \cdot A^T = \left[ \begin{array}{rr} 0 & 0 \\ 0 & 5 \end{array} \right] \text{ while the other product gives } A^T \cdot A = \left[ \begin{array}{rr} 1 & 2 \\ 2 & 4 \end{array} \right] \]

This is sufficient to prove that a matrix and its transpose don’t commute by finding one counterexample.

1.2 Item 2: When could a matrix and its transpose commute?

The following numerical experiment shows that a randomly chosen matrix does not commute with its transpose. I conduct an experiment by measuring the set of \(n=1000\) randomly generated 2 by 2 matrices where entries are chosen independently from a uniform \([0,1]\) interval distribution.

I then measure the norm of its commuter matrix defined as: \[ comm(A) = A \cdot A^T - A^T \cdot A\] Clearly A commutes with its transpose iff \[||comm(A)|| = 0\]. As a control, I check if the matrix A is also invertible.

## [1] "Which random 2x2 matrices are commute with their transpose? "
## 
## FALSE 
##  1000 
## [1] "Which random 2x2 matrices are invertible? "
## 
## TRUE 
## 1000

The above findings show that a random matrix does not commute with its transpose but is invertible.

A few standard categories of matrices do commute with their transposes:

  1. symmetric matrices
  2. orthogonal matrices - those where the rows and columns are orthogonal unit vectors

According to wikipedia, the spectral theorem solves the problem of matrices which commute with their transpose. It states that a matrix is normal iff it is unitarily similar to a diagonal matrix. However, that theorem is stated in terms of its conjugate transpose \(A^*\). [https://en.wikipedia.org/wiki/Normal_matrix] However we have not studied the spectral theorem yet.

2 Problem Set 2

In this exercise, I present an R function that calculates an LU decomposition of a real-valued matrix. The algorithm chosen was called Doolittle’s algorithm and found online in multiple locations. After implementing the algorithm as an R function, I write a test harness to allow multiple test cases to be validated. Afterwards, I show that multiple test cases can be correctly replicated within the test harness. Finally, I conclude by showing a corner case of a 2x2 matrix where no LU decomposition exists.

2.1 Explaining Doolittle’s Algorithm for LU Decomposition

The best exposition of the algorithm that was implementable in R was: [https://www3.nd.edu/~zxu2/acms40390F11/Alg-LU-Crout.pdf]
This exposition used indices from 1 to \(n\) in contrast to expositions in Wikipedia which used \(0\)-based index notation for the algorithm. I found some typos in exposition which are corrected below.

The R code directly reflects the notation in this section which serves as documentation for the R.

\[ A = \left[ \begin{array}{rrrr} a_{11} & a_{12} & ... & a_{1n} \\ a_{21} & a_{22} & ... & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{n1} & a_{n2} & \cdots & a_{nn} \end{array} \right] = LU = \left[ \begin{array}{rrrr} 1 & 0 & \cdots & 0 \\ l_{21} & 1 & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ l_{n1} & l_{n2} & \cdots & 1 \end{array} \right] \left[ \begin{array}{rrrr} u_{11} & u_{12} & \cdots & u_{1n} \\ 0 & u_{22} & \cdots & u_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & u_{nn} \end{array} \right] \] Each entry \(a_{ij}\) is associated with the product of two vectors \(L[i,]\) and \(U[,j]\) which defines an equation in terms of the desired variables which need to be solved. The key idea is that by choosing the correct order in which \(a_{ij}\) are examined, the equations are solvable in terms of previously solved quantities.

The strategy of Doolittle’s algorithm is to start by solving for the first row of the \(U\) matrix by using the associated equations from the first row of \(A\). Then solving for the first column of the \(L\) matrix which is only dependent on the entry \(u_{11}\). The iterative step is to solve the variables in the \(i\)-th row of U and then the \(i\)-th column of L. The final step is to solve for \(u_{nn}\) in terms of previously derived variables.

Thus, the key formulas for the first step are:

\[ \begin{align} u_{1j} = a_{1j} && j = 1,2, \cdots, n &&\text{the first row of U} \\ && && \\ l_{j1} = \frac{a_{j1}}{u_{11}} && j = 2, \cdots ,n && \text{the first column of L} \\ \end{align} \] In the above, note that the \(u_{11}\) must be solved before solving \(l_{j1}\).

The next steps are solving the interior variables along the \(i\)-th row of \(U\) and the \(i\)-th column of \(L\).

\[ \begin{align} \text{for i = 2, 3, } \cdots n-1 && && && \text{ calculate the following terms} \\ u_{ii} && = && a_{ii} - \sum_{t=1}^{i-1} l_{it}u_{ti} && \text{solve the diagonal term} \\ u_{ij} && = && a_{ij} - \sum_{t=1}^{i-1} l_{it}u_{tj} && \text{for } j = i+1, \cdots , n \text{ i-th row of U} \\ l_{ji} && = && \frac{a_{ji} - \sum_{t=1}^{i-1} l_{jt}u_{ti} }{u_{ii}} && \text{for } j = i+1, \cdots , n \text{ i-th column of L} \\ \end{align} \]

Lastly, we have to solve for the right bottom corner variable of the \(U\) matrix:

\[ u_{nn} = a_{nn} - \sum_{t=1}^{n-1} l_{nt}u_{tn} \]

In the next section, I code this logic in R.

2.2 Implementing Doolittle’s algorithm

The code implementing Doolittle’s algorithm is shown below.

# FUNCTION: DoolittleLUAlgo
#
# PURPOSE:  Calculate the Lower and Upper Triangular decomposition of a square
#           matrix in R using the Dolittle Algorithm described above.
#
# INPUT:    A matrix object with equal rows and columns.  Matrix must be non-empty.
#           Values must be real numbers.
#
# OUTPUTS:  A list of 3 objects:
#
#               Element 1: the number of rows in the the square matrix. 
#               Element 2: The lower triangular matrix L for input A
#               Element 3: The upper triangular matrix U for input A
#
#           Note that L * U = (input matrix) A
# ----------------------------------------------------------------------------------
DoolittleLUAlgo <- function(A )
{
    n = nrow(A)  # the input argument must   
    L = matrix(rep(0,n*n), nrow = n)
    U = matrix(rep(0,n*n), nrow = n)
    
    # Set up first row of Upper triangular matrix
    # Set up the first column of the 
    for(j in 1:n)
    {
        U[1,j] = A[1,j]
        L[j,1] = A[j,1]/U[1,1]
        L[j,j] = 1
    }
    
    i = 2
    while( i < n )
    {
        sum_i = 0
        t = 1
        while( t < i )
        {
            sum_i = sum_i  + L[i,t]*U[t,i]
            t = t + 1
        }
        
        # Define the main diagonal entry of U in row i
        # ----------------------------------------------
        U[i,i] = A[i,i] - sum_i 
        
        sum_i = 0
        j = i + 1
        
        # Define the U entries of row i 
        # (to the right side of the main diagonal)
        # -----------------------------------------------
        while( j <= n)
        {
            sum_i = 0
            for(t in 1:(i-1) )
            {
                sum_i = sum_i + L[i,t] * U[t,j]
            }
            U[i,j] = A[i,j] - sum_i
            j = j + 1
        }
        
        # Define the L entries of column i 
        # (below the main diagonal of row)
        # -------------------------------------------
        j = i + 1
        
        while( j <= n)
        {        
          sum_i = 0
          
           for(t in 1:(i-1))
           {
              sum_i = sum_i + L[j,t] * U[t, i]
           }
           L[j, i ] = (A[j, i ] - sum_i ) / U[i, i]
           j = j + 1
        }
        i = i + 1
    }    
    # Final corner U[n,n]
    # ---------------------------------------------------
    sum_i = 0
    t = 1
    
    while(t < n)
    {
        sum_i = sum_i + L[n, t] * U[ t, n]
        t = t + 1
    }    
    U[n,n] = A[n,n] - sum_i
 
    # Return the row count, lower matrix L, upper matrix M
    # -------------------------------------------------------
    retList = list(n, L, U )    
}

2.4 Test Cases

We develop 5 test cases ordered by dimension of the matrix \(A\) from \(dim(A) = 1, 2, 3, 4\). All test cases have known solutions and the examples below when run using my R function all pass the tests.

## [1] "solveAndValidateTestCase for Test Case 1: 1x1 (Trivial) "
## [1] " Dimensions: 1"
## [1] " Lower triangular matrix is: "
##      [,1]
## [1,]    1
## [1] " Does L matches initial guess? TRUE"
## [1] "  Upper triangular matrix is: "
##      [,1]
## [1,]    9
## [1] "  Does U matches initial guess? TRUE"
## [1] " Does the solution work? Does A equal L %*% U ? TRUE"
##      [,1]
## [1,]    9
## [1] "------------------------------------------------------"
## [1] "solveAndValidateTestCase for  Test Case 2 (2x2) "
## [1] " Dimensions: 2"
## [1] " Lower triangular matrix is: "
##          [,1] [,2]
## [1,] 1.000000    0
## [2,] 1.333333    1
## [1] " Does L matches initial guess? TRUE"
## [1] "  Upper triangular matrix is: "
##      [,1]      [,2]
## [1,]    3 1.0000000
## [2,]    0 0.6666667
## [1] "  Does U matches initial guess? TRUE"
## [1] " Does the solution work? Does A equal L %*% U ? TRUE"
##      [,1] [,2]
## [1,]    3    1
## [2,]    4    2
## [1] "------------------------------------------------------"
## [1] "solveAndValidateTestCase for Test Case 3 (3x3) "
## [1] " Dimensions: 3"
## [1] " Lower triangular matrix is: "
##      [,1] [,2] [,3]
## [1,]    1 0.00    0
## [2,]    4 1.00    0
## [3,]    5 1.25    1
## [1] " Does L matches initial guess? TRUE"
## [1] "  Upper triangular matrix is: "
##      [,1] [,2] [,3]
## [1,]    1    0    1
## [2,]    0    4    0
## [3,]    0    0   -1
## [1] "  Does U matches initial guess? TRUE"
## [1] " Does the solution work? Does A equal L %*% U ? TRUE"
##      [,1] [,2] [,3]
## [1,]    1    0    1
## [2,]    4    4    4
## [3,]    5    5    4
## [1] "------------------------------------------------------"
## [1] "solveAndValidateTestCase for Test Case 4 (3x3)"
## [1] " Dimensions: 3"
## [1] " Lower triangular matrix is: "
##      [,1] [,2] [,3]
## [1,]    1 0.00    0
## [2,]    4 1.00    0
## [3,]    5 1.25    1
## [1] " Does L matches initial guess? TRUE"
## [1] "  Upper triangular matrix is: "
##      [,1] [,2] [,3]
## [1,]    1    0    1
## [2,]    0    4    0
## [3,]    0    0   -1
## [1] "  Does U matches initial guess? TRUE"
## [1] " Does the solution work? Does A equal L %*% U ? TRUE"
##      [,1] [,2] [,3]
## [1,]    1    0    1
## [2,]    4    4    4
## [3,]    5    5    4
## [1] "------------------------------------------------------"
## [1] "solveAndValidateTestCase for Test Case 5 (4x4)"
## [1] " Dimensions: 4"
## [1] " Lower triangular matrix is: "
##      [,1] [,2] [,3] [,4]
## [1,]    1    0    0    0
## [2,]    2    1    0    0
## [3,]    4    3    1    0
## [4,]    3    4    1    1
## [1] " Does L matches initial guess? TRUE"
## [1] "  Upper triangular matrix is: "
##      [,1] [,2] [,3] [,4]
## [1,]    2    1    1    0
## [2,]    0    1    1    1
## [3,]    0    0    2    2
## [4,]    0    0    0    2
## [1] "  Does U matches initial guess? TRUE"
## [1] " Does the solution work? Does A equal L %*% U ? TRUE"
##      [,1] [,2] [,3] [,4]
## [1,]    2    1    1    0
## [2,]    4    3    3    1
## [3,]    8    7    9    5
## [4,]    6    7    9    8
## [1] "------------------------------------------------------"

2.5 Corner Cases

Necessary and sufficient conditions for the existence of an LU factorization are now known. It was solved in a 1997 paper by Johnson and Okunev. [https://arxiv.org/pdf/math/0506382v1.pdf] The paper gives a well known example of a matrix with no LU factorization. The simplest example is:

\[ A = \left[ \begin{array}{rr} 0 & 1 \\ 1 & 0 \end{array} \right] = LU = \left[ \begin{array}{rr} 1 & 0 \\ l_{21} & 1 \end{array} \right] \left[ \begin{array}{rr} u_{11} & u_{12} \\ 0 & u_{22} \end{array} \right] \] The reason is simple. Obviously \(0 = a_{11} = l_{11}u_{11} = 1 \cdot u_{11}\). This implies \(u_{11} = 0\). Which implies \(U\) is singular since it has a zero column. However, \(A\) is invertible which is a contradiction.

The following test cases has no solution. We set \(U\) equal to the identify matrix. We set \(L\) to some plausible 2x2 matrix.

## [1] "solveAndValidateTestCase for  Corner Case with no solution (2x2) "
## [1] " Dimensions: 2"
## [1] " Lower triangular matrix is: "
##      [,1] [,2]
## [1,]    1    0
## [2,]  Inf    1
## [1] " Does L matches initial guess? FALSE"
## [1] "  Upper triangular matrix is: "
##      [,1] [,2]
## [1,]    0    1
## [2,]    0 -Inf
## [1] "  Does U matches initial guess? FALSE"
## [1] " Does the solution work? Does A equal L %*% U ? NA"
##      [,1] [,2]
## [1,]    0  NaN
## [2,]  NaN  NaN
## [1] "------------------------------------------------------"

Clearly, the above example will cause the code to produce a nonsense answer as the matrix entries are NaN and Inf. This is easily solved by permuting the rows of \(A\) to obtain the identity matrix.

Clearly, LU decomposition may require permutation of rows or columns to allow a solution.