forlab_linalg_qr.f90 Source File


Contents

Source Code


Source Code

submodule(forlab_linalg) forlab_linalg_qr

    implicit none

contains

    module procedure qr_sp
    real(sp), allocatable::v(:)
    integer::i, j, k, m, n, nn, templ
    real(sp)::alpha, t, u
    real(sp), parameter::eps = epsilon(1.0_sp), zero = 0.0_sp, one = 1.0_sp
    m = size(a, 1)
    n = size(a, 2)
    if (m < n) then
        call error_stop("Error:Matrix a dimension m < n ")
    end if
    if (present(l)) then
        templ = l
    else
        templ = 1
    end if
    select case (templ)
    case (1)
        r = a
        allocate (q(m, m))
        q = zero
        r = a
        forall (i=1:m)
            q(i, i) = one
        end forall
        nn = n
        if (m == n) nn = m - 1
        do k = 1, nn
            u = zero
            do i = k, m
                if (abs(r(i, k)) > u) u = abs(r(i, k))
            end do
            alpha = dot_product(r(k:m, k), r(k:m, k))/(u*u)
            if (r(k, k) > 0) u = -u
            alpha = u*sqrt(alpha)
            if (abs(alpha) < eps) then
                call error_stop("Error:matrix r linearly dependent")
            end if
            u = sqrt(2*alpha*(alpha - r(k, k)))
            if (abs(u) > eps) then
                r(k, k) = (r(k, k) - alpha)/u
                r(k + 1:m, k) = r(k + 1:m, k)/u
                do j = 1, m
                    t = dot_product(r(k:m, k), q(k:m, j))
                    q(k:m, j) = q(k:m, j) - 2*r(k:m, k)*t
                end do
                do j = k + 1, n
                    t = dot_product(r(k:m, k), r(k:m, j))
                    r(k:m, j) = r(k:m, j) - 2*r(k:m, k)*t
                end do
                r(k, k) = alpha
                r(k + 1:m, k) = zero
            end if
        end do
        do i = 1, m - 1
            do j = i + 1, m
                t = q(i, j)
                q(i, j) = q(j, i)
                q(j, i) = t
            end do
        end do
    case (2)
        allocate (r(n, n))
        r = zero
        q = a
        v = q(:, 1)
        alpha = norm2(v)
        q(:, 1) = v/alpha
        r(1, 1) = alpha
        do i = 2, n
            v = q(:, i)
            do j = 1, i - 1
                alpha = dot_product(q(:, i), q(:, j))
                v = v - alpha*q(:, j)
                r(j, i) = alpha
            end do
            alpha = norm2(v)
            if (abs(alpha) < eps) then
                call error_stop("Error:Matrix q linearly dependent")
            end if
            q(:, i) = v/alpha
            r(i, i) = alpha
        end do
    case default
        call Error_stop("Error: QR decomposition Type must be 1 or 2")
    end select
    end procedure qr_sp
    module procedure qr_dp
    real(dp), allocatable::v(:)
    integer::i, j, k, m, n, nn, templ
    real(dp)::alpha, t, u
    real(dp), parameter::eps = epsilon(1.0_dp), zero = 0.0_dp, one = 1.0_dp
    m = size(a, 1)
    n = size(a, 2)
    if (m < n) then
        call error_stop("Error:Matrix a dimension m < n ")
    end if
    if (present(l)) then
        templ = l
    else
        templ = 1
    end if
    select case (templ)
    case (1)
        r = a
        allocate (q(m, m))
        q = zero
        r = a
        forall (i=1:m)
            q(i, i) = one
        end forall
        nn = n
        if (m == n) nn = m - 1
        do k = 1, nn
            u = zero
            do i = k, m
                if (abs(r(i, k)) > u) u = abs(r(i, k))
            end do
            alpha = dot_product(r(k:m, k), r(k:m, k))/(u*u)
            if (r(k, k) > 0) u = -u
            alpha = u*sqrt(alpha)
            if (abs(alpha) < eps) then
                call error_stop("Error:matrix r linearly dependent")
            end if
            u = sqrt(2*alpha*(alpha - r(k, k)))
            if (abs(u) > eps) then
                r(k, k) = (r(k, k) - alpha)/u
                r(k + 1:m, k) = r(k + 1:m, k)/u
                do j = 1, m
                    t = dot_product(r(k:m, k), q(k:m, j))
                    q(k:m, j) = q(k:m, j) - 2*r(k:m, k)*t
                end do
                do j = k + 1, n
                    t = dot_product(r(k:m, k), r(k:m, j))
                    r(k:m, j) = r(k:m, j) - 2*r(k:m, k)*t
                end do
                r(k, k) = alpha
                r(k + 1:m, k) = zero
            end if
        end do
        do i = 1, m - 1
            do j = i + 1, m
                t = q(i, j)
                q(i, j) = q(j, i)
                q(j, i) = t
            end do
        end do
    case (2)
        allocate (r(n, n))
        r = zero
        q = a
        v = q(:, 1)
        alpha = norm2(v)
        q(:, 1) = v/alpha
        r(1, 1) = alpha
        do i = 2, n
            v = q(:, i)
            do j = 1, i - 1
                alpha = dot_product(q(:, i), q(:, j))
                v = v - alpha*q(:, j)
                r(j, i) = alpha
            end do
            alpha = norm2(v)
            if (abs(alpha) < eps) then
                call error_stop("Error:Matrix q linearly dependent")
            end if
            q(:, i) = v/alpha
            r(i, i) = alpha
        end do
    case default
        call Error_stop("Error: QR decomposition Type must be 1 or 2")
    end select
    end procedure qr_dp

end submodule forlab_linalg_qr