I'm trying to write a Fortran subroutine to compute a QR factorization using the Householder method. To test my routine, I compute the factorization of the following matrix: $$ A = \begin{pmatrix} 12 & -51 & 4 \\ 6 & 167 & -68 \\ -4 & 24 & -41 \end{pmatrix}, $$ which, if done correctly, will reduce to the following upper triangular matrix: $$ R = \begin{pmatrix} 14 & 21 & -14 \\ 0 & 175 & -70 \\ 0 & 0 & 35 \end{pmatrix}. $$ However, the matrix I actually get is: $$ R = \begin{pmatrix} -14 & -21 & 14 \\ 0 & -175 & 70 \\ -0 & 0 & 35 \end{pmatrix}, $$ which looks almost correct, except for some strange sign changes. I've been staring at my subroutine all day trying to see where these sign changes are being introduced, but I can't identify the problem.
My algorithm is as follows:
$ for \:\: k \:=\: 1\: to\: n $
$ \qquad x(k:m) = A(k:m,k) $
$ \qquad v(k:m) = \mathtt{sign}(x(k))||x(k:m)||_{2}e1 + x(k:m) $
$ \qquad v(k:m) = v(k:m)/||v(k:m)||_{2} $
$ \qquad A(k:m,k:n) = A(k:m,k:n) - 2vv^{\top}A(k:m,k:n) $
To calculate the factor $2vv^{\top}A(k:m,k:n),$ I made another subroutine called outer_product to compute the outer product of $v$ with itself, i.e. $vv^{\top}$, and then matrix multiply the result into my submatrix $A(k:m,k:n)$. However, I'm not sure if this is legitimate - I suspect herein lies the problem.
I would really appreciate it if someone could glance at my code to see if there is any obvious reason for the incorrect sign changes:
integer, parameter :: dp = selected_real_kind(15)
integer, intent(in) :: m, n
real(dp), dimension(m,n), intent(inout) :: A
real(dp), dimension(m,m), intent(out) :: Q
integer :: k
real(dp) :: two_norm
real(dp), dimension(m) :: x, e1
real(dp), dimension(m,n) :: v
real(dp), dimension(m,m) :: outprod_vv
v = 0.0_dp
do k=1,m
Q(k,k) = 1.0_dp
end do
!Householder triangularization
do k=1,n
e1(k) = 1.0_dp
x(k:m) = A(k:m,k)
v(k:m,k) = sign( sqrt(dot_product(x(k:m),x(k:m))), x(k) )* &
e1(k:m) + x(k:m)
v(k:m,k) = v(k:m,k)/(sqrt(dot_product(v(k:m,k),v(k:m,k))))
call outer_product(v(k:m,k), m-k+1, outprod_vv(k:m,k:m))
A(k:m,k:n) = A(k:m,k:n) - &
2.0_dp*matmul(outprod_vv(k:m,k:m), A(k:m,k:n))
!Form Q implicitly
Q(k:m,k:m) = Q(k:m,k:m) - 2.0_dp* &
matmul(outprod_vv(k:m,k:m), Q(k:m,k:m))
end do
Q = transpose(Q)
A quick glance tells me your routine is fine. But more importantly, since QR factorization is not unique, the $R$ your routine outputs is perfectly fine-- it just means that the $Q$ has absorbed a negative. Also, for comparison, the Householder routine in Matlab gives the same $R$ as your Fortran routine.
If you implement the modified Gram-Schmidt (MGS) routine, you will obtain the $R$ you originally sought, since MGS sets the diagonal entries to positive values.
In practice, this difference in sign doesn't make a difference, since one usually cares more about the product $QR$ than about the individual factors.