forsvd.f90 Source File


Files dependent on this one

sourcefile~~forsvd.f90~~AfferentGraph sourcefile~forsvd.f90 forsvd.f90 sourcefile~benchmark.f90 benchmark.f90 sourcefile~benchmark.f90->sourcefile~forsvd.f90 sourcefile~test1.f90 test1.f90 sourcefile~test1.f90->sourcefile~forsvd.f90 sourcefile~test2.f90 test2.f90 sourcefile~test2.f90->sourcefile~forsvd.f90 sourcefile~test3.f90 test3.f90 sourcefile~test3.f90->sourcefile~forsvd.f90 sourcefile~test4.f90 test4.f90 sourcefile~test4.f90->sourcefile~forsvd.f90 sourcefile~test5.f90 test5.f90 sourcefile~test5.f90->sourcefile~forsvd.f90

Source Code

module forsvd

   ! This module provides functions and subroutines
   ! for calculating the singular value decomposition (SVD).

   use kinds

   implicit none

   private

   public :: svd, tsvd, pixel

   !===============================================================================
   type :: tsvd
      real(rk), dimension(:,:), allocatable :: matrix
      real(rk), dimension(:,:), allocatable :: matrix_app
      integer                               :: nrow, ncol
      integer                               :: rank
   contains
      procedure :: lowrank
      procedure :: dlloc => deallocate_tsvd
   end type tsvd
   !===============================================================================


   !===============================================================================
   type :: pixel
      character(256)                        :: image_name
      character(256)                        :: file_name
      real(rk), dimension(:,:), allocatable :: pixels
      real(rk), dimension(:,:), allocatable :: pixels_app
      integer                               :: nrow, ncol
      integer                               :: rank
   contains
      procedure :: image_to_pixels ! TODO:
      procedure :: load_pixels
      procedure :: compress_pixels
      procedure :: save_pixels
      procedure :: pixels_to_image  ! TODO:
      procedure :: dlloc => deallocate_pixel
   end type pixel
   !===============================================================================


   !===============================================================================
   interface svd
      procedure :: svd_rel ! Interface for the svd_rel subroutine
   end interface
   !===============================================================================

contains

   !===============================================================================
   !> author: Seyed Ali Ghasemi
   !> Calculates the singular value decomposition (SVD) of a matrix A.
   pure subroutine svd_rel(A, U,S,VT, method)

      ! Inputs:
      real(rk), dimension(:, :), contiguous, intent(in)  :: A    ! Input matrix A

      ! Outputs:
      real(rk), dimension(:,:), intent(out) :: U    ! Left singular vectors
      real(rk), dimension(:,:), intent(out) :: VT   ! Right singular vectors
      real(rk), dimension(:),   intent(out) :: S    ! Singular values

      character(*), intent(in), optional :: method

      if (.not. present(method)) then
         call gesvd_rel(A, U,S,VT)
      else

         select case (method)
            case ('gesvd')
            call gesvd_rel(A, U,S,VT)
            case( 'gesdd')
            call gesdd_rel(A, U,S,VT)
         end select

      end if

   end subroutine svd_rel
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   !> Calculates the singular value decomposition (SVD) of a matrix A.
   pure subroutine gesvd_rel(A, U,S,VT)

      ! Inputs:
      real(rk), dimension(:, :), contiguous,          intent(in)  :: A    ! Input matrix A

      ! Outputs:
      real(rk), dimension(:,:), intent(out) :: U    ! Left singular vectors
      real(rk), dimension(:,:), intent(out) :: VT   ! Right singular vectors
      real(rk), dimension(:),   intent(out) :: S    ! Singular values

      ! Local variables
      real(rk)                                                    :: work1(1) ! memory allocation query
      real(rk), dimension(:), allocatable                         :: work     ! Work array
      integer                                                     :: m, n, lwork, info

      ! External subroutine for calculating the SVD
      interface dgesvd
         pure subroutine dgesvd(jobuf,jobvtf,mf,nf,af,ldaf,sf,uf,lduf,vtf,ldvtf,workf,lworkf,infof)
            use kinds
            character, intent(in)  :: jobuf, jobvtf
            integer,   intent(in)  :: mf, nf, ldaf, lduf, ldvtf, lworkf
            real(rk),  intent(in)  :: Af(ldaf, *)
            real(rk),  intent(out) :: Sf(min(mf, nf))
            real(rk),  intent(out) :: Uf(lduf, *), VTf(ldvtf, *)
            real(rk),  intent(out) :: workf(*)
            integer,   intent(out) :: infof
         end subroutine dgesvd
      end interface

      m = size(A, 1)
      n = size(A, 2)

      ! Calculate the optimal size of the work array
      call dgesvd('S', 'S', m, n, A, m, S, U, m, VT, n, work1, -1, info)
      lwork = nint(work1(1))
      allocate(work(lwork))

      call dgesvd('S', 'S', m, n, A, m, S, U, m, VT, n, work, lwork, info)

      deallocate(work)
   end subroutine gesvd_rel
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   !> Calculates the singular value decomposition (SVD) of a matrix A.
   pure subroutine gesdd_rel(A, U, S, VT)

      ! Inputs:
      real(rk), dimension(:, :), contiguous,          intent(in)  :: A    ! Input matrix A

      ! Outputs:
      real(rk), dimension(:,:), intent(out) :: U    ! Left singular vectors
      real(rk), dimension(:,:), intent(out) :: VT   ! Right singular vectors
      real(rk), dimension(:),   intent(out) :: S    ! Singular values

      ! Local variables
      real(rk) :: work1(1) ! memory allocation query
      real(rk), dimension(:), allocatable :: work     ! Work array
      integer :: m, n, lwork, info
      integer, dimension(:), allocatable :: iwork     ! Integer work array

      ! External subroutine for calculating the SVD
      interface dgesdd
         pure subroutine dgesdd(f_jobz, f_m, f_n, f_a, f_lda, f_s, f_u, f_ldu, f_vt, f_ldvt, f_work, f_lwork, f_iwork, f_info)
            use kinds
            character,                       intent(in)    :: f_jobz
            integer,                         intent(in)    :: f_m, f_n, f_lda, f_ldu, f_ldvt, f_lwork
            real(rk),  dimension(f_lda, *),  intent(in)    :: f_a
            real(rk),  dimension(*),         intent(out)   :: f_s
            real(rk),  dimension(f_ldu, *),  intent(out)   :: f_u
            real(rk),  dimension(f_ldvt, *), intent(out)   :: f_vt
            real(rk),  dimension(*),         intent(out)   :: f_work
            integer,   dimension(*),         intent(out)   :: f_iwork
            integer,                         intent(out)   :: f_info
         end subroutine dgesdd
      end interface

      m = size(A, 1)
      n = size(A, 2)

      allocate(iwork(n * 8)) ! Adjust the size as needed

      ! Calculate the optimal size of the work array
      call dgesdd('S', m, n, A, m, S, U, m, VT, n, work1, -1, iwork, info)
      lwork = nint(work1(1))
      allocate(work(lwork))

      call dgesdd('S', m, n, A, m, S, U, m, VT, n, work, lwork, iwork, info)

      deallocate(work)
      deallocate(iwork)
   end subroutine gesdd_rel
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   pure subroutine lowrank(this, matrix, rank, method)
      class(tsvd),  intent(inout)            :: this
      real(rk), dimension(:, :), intent(in)  :: matrix
      integer,      intent(in)               :: rank
      character(*), intent(in), optional     :: method
      real(rk), dimension(:, :), allocatable :: U, VT
      real(rk), dimension(:),    allocatable :: S
      integer                                :: i, j, irank

      this%matrix = matrix
      this%nrow   = size(matrix,1)
      this%ncol   = size(matrix,2)
      this%rank   = rank

      allocate(U(this%nrow,this%nrow), S(min(this%nrow,this%ncol)), VT(this%ncol,this%ncol))

      call svd(this%matrix, U,S,VT, method)

      allocate(this%matrix_app(this%nrow,this%ncol))
      this%matrix_app = 0.0_rk
      do irank = 1, rank
         do j = 1,this%ncol
            do i = 1,this%nrow
               this%matrix_app(i,j) = this%matrix_app(i,j) + U(i, irank)*S(irank)*VT(irank, j)
            end do
         end do
      end do

   end subroutine lowrank
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   ! TODO:
   impure subroutine image_to_pixels(this, image_name, file_name)
      class(pixel), intent(inout) :: this
      character(*), intent(in)    :: image_name
      character(*), intent(in)    :: file_name
      integer :: i, nunit

      call execute_command_line('python pixel/image_to_pixels.py')

   end subroutine image_to_pixels
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   ! TODO:
   impure subroutine pixels_to_image(this, file_name, image_name)
      class(pixel), intent(inout) :: this
      character(*), intent(in)    :: file_name
      character(*), intent(in)    :: image_name
      integer :: i, nunit

      call execute_command_line('python pixel/pixels_to_image.py')

   end subroutine pixels_to_image
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   impure subroutine load_pixels(this, file_name)
      class(pixel), intent(inout) :: this
      character(*), intent(in) :: file_name
      integer :: i, nunit

      allocate(this%pixels(this%nrow,this%ncol))

      open(newunit=nunit, file=trim(file_name), status='old')
      do i = 1, this%nrow
         read(nunit, *) this%pixels(i, :)
      end do
      close(nunit)

   end subroutine load_pixels
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   pure subroutine compress_pixels(this, rank, method)
      class(pixel), intent(inout)            :: this
      integer,      intent(in)               :: rank
      character(*), intent(in), optional     :: method
      type(tsvd)                             :: mat

      call mat%lowrank(this%pixels, rank, method)
      this%pixels_app = mat%matrix_app

   end subroutine compress_pixels
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   impure subroutine save_pixels(this, file_name)
      class(pixel), intent(inout) :: this
      character(*), intent(in) :: file_name
      integer :: i, nunit

      open(newunit=nunit, file=trim(file_name))
      do i = 1, this%nrow
         write(nunit, *) this%pixels_app(i, :)
      end do
      close(nunit)

   end subroutine save_pixels
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   elemental pure subroutine deallocate_pixel(this)
      class(pixel), intent(inout) :: this
      if (allocated(this%pixels)) deallocate(this%pixels)
      if (allocated(this%pixels_app)) deallocate(this%pixels_app)
   end subroutine deallocate_pixel
   !===============================================================================


   !===============================================================================
   !> author: Seyed Ali Ghasemi
   elemental pure subroutine deallocate_tsvd(this)
      class(tsvd), intent(inout) :: this
      if (allocated(this%matrix)) deallocate(this%matrix)
      if (allocated(this%matrix_app)) deallocate(this%matrix_app)
   end subroutine deallocate_tsvd
   !===============================================================================

end module forsvd