qrsolv Subroutine

public subroutine qrsolv(n, r, Ldr, Ipvt, Diag, Qtb, x, Sdiag, Wa)

given an m by n matrix a, an n by n diagonal matrix d, and an m-vector b, the problem is to determine an x which solves the system

        a*x = b ,     d*x = 0 ,

in the least squares sense.

this subroutine completes the solution of the problem if it is provided with the necessary information from the qr factorization, with column pivoting, of a. that is, if ap = qr, where p is a permutation matrix, q has orthogonal columns, and r is an upper triangular matrix with diagonal elements of nonincreasing magnitude, then qrsolv expects the full upper triangle of r, the permutation matrix p, and the first n components of (q transpose)b. the system ax = b, d*x = 0, is then equivalent to

               t       t
        r*z = q *b ,  p *d*p*z = 0 ,

where x = p*z. if this system does not have full rank, then a least squares solution is obtained. on output qrsolv also provides an upper triangular matrix s such that

         t   t               t
        p *(a *a + d*d)*p = s *s .

s is computed within qrsolv and may be of separate interest.

Arguments

TypeIntentOptionalAttributesName
integer, intent(in) :: n

a positive integer input variable set to the order of r.

real(kind=wp), intent(inout) :: r(Ldr,n)

an n by n array. on input the full upper triangle must contain the full upper triangle of the matrix r. on output the full upper triangle is unaltered, and the strict lower triangle contains the strict upper triangle (transposed) of the upper triangular matrix s.

integer, intent(in) :: Ldr

a positive integer input variable not less than n which specifies the leading dimension of the array r.

integer, intent(in) :: Ipvt(n)

an integer input array of length n which defines the permutation matrix p such that ap = qr. column j of p is column ipvt(j) of the identity matrix.

real(kind=wp), intent(in) :: Diag(n)

an input array of length n which must contain the diagonal elements of the matrix d.

real(kind=wp), intent(in) :: Qtb(n)

an input array of length n which must contain the first n elements of the vector (q transpose)*b.

real(kind=wp), intent(out) :: x(n)

an output array of length n which contains the least squares solution of the system ax = b, dx = 0.

real(kind=wp), intent(out) :: Sdiag(n)

an output array of length n which contains the diagonal elements of the upper triangular matrix s.

real(kind=wp), intent(inout) :: Wa(n)

a work array of length n.


Called by

proc~~qrsolv~~CalledByGraph proc~qrsolv qrsolv proc~lmpar lmpar proc~lmpar->proc~qrsolv proc~lmdif lmdif proc~lmdif->proc~lmpar proc~lmder lmder proc~lmder->proc~lmpar proc~lmstr lmstr proc~lmstr->proc~lmpar proc~minpack_lmdif minpack_lmdif proc~minpack_lmdif->proc~lmdif proc~lmstr1 lmstr1 proc~lmstr1->proc~lmstr proc~minpack_lmstr minpack_lmstr proc~minpack_lmstr->proc~lmstr proc~minpack_lmder minpack_lmder proc~minpack_lmder->proc~lmder proc~lmdif1 lmdif1 proc~lmdif1->proc~lmdif proc~lmder1 lmder1 proc~lmder1->proc~lmder proc~minpack_lmder1 minpack_lmder1 proc~minpack_lmder1->proc~lmder1 proc~minpack_lmstr1 minpack_lmstr1 proc~minpack_lmstr1->proc~lmstr1 proc~minpack_lmdif1 minpack_lmdif1 proc~minpack_lmdif1->proc~lmdif1

Contents

Source Code


Source Code

    subroutine qrsolv(n, r, Ldr, Ipvt, Diag, Qtb, x, Sdiag, Wa)
        implicit none

        integer, intent(in) :: n !! a positive integer input variable set to the order of r.
        integer, intent(in) :: Ldr !! a positive integer input variable not less than n
                                  !! which specifies the leading dimension of the array r.
        integer, intent(in) :: Ipvt(n) !! an integer input array of length n which defines the
                                      !! permutation matrix p such that a*p = q*r. column j of p
                                      !! is column ipvt(j) of the identity matrix.
        real(wp), intent(inout) :: r(Ldr, n) !! an n by n array. on input the full upper triangle
                                            !! must contain the full upper triangle of the matrix r.
                                            !! on output the full upper triangle is unaltered, and the
                                            !! strict lower triangle contains the strict upper triangle
                                            !! (transposed) of the upper triangular matrix s.
        real(wp), intent(in) :: Diag(n) !! an input array of length n which must contain the
                                       !! diagonal elements of the matrix d.
        real(wp), intent(in) :: Qtb(n) !! an input array of length n which must contain the first
                                      !! n elements of the vector (q transpose)*b.
        real(wp), intent(out) :: x(n) !! an output array of length n which contains the least
                                     !! squares solution of the system a*x = b, d*x = 0.
        real(wp), intent(out) :: Sdiag(n) !! an output array of length n which contains the
                                         !! diagonal elements of the upper triangular matrix s.
        real(wp), intent(inout) :: Wa(n) !! a work array of length n.

        integer :: i, j, jp1, k, kp1, l, nsing
        real(wp) :: cos, cotan, qtbpj, sin, sum, tan, temp

        real(wp), parameter :: p5 = 5.0e-1_wp
        real(wp), parameter :: p25 = 2.5e-1_wp

        ! copy r and (q transpose)*b to preserve input and initialize s.
        ! in particular, save the diagonal elements of r in x.

        do j = 1, n
            do i = j, n
                r(i, j) = r(j, i)
            end do
            x(j) = r(j, j)
            Wa(j) = Qtb(j)
        end do

        ! eliminate the diagonal matrix d using a givens rotation.

        do j = 1, n

            ! prepare the row of d to be eliminated, locating the
            ! diagonal element using p from the qr factorization.

            l = Ipvt(j)
            if (Diag(l) /= zero) then
                do k = j, n
                    Sdiag(k) = zero
                end do
                Sdiag(j) = Diag(l)

                ! the transformations to eliminate the row of d
                ! modify only a single element of (q transpose)*b
                ! beyond the first n, which is initially zero.

                qtbpj = zero
                do k = j, n

                    ! determine a givens rotation which eliminates the
                    ! appropriate element in the current row of d.

                    if (Sdiag(k) /= zero) then
                        if (abs(r(k, k)) >= abs(Sdiag(k))) then
                            tan = Sdiag(k)/r(k, k)
                            cos = p5/sqrt(p25 + p25*tan**2)
                            sin = cos*tan
                        else
                            cotan = r(k, k)/Sdiag(k)
                            sin = p5/sqrt(p25 + p25*cotan**2)
                            cos = sin*cotan
                        end if

                        ! compute the modified diagonal element of r and
                        ! the modified element of ((q transpose)*b,0).

                        r(k, k) = cos*r(k, k) + sin*Sdiag(k)
                        temp = cos*Wa(k) + sin*qtbpj
                        qtbpj = -sin*Wa(k) + cos*qtbpj
                        Wa(k) = temp

                        ! accumulate the tranformation in the row of s.

                        kp1 = k + 1
                        if (n >= kp1) then
                            do i = kp1, n
                                temp = cos*r(i, k) + sin*Sdiag(i)
                                Sdiag(i) = -sin*r(i, k) + cos*Sdiag(i)
                                r(i, k) = temp
                            end do
                        end if
                    end if
                end do
            end if

            ! store the diagonal element of s and restore
            ! the corresponding diagonal element of r.

            Sdiag(j) = r(j, j)
            r(j, j) = x(j)
        end do

        ! solve the triangular system for z. if the system is
        ! singular, then obtain a least squares solution.

        nsing = n
        do j = 1, n
            if (Sdiag(j) == zero .and. nsing == n) nsing = j - 1
            if (nsing < n) Wa(j) = zero
        end do
        if (nsing >= 1) then
            do k = 1, nsing
                j = nsing - k + 1
                sum = zero
                jp1 = j + 1
                if (nsing >= jp1) then
                    do i = jp1, nsing
                        sum = sum + r(i, j)*Wa(i)
                    end do
                end if
                Wa(j) = (Wa(j) - sum)/Sdiag(j)
            end do
        end if

        ! permute the components of z back to components of x.

        do j = 1, n
            l = Ipvt(j)
            x(l) = Wa(j)
        end do

    end subroutine qrsolv