ReinforcementLearning.f90 Source File


Source Code

!
!//////////////////////////////////////////////////////
!
!      Module containing classes and subroutines for Reinforcement Learning
!      Currently implemented:
!        * p-Adaptation agent based on Value Iteration.
!
!////////////////////////////////////////////////////////////////////////
!

module ReinforcementLearning

    implicit none

    private 

    public pAdaptationAgent_t

    type, abstract :: MatrixND_t
        contains
            procedure(MatrixND_ConstructInterface), deferred :: MatrixND_Construct
            generic :: construct => MatrixND_Construct
            procedure(MatrixND_DestructInterface), deferred :: MatrixND_Destruct
            generic :: destruct  => MatrixND_Destruct
            procedure(MatrixND_LoadInterface), deferred :: MatrixND_Load
            generic :: load  => MatrixND_Load
            procedure(MatrixND_GetDataInterface), deferred :: MatrixND_GetData
            generic :: getData  => MatrixND_GetData
    end type MatrixND_t

    type, extends(MatrixND_t) :: Matrix2D_t
        integer(kind=1), allocatable :: data(:,:)
        contains
            procedure :: MatrixND_Construct => Matrix2D_Construct
            procedure :: MatrixND_Destruct  => Matrix2D_Destruct
            procedure :: MatrixND_Load      => Matrix2D_Load
            procedure :: MatrixND_GetData   => Matrix2D_GetData
    end type Matrix2D_t

    type, extends(MatrixND_t) :: Matrix3D_t
        integer(kind=1), allocatable :: data(:,:,:)
        contains
            procedure :: MatrixND_Construct => Matrix3D_Construct
            procedure :: MatrixND_Destruct  => Matrix3D_Destruct
            procedure :: MatrixND_Load      => Matrix3D_Load
            procedure :: MatrixND_GetData   => Matrix3D_GetData
    end type Matrix3D_t

    type, extends(MatrixND_t) :: Matrix4D_t
        integer(kind=1), allocatable :: data(:,:,:,:)
        contains
            procedure :: MatrixND_Construct => Matrix4D_Construct
            procedure :: MatrixND_Destruct  => Matrix4D_Destruct
            procedure :: MatrixND_Load      => Matrix4D_Load
            procedure :: MatrixND_GetData   => Matrix4D_GetData
    end type Matrix4D_t

    type, extends(MatrixND_t) :: Matrix5D_t
        integer(kind=1), allocatable :: data(:,:,:,:,:)
        contains
            procedure :: MatrixND_Construct => Matrix5D_Construct
            procedure :: MatrixND_Destruct  => Matrix5D_Destruct
            procedure :: MatrixND_Load      => Matrix5D_Load
            procedure :: MatrixND_GetData   => Matrix5D_GetData
    end type Matrix5D_t

    type, extends(MatrixND_t) :: Matrix6D_t
        integer(kind=1), allocatable :: data(:,:,:,:,:,:)
        contains
            procedure :: MatrixND_Construct => Matrix6D_Construct
            procedure :: MatrixND_Destruct  => Matrix6D_Destruct
            procedure :: MatrixND_Load      => Matrix6D_Load
            procedure :: MatrixND_GetData   => Matrix6D_GetData
    end type Matrix6D_t

    type, extends(MatrixND_t) :: Matrix7D_t
        integer(kind=1), allocatable :: data(:,:,:,:,:,:,:)
        contains
            procedure :: MatrixND_Construct => Matrix7D_Construct
            procedure :: MatrixND_Destruct  => Matrix7D_Destruct
            procedure :: MatrixND_Load      => Matrix7D_Load
            procedure :: MatrixND_GetData   => Matrix7D_GetData
    end type Matrix7D_t

    type :: adaptiveArray_t
        class(MatrixND_t), allocatable :: matrix
    end type adaptiveArray_t

    type :: pAdaptationAgent_t
        integer                            :: smax      ! Maximum value of the state
        integer                            :: pmin      ! Minimum polynomial order
        integer                            :: pmax      ! Maximum polynomial order
        type(adaptiveArray_t), allocatable :: policy(:) ! Policy
        contains
            procedure :: construct => pAdaptationAgent_Construct
            procedure :: destruct => pAdaptationAgent_Destruct
    end type pAdaptationAgent_t

    !  ------------------------------------------
!  Interface for constructing the MatrixND classs
!  ----------------------------------------------
   interface
   subroutine MatrixND_ConstructInterface(self, Npoints)
      import MatrixND_t
      !-------------------------------------------------
      implicit none
      !-------------------------------------------------
      class(MatrixND_t) , intent(inout) :: self   
      integer           , intent(in)    :: Npoints      
   end subroutine MatrixND_ConstructInterface
   end interface

!  --------------------------------------------
!  Interface for destructing the MatrixND class
!  --------------------------------------------
   interface
   subroutine MatrixND_DestructInterface(self)
      import MatrixND_t
      !--------------------------------------
      implicit none
      !--------------------------------------
      class(MatrixND_t) , intent(inout) :: self
   end subroutine MatrixND_DestructInterface
   end interface

!  -----------------------------------------------------------
!  Interface for loading the MatrixND class from a binary file
!  -----------------------------------------------------------
   interface
   subroutine MatrixND_LoadInterface(self, agentFile)
      import MatrixND_t
      !--------------------------------------
      implicit none
      !--------------------------------------
      class(MatrixND_t) , intent(inout) :: self
      character(len=*)  , intent(in)    :: agentFile
   end subroutine MatrixND_LoadInterface
   end interface

!  -------------------------------------------------------
!  Interface for retrieving the data from a MatrixND class
!  -------------------------------------------------------
   interface
   function MatrixND_GetDataInterface(self, indices) result(val)
      import MatrixND_t
      !--------------------------------------
      implicit none
      !--------------------------------------
      class(MatrixND_t)     , intent(in)    :: self
      integer               , intent(in)    :: indices(:)
      integer(kind=1)                       :: val
   end function MatrixND_GetDataInterface
   end interface

    !========
    contains
    !========
    !
    !///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    !
    !  -------------------------------------------
    !  Routine for constructing the MatrixND class
    !  -------------------------------------------
    subroutine Matrix2D_Construct(self, Npoints)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix2D_t), intent(inout) :: self
        integer          , intent(in)    :: Npoints
        !----------------------------------------------------
        allocate(self % data(Npoints,Npoints))
    end subroutine Matrix2D_Construct

    subroutine Matrix3D_Construct(self, Npoints)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix3D_t), intent(inout) :: self
        integer          , intent(in)    :: Npoints
        !----------------------------------------------------
        allocate(self % data(Npoints,Npoints,Npoints))
    end subroutine Matrix3D_Construct

    subroutine Matrix4D_Construct(self, Npoints)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix4D_t), intent(inout) :: self
        integer          , intent(in)    :: Npoints
        !----------------------------------------------------
        allocate(self % data(Npoints,Npoints,Npoints,Npoints))
    end subroutine Matrix4D_Construct

    subroutine Matrix5D_Construct(self, Npoints)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix5D_t), intent(inout) :: self
        integer          , intent(in)    :: Npoints
        !----------------------------------------------------
        allocate(self % data(Npoints,Npoints,Npoints,Npoints,Npoints))
    end subroutine Matrix5D_Construct

    subroutine Matrix6D_Construct(self, Npoints)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix6D_t), intent(inout) :: self
        integer          , intent(in)    :: Npoints
        !----------------------------------------------------
        allocate(self % data(Npoints,Npoints,Npoints,Npoints,Npoints,Npoints))
    end subroutine Matrix6D_Construct

    subroutine Matrix7D_Construct(self, Npoints)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix7D_t), intent(inout) :: self
        integer          , intent(in)    :: Npoints
        !----------------------------------------------------
        allocate(self % data(Npoints,Npoints,Npoints,Npoints,Npoints,Npoints,Npoints))
    end subroutine Matrix7D_Construct
    !
    !///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    !
    !  -------------------------------------------
    !  Routine for destructing the MatrixNd class
    !  -------------------------------------------
    subroutine Matrix2D_Destruct(self)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix2D_t), intent(inout) :: self
        !----------------------------------------------------
        deallocate(self % data)
    end subroutine Matrix2D_Destruct

    subroutine Matrix3D_Destruct(self)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix3D_t), intent(inout) :: self
        !----------------------------------------------------
        deallocate(self % data)
    end subroutine Matrix3D_Destruct

    subroutine Matrix4D_Destruct(self)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix4D_t), intent(inout) :: self
        !----------------------------------------------------
        deallocate(self % data)
    end subroutine Matrix4D_Destruct

    subroutine Matrix5D_Destruct(self)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix5D_t), intent(inout) :: self
        !----------------------------------------------------
        deallocate(self % data)
    end subroutine Matrix5D_Destruct

    subroutine Matrix6D_Destruct(self)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix6D_t), intent(inout) :: self
        !----------------------------------------------------
        deallocate(self % data)
    end subroutine Matrix6D_Destruct

    subroutine Matrix7D_Destruct(self)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix7D_t), intent(inout) :: self
        !----------------------------------------------------
        deallocate(self % data)
    end subroutine Matrix7D_Destruct
    !
    !///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    !
    !  ---------------------------------------------------------
    !  Routine for loading the MatrixNd class from a binary file
    !  ---------------------------------------------------------
    subroutine Matrix2D_Load(self, agentFile)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix2D_t), intent(inout)  :: self
        character(len=*)  , intent(in)    :: agentFile
        !----------------------------------------------------
        integer :: fd
        !----------------------------------------------------
        open(newunit = fd, FILE = agentFile//"_p1.bin", form="unformatted", action="read", status="old", access='stream') 
        read(fd) self % data
        close(UNIT=fd)
    end subroutine Matrix2D_Load

    subroutine Matrix3D_Load(self, agentFile)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix3D_t), intent(inout)  :: self
        character(len=*)  , intent(in)    :: agentFile
        !----------------------------------------------------
        integer :: fd
        !----------------------------------------------------
        open(newunit = fd, FILE = agentFile//"_p2.bin", form="unformatted", action="read", status="old", access='stream') 
        read(fd) self % data
        close(UNIT=fd)
    end subroutine Matrix3D_Load

    subroutine Matrix4D_Load(self, agentFile)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix4D_t), intent(inout)  :: self
        character(len=*)  , intent(in)    :: agentFile
        !----------------------------------------------------
        integer :: fd
        !----------------------------------------------------
        open(newunit = fd, FILE = agentFile//"_p3.bin", form="unformatted", action="read", status="old", access='stream') 
        read(fd) self % data
        close(UNIT=fd)
    end subroutine Matrix4D_Load

    subroutine Matrix5D_Load(self, agentFile)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix5D_t), intent(inout)  :: self
        character(len=*)  , intent(in)    :: agentFile
        !----------------------------------------------------
        integer :: fd
        !----------------------------------------------------
        open(newunit = fd, FILE = agentFile//"_p4.bin", form="unformatted", action="read", status="old", access='stream') 
        read(fd) self % data
        close(UNIT=fd)
    end subroutine Matrix5D_Load

    subroutine Matrix6D_Load(self, agentFile)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix6D_t), intent(inout)  :: self
        character(len=*)  , intent(in)    :: agentFile
        !----------------------------------------------------
        integer :: fd
        !----------------------------------------------------
        open(newunit = fd, FILE = agentFile//"_p5.bin", form="unformatted", action="read", status="old", access='stream') 
        read(fd) self % data
        close(UNIT=fd)
    end subroutine Matrix6D_Load

    subroutine Matrix7D_Load(self, agentFile)
        implicit none
        !-arguments-------------------------------------------
        class(Matrix7D_t), intent(inout)  :: self
        character(len=*)  , intent(in)    :: agentFile
        !----------------------------------------------------
        integer :: fd
        !----------------------------------------------------
        open(newunit = fd, FILE = agentFile//"_p6.bin", form="unformatted", action="read", status="old", access='stream') 
        read(fd) self % data
        close(UNIT=fd)
    end subroutine Matrix7D_Load
    !
    !///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    !
    !  -------------------------------------------------------
    !  Routine for retrieving the data from the MatrixNd class
    !  -------------------------------------------------------
    function Matrix2D_GetData(self, indices) result(val)
        !--------------------------------------
        implicit none
        !--------------------------------------
        class(Matrix2D_t)     , intent(in)    :: self
        integer               , intent(in)    :: indices(:)
        integer(kind=1)                       :: val
        !--------------------------------------
        val = self % data(indices(1), indices(2))
    end function Matrix2D_GetData

    function Matrix3D_GetData(self, indices) result(val)
        !--------------------------------------
        implicit none
        !--------------------------------------
        class(Matrix3D_t)     , intent(in)    :: self
        integer               , intent(in)    :: indices(:)
        integer(kind=1)                       :: val
        !--------------------------------------
        val = self % data(indices(1), indices(2), indices(3))
    end function Matrix3D_GetData

    function Matrix4D_GetData(self, indices) result(val)
        !--------------------------------------
        implicit none
        !--------------------------------------
        class(Matrix4D_t)     , intent(in)    :: self
        integer               , intent(in)    :: indices(:)
        integer(kind=1)                       :: val
        !--------------------------------------
        val = self % data(indices(1), indices(2), indices(3), indices(4))
    end function Matrix4D_GetData

    function Matrix5D_GetData(self, indices) result(val)
        !--------------------------------------
        implicit none
        !--------------------------------------
        class(Matrix5D_t)     , intent(in)    :: self
        integer               , intent(in)    :: indices(:)
        integer(kind=1)                       :: val
        !--------------------------------------
        val = self % data(indices(1), indices(2), indices(3), indices(4), indices(5))
    end function Matrix5D_GetData

    function Matrix6D_GetData(self, indices) result(val)
        !--------------------------------------
        implicit none
        !--------------------------------------
        class(Matrix6D_t)     , intent(in)    :: self
        integer               , intent(in)    :: indices(:)
        integer(kind=1)                       :: val
        !--------------------------------------
        val = self % data(indices(1), indices(2), indices(3), indices(4), indices(5), indices(6))
    end function Matrix6D_GetData

    function Matrix7D_GetData(self, indices) result(val)
        !--------------------------------------
        implicit none
        !--------------------------------------
        class(Matrix7D_t)     , intent(in)    :: self
        integer               , intent(in)    :: indices(:)
        integer(kind=1)                       :: val
        !--------------------------------------
        val = self % data(indices(1), indices(2), indices(3), indices(4), indices(5), indices(6), indices(7))
    end function Matrix7D_GetData

    !
    !///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    !
    !  ----------------------------------------
    !  Routine for constructing the p-adaptator
    !  ----------------------------------------
    subroutine pAdaptationAgent_Construct(self, agentFile)
        use, intrinsic :: iso_fortran_env
        implicit none
        !-arguments-------------------------------------------
        class(pAdaptationAgent_t), intent(inout) :: self
        character(len=*)         , intent(in)    :: agentFile
        !-local variables-------------------------------------
        integer          :: fd, NPoints, policySize, i, j, k, p, header, indices3(3), indices2(2)
        !----------------------------------------------------
        open(newunit = fd, FILE = agentFile//".bin", form="unformatted", action="read", status="old", access='stream')   
            READ(fd) NPoints, header
            self % smax = NPoints / 2
            READ(fd) self % pmin, header
            READ(fd) self % pmax, header
        close(UNIT=fd)
        
        policySize = self % pmax - self % pmin + 1
        allocate(self % policy(policySize))
        do i = 1, policySize
            p = self % pmin + i - 1
            if (p == 1) then
                allocate(Matrix2D_t::self % policy(i) % matrix)
            else if (p == 2) then
                allocate(Matrix3D_t::self % policy(i) % matrix)
            else if (p == 3) then
                allocate(Matrix4D_t::self % policy(i) % matrix)
            else if (p == 4) then
                allocate(Matrix5D_t::self % policy(i) % matrix)
            else if (p == 5) then
                allocate(Matrix6D_t::self % policy(i) % matrix)
            else if (p == 6) then
                allocate(Matrix7D_t::self % policy(i) % matrix)
            else 
                error stop 'The maximum polynomial order is 6 for p-adaptation with Value Iteration RL'
            end if
            call self % policy(i) % matrix % construct(NPoints)

            ! Read the policy from the file
            call self % policy(i) % matrix % load(agentFile)
        enddo

    end subroutine pAdaptationAgent_Construct
    !
    !///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    !
    !  ----------------------------------------
    !  Routine for destructing the p-adaptator
    !  ----------------------------------------
    subroutine pAdaptationAgent_Destruct(self)
        implicit none
        !-arguments-------------------------------------------
        class(pAdaptationAgent_t), intent(inout) :: self
        !-local variables-------------------------------------
        integer :: policySize, i
        !----------------------------------------------------     
        policySize = self % pmax - self % pmin + 1
        do i = 1, policySize
            call self % policy(i) % matrix % destruct()
        enddo

        deallocate(self % policy)

    end subroutine pAdaptationAgent_Destruct

end module ReinforcementLearning