dlsi Subroutine

private subroutine dlsi(w, mdw, ma, mg, n, prgopt, x, rnorm, mode, ws, ip)

This is a companion subprogram to DLSEI. The documentation for DLSEI has complete usage instructions.

Solve:

    AX = B,  A  MA by N  (least squares equations)

subject to:

    GX>=H, G  MG by N  (inequality constraints)

Revision history

  • 790701 DATE WRITTEN. Hanson, R. J., (SNLA)
  • 890531 Changed all specific intrinsics to generic. (WRB)
  • 890618 Completely restructured and extensively revised (WRB & RWC)
  • 891214 Prologue converted to Version 4.0 format. (BAB)
  • 900328 Added TYPE section. (WRB)
  • 900604 DP version created from SP version. (RWC)
  • 920422 Changed CALL to DHFTI to include variable MA. (WRB)

Arguments

Type IntentOptional Attributes Name
real(kind=wp) :: w(mdw,*)

W(*,*) contains:

 (A B)
 (G H)

in rows 1,...,MA+MG, cols 1,...,N+1.

integer, intent(in) :: mdw

contain (resp) var. dimension of W(*,*), and matrix dimensions.

integer, intent(in) :: ma

contain (resp) var. dimension of W(*,*), and matrix dimensions.

integer, intent(in) :: mg

contain (resp) var. dimension of W(*,*), and matrix dimensions.

integer, intent(in) :: n

contain (resp) var. dimension of W(*,*), and matrix dimensions.

real(kind=wp), intent(in) :: prgopt(*)

Program option vector.

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

Solution vector(unless MODE=2)

real(kind=wp), intent(out) :: rnorm

length of AX-B.

integer, intent(out) :: mode
  • =0 Inequality constraints are compatible.
  • =2 Inequality constraints contradictory.
real(kind=wp) :: ws(*)

Working storage of dimension K+N+(MG+2)*(N+7), where K=MAX(MA+MG,N).

integer :: ip(*)

IP(MG+2*N+1) Integer working storage


Calls

proc~~dlsi~~CallsGraph proc~dlsi bspline_defc_module::dlsi proc~dasum bspline_blas_module::dasum proc~dlsi->proc~dasum proc~daxpy bspline_blas_module::daxpy proc~dlsi->proc~daxpy proc~dcopy bspline_blas_module::dcopy proc~dlsi->proc~dcopy proc~ddot bspline_blas_module::ddot proc~dlsi->proc~ddot proc~dh12 bspline_defc_module::dh12 proc~dlsi->proc~dh12 proc~dhfti bspline_defc_module::dhfti proc~dlsi->proc~dhfti proc~dlpdp bspline_defc_module::dlpdp proc~dlsi->proc~dlpdp proc~dscal bspline_blas_module::dscal proc~dlsi->proc~dscal proc~dswap bspline_blas_module::dswap proc~dlsi->proc~dswap proc~dh12->proc~daxpy proc~dh12->proc~ddot proc~dh12->proc~dswap proc~dhfti->proc~dh12 proc~dlpdp->proc~dcopy proc~dlpdp->proc~ddot proc~dlpdp->proc~dscal proc~dnrm2 bspline_blas_module::dnrm2 proc~dlpdp->proc~dnrm2 proc~dwnnls bspline_defc_module::dwnnls proc~dlpdp->proc~dwnnls proc~dwnlsm bspline_defc_module::dwnlsm proc~dwnnls->proc~dwnlsm proc~dwnlsm->proc~dasum proc~dwnlsm->proc~daxpy proc~dwnlsm->proc~dcopy proc~dwnlsm->proc~dh12 proc~dwnlsm->proc~dscal proc~dwnlsm->proc~dswap proc~dwnlsm->proc~dnrm2 proc~drotm bspline_blas_module::drotm proc~dwnlsm->proc~drotm proc~drotmg bspline_blas_module::drotmg proc~dwnlsm->proc~drotmg proc~dwnlit bspline_defc_module::dwnlit proc~dwnlsm->proc~dwnlit proc~idamax bspline_blas_module::idamax proc~dwnlsm->proc~idamax proc~dwnlit->proc~dcopy proc~dwnlit->proc~dh12 proc~dwnlit->proc~dscal proc~dwnlit->proc~dswap proc~dwnlit->proc~drotm proc~dwnlit->proc~drotmg proc~dwnlit->proc~idamax proc~dwnlt1 bspline_defc_module::dwnlt1 proc~dwnlit->proc~dwnlt1 proc~dwnlt2 bspline_defc_module::dwnlt2 proc~dwnlit->proc~dwnlt2 proc~dwnlt3 bspline_defc_module::dwnlt3 proc~dwnlit->proc~dwnlt3 proc~dwnlt1->proc~idamax proc~dwnlt3->proc~dswap

Called by

proc~~dlsi~~CalledByGraph proc~dlsi bspline_defc_module::dlsi proc~dlsei bspline_defc_module::dlsei proc~dlsei->proc~dlsi proc~dfcmn bspline_defc_module::dfcmn proc~dfcmn->proc~dlsei proc~dfc bspline_defc_module::dfc proc~dfc->proc~dfcmn

Source Code

   subroutine dlsi (w, mdw, ma, mg, n, prgopt, x, rnorm, mode, ws, ip)

   integer,intent(in) :: mdw !! contain (resp) var. dimension of `W(*,*)`, and matrix dimensions.
   integer,intent(in) :: ma  !! contain (resp) var. dimension of `W(*,*)`, and matrix dimensions.
   integer,intent(in) :: mg  !! contain (resp) var. dimension of `W(*,*)`, and matrix dimensions.
   integer,intent(in) :: n   !! contain (resp) var. dimension of `W(*,*)`, and matrix dimensions.
   real(wp) :: w(mdw,*) !! `W(*,*)` contains:
                        !!
                        !!```
                        !! (A B)
                        !! (G H)
                        !!```
                        !!
                        !! in rows `1,...,MA+MG`,
                        !! cols `1,...,N+1`.
   real(wp),intent(in) :: prgopt(*) !! Program option vector.
   real(wp),intent(out) :: x(*) !! Solution vector(unless MODE=2)
   real(wp),intent(out) :: rnorm !! length of AX-B.
   integer,intent(out) :: mode !! * `=0`   Inequality constraints are compatible.
                               !! * `=2`   Inequality constraints contradictory.
   real(wp) :: ws(*) !! Working storage of dimension `K+N+(MG+2)*(N+7)`,
                     !! where `K=MAX(MA+MG,N)`.
   integer :: ip(*) !! `IP(MG+2*N+1)` Integer working storage

   real(wp) :: anorm, fac, gam, rb, tau, tol, xnorm
   integer :: i, j, k, key, krank, krm1, krp1, l, last, link, m, map1, &
              mdlpdp, minman, n1, n2, n3, next, np1
   logical :: cov, sclcov
   real(wp) :: rnorm_(1) !! JW added for call to [[dhfti]]

   ! Set the nominal tolerance used in the code.
   tol = sqrt(drelpr)

   mode = 0
   rnorm = 0.0_wp
   m = ma + mg
   np1 = n + 1
   krank = 0

   main : block

      if (n<=0 .or. m<=0) exit main

      ! To process option vector.

      cov = .false.
      sclcov = .true.
      last = 1
      link = prgopt(1)

      do
         if (link<=1) exit
         key = prgopt(last+1)
         if (key==1) cov = prgopt(last+2) /= 0.0_wp
         if (key==10) sclcov = prgopt(last+2) == 0.0_wp
         if (key==5) tol = max(drelpr,prgopt(last+2))
         next = prgopt(link)
         last = link
         link = next
      end do

      ! Compute matrix norm of least squares equations.

      anorm = 0.0_wp
      do j = 1,n
         anorm = max(anorm,dasum(ma,w(1,j),1))
      end do

      ! Set tolerance for DHFTI( ) rank test.

      tau = tol*anorm

      ! Compute Householder orthogonal decomposition of matrix.

      call dcopy (n, [0.0_wp], 0, ws, 1)
      call dcopy (ma, w(1, np1), 1, ws, 1)
      k = max(m,n)
      minman = min(ma,n)
      n1 = k + 1
      n2 = n1 + n
      rnorm_(1) = rnorm ! JW
      call dhfti (w, mdw, ma, n, ws, ma, 1, tau, krank, rnorm_, ws(n2), &
                  ws(n1), ip)
      rnorm = rnorm_(1) ! JW
      fac = 1.0_wp
      gam = ma - krank
      if (krank<ma .and. sclcov) fac = rnorm**2/gam

      ! Reduce to DLPDP and solve.

      map1 = ma + 1

      ! Compute inequality rt-hand side for DLPDP.

      if (ma<m) then
         if (minman>0) then
            do i = map1,m
               w(i,np1) = w(i,np1) - ddot(n,w(i,1),mdw,ws,1)
            end do

            ! Apply permutations to col. of inequality constraint matrix.

            do i = 1,minman
               call dswap (mg, w(map1,i), 1, w(map1,ip(i)), 1)
            end do

            ! Apply Householder transformations to constraint matrix.

            if (krank>0 .and. krank<n) then
               do i = krank,1,-1
                  call dh12 (2, i, krank+1, n, w(i,1), mdw, ws(n1+i-1), &
                           w(map1,1), mdw, 1, mg)
               end do
            endif

            ! Compute permuted inequality constraint matrix times r-inv.

            do i = map1,m
               do j = 1,krank
                  w(i,j) = (w(i,j)-ddot(j-1,w(1,j),1,w(i,1),mdw))/w(j,j)
               end do
         end do
         endif

         ! Solve the reduced problem with DLPDP algorithm,
         ! the least projected distance problem.

         call dlpdp(w(map1,1), mdw, mg, krank, n-krank, prgopt, x, &
                  xnorm, mdlpdp, ws(n2), ip(n+1))

         ! Compute solution in original coordinates.

         if (mdlpdp==1) then
            do i = krank,1,-1
               x(i) = (x(i)-ddot(krank-i,w(i,i+1),mdw,x(i+1),1))/w(i,i)
            end do

            ! Apply Householder transformation to solution vector.

            if (krank<n) then
               do i = 1,krank
                  call dh12 (2, i, krank+1, n, w(i,1), mdw, ws(n1+i-1), &
                           x, 1, 1, 1)
               end do
            endif

            ! Repermute variables to their input order.

            if (minman>0) then
               do i = minman,1,-1
                  call dswap (1, x(i), 1, x(ip(i)), 1)
               end do

               ! Variables are now in original coordinates.
               ! Add solution of unconstrained problem.

               do i = 1,n
                  x(i) = x(i) + ws(i)
               end do

               ! Compute the residual vector norm.

               rnorm = sqrt(rnorm**2+xnorm**2)
            endif
         else
            mode = 2
         endif
      else
         call dcopy (n, ws, 1, x, 1)
      endif

      ! Compute covariance matrix based on the orthogonal decomposition
      ! from DHFTI( ).

      if (.not.cov .or. krank<=0) exit main
      krm1 = krank - 1
      krp1 = krank + 1

      ! Copy diagonal terms to working array.

      call dcopy (krank, w, mdw+1, ws(n2), 1)

      ! Reciprocate diagonal terms.

      do j = 1,krank
         w(j,j) = 1.0_wp/w(j,j)
      end do

      ! Invert the upper triangular QR factor on itself.

      if (krank>1) then
         do i = 1,krm1
            do j = i+1,krank
               w(i,j) = -ddot(j-i,w(i,i),mdw,w(i,j),1)*w(j,j)
            end do
         end do
      endif

      ! Compute the inverted factor times its transpose.

      do i = 1,krank
         do j = i,krank
            w(i,j) = ddot(krank+1-j,w(i,j),mdw,w(j,j),mdw)
         end do
      end do

      ! Zero out lower trapezoidal part.
      ! Copy upper triangular to lower triangular part.

      if (krank<n) then
         do j = 1,krank
            call dcopy (j, w(1,j), 1, w(j,1), mdw)
         end do

         do i = krp1,n
            call dcopy (i, [0.0_wp], 0, w(i,1), mdw)
         end do

         ! Apply right side transformations to lower triangle.

         n3 = n2 + krp1
         do i = 1,krank
            l = n1 + i
            k = n2 + i
            rb = ws(l-1)*ws(k-1)

            ! If RB>=0.0_wp, transformation can be regarded as zero.

            if (rb<0.0_wp) then
               rb = 1.0_wp/rb

               ! Store unscaled rank one Householder update in work array.

               call dcopy (n, [0.0_wp], 0, ws(n3), 1)
               l = n1 + i
               k = n3 + i
               ws(k-1) = ws(l-1)

               do j = krp1,n
                  ws(n3+j-1) = w(i,j)
               end do

               do j = 1,n
                  ws(j) = rb*(ddot(j-i,w(j,i),mdw,ws(n3+i-1),1)+ &
                        ddot(n-j+1,w(j,j),1,ws(n3+j-1),1))
               end do

               l = n3 + i
               gam = 0.5_wp*rb*ddot(n-i+1,ws(l-1),1,ws(i),1)
               call daxpy (n-i+1, gam, ws(l-1), 1, ws(i), 1)
               do j = i,n
                  do l = 1,i-1
                     w(j,l) = w(j,l) + ws(n3+j-1)*ws(l)
                  end do
                  do l = i,j
                     w(j,l) = w(j,l) + ws(j)*ws(n3+l-1)+ws(l)*ws(n3+j-1)
                  end do
               end do
            endif
         end do

         ! Copy lower triangle to upper triangle to symmetrize the
         ! covariance matrix.

         do i = 1,n
            call dcopy (i, w(i,1), mdw, w(1,i), 1)
         end do
      endif

      ! Repermute rows and columns.

      do i = minman,1,-1
         k = ip(i)
         if (i/=k) then
            call dswap (1, w(i,i), 1, w(k,k), 1)
            call dswap (i-1, w(1,i), 1, w(1,k), 1)
            call dswap (k-i-1, w(i,i+1), mdw, w(i+1,k), 1)
            call dswap (n-k, w(i, k+1), mdw, w(k, k+1), mdw)
         endif
      end do

      ! Put in normalized residual sum of squares scale factor
      ! and symmetrize the resulting covariance matrix.

      do j = 1,n
         call dscal (j, fac, w(1,j), 1)
         call dcopy (j, w(1,j), 1, w(j,1), mdw)
      end do

   end block main

   ip(1) = krank
   ip(2) = n + max(m,n) + (mg+2)*(n+7)

   end subroutine dlsi