Mystified by qr.Q(): what is an orthonormal matrix in “compact” form?

后端 未结 2 1562
耶瑟儿~
耶瑟儿~ 2021-01-31 20:09

R has a qr() function, which performs QR decomposition using either LINPACK or LAPACK (in my experience, the latter is 5% faster). The main object returned is a mat

2条回答
  •  感情败类
    2021-01-31 20:47

    Introduction

    R uses the LINPACK dqrdc routine, by default, or the LAPACK DGEQP3 routine, when specified, for computing the QR decomposition. Both routines compute the decomposition using Householder reflections. An m x n matrix A is decomposed into an m x n economy-size orthogonal matrix (Q) and an n x n upper triangular matrix (R) as A = QR, where Q can be computed by the product of t Householder reflection matrices, with t being the lesser of m-1 and n: Q = H1H2...Ht.

    Each reflection matrix Hi can be represented by a length-(m-i+1) vector. For example, H1 requires a length-m vector for compact storage. All but one entry of this vector is placed in the first column of the lower triangle of the input matrix (the diagonal is used by the R factor). Therefore, each reflection needs one more scalar of storage, and this is provided by an auxiliary vector (called $qraux in the result from R's qr).

    The compact representation used is different between the LINPACK and LAPACK routines.

    The LINPACK Way

    A Householder reflection is computed as Hi = I - viviT/pi, where I is the identity matrix, pi is the corresponding entry in $qraux, and vi is as follows:

    • vi[1..i-1] = 0,
    • vi[i] = pi
    • vi[i+1:m] = A[i+1..m, i] (i.e., a column of the lower triangle of A after calling qr)

    LINPACK Example

    Let's work through the example from the QR decomposition article at Wikipedia in R.

    The matrix being decomposed is

    > A <- matrix(c(12, 6, -4, -51, 167, 24, 4, -68, -41), nrow=3)
    > A
         [,1] [,2] [,3]
    [1,]   12  -51    4
    [2,]    6  167  -68
    [3,]   -4   24  -41
    

    We do the decomposition, and the most relevant portions of the result is shown below:

    > Aqr = qr(A)
    > Aqr
    $qr
                [,1]         [,2] [,3]
    [1,] -14.0000000  -21.0000000   14
    [2,]   0.4285714 -175.0000000   70
    [3,]  -0.2857143    0.1107692  -35
    
    [snip...]
    
    $qraux
    [1]  1.857143  1.993846 35.000000
    
    [snip...]
    

    This decomposition was done (under the covers) by computing two Householder reflections and multiplying them by A to get R. We will now recreate the reflections from the information in $qr.

    > p = Aqr$qraux   # for convenience
    > v1 <- matrix(c(p[1], Aqr$qr[2:3,1]))
    > v1
               [,1]
    [1,]  1.8571429
    [2,]  0.4285714
    [3,] -0.2857143
    
    > v2 <- matrix(c(0, p[2], Aqr$qr[3,2]))
    > v2
              [,1]
    [1,] 0.0000000
    [2,] 1.9938462
    [3,] 0.1107692
    
    > I = diag(3)   # identity matrix
    > H1 = I - v1 %*% t(v1)/p[1]   # I - v1*v1^T/p[1]
    > H2 = I - v2 %*% t(v2)/p[2]   # I - v2*v2^T/p[2]
    
    > Q = H1 %*% H2
    > Q
               [,1]       [,2]        [,3]
    [1,] -0.8571429  0.3942857  0.33142857
    [2,] -0.4285714 -0.9028571 -0.03428571
    [3,]  0.2857143 -0.1714286  0.94285714
    

    Now let's verify the Q computed above is correct:

    > qr.Q(Aqr)
               [,1]       [,2]        [,3]
    [1,] -0.8571429  0.3942857  0.33142857
    [2,] -0.4285714 -0.9028571 -0.03428571
    [3,]  0.2857143 -0.1714286  0.94285714
    

    Looks good! We can also verify QR is equal to A.

    > R = qr.R(Aqr)   # extract R from Aqr$qr
    > Q %*% R
         [,1] [,2] [,3]
    [1,]   12  -51    4
    [2,]    6  167  -68
    [3,]   -4   24  -41
    

    The LAPACK Way

    A Householder reflection is computed as Hi = I - piviviT, where I is the identity matrix, pi is the corresponding entry in $qraux, and vi is as follows:

    • vi[1..i-1] = 0,
    • vi[i] = 1
    • vi[i+1:m] = A[i+1..m, i] (i.e., a column of the lower triangle of A after calling qr)

    There is another twist when using the LAPACK routine in R: column pivoting is used, so the decomposition is solving a different, related problem: AP = QR, where P is a permutation matrix.

    LAPACK Example

    This section does the same example as before.

    > A <- matrix(c(12, 6, -4, -51, 167, 24, 4, -68, -41), nrow=3)
    > Bqr = qr(A, LAPACK=TRUE)
    > Bqr
    $qr
                [,1]        [,2]       [,3]
    [1,] 176.2554964 -71.1694118   1.668033
    [2,]  -0.7348557  35.4388886  -2.180855
    [3,]  -0.1056080   0.6859203 -13.728129
    
    [snip...]
    
    $qraux
    [1] 1.289353 1.360094 0.000000
    
    $pivot
    [1] 2 3 1
    
    attr(,"useLAPACK")
    [1] TRUE
    
    [snip...]
    

    Notice the $pivot field; we will come back to that. Now we generate Q from the information the Aqr.

    > p = Bqr$qraux   # for convenience
    > v1 = matrix(c(1, Bqr$qr[2:3,1]))
    > v1
               [,1]
    [1,]  1.0000000
    [2,] -0.7348557
    [3,] -0.1056080
    
    
    > v2 = matrix(c(0, 1, Bqr$qr[3,2]))
    > v2
              [,1]
    [1,] 0.0000000
    [2,] 1.0000000
    [3,] 0.6859203
    
    
    > H1 = I - p[1]*v1 %*% t(v1)   # I - p[1]*v1*v1^T
    > H2 = I - p[2]*v2 %*% t(v2)   # I - p[2]*v2*v2^T
    > Q = H1 %*% H2
               [,1]        [,2]       [,3]
    [1,] -0.2893527 -0.46821615 -0.8348944
    [2,]  0.9474882 -0.01602261 -0.3193891
    [3,]  0.1361660 -0.88346868  0.4482655
    

    Once again, the Q computed above agrees with the R-provided Q.

    > qr.Q(Bqr)
               [,1]        [,2]       [,3]
    [1,] -0.2893527 -0.46821615 -0.8348944
    [2,]  0.9474882 -0.01602261 -0.3193891
    [3,]  0.1361660 -0.88346868  0.4482655
    

    Finally, let's compute QR.

    > R = qr.R(Bqr)
    > Q %*% R
         [,1] [,2] [,3]
    [1,]  -51    4   12
    [2,]  167  -68    6
    [3,]   24  -41   -4
    

    Notice the difference? QR is A with its columns permuted given the order in Bqr$pivot above.

提交回复
热议问题