Skip to content
Snippets Groups Projects
net_m.f90 11.57 KiB
!> Module containing classes representing the whole 
!! neural network.
!!
!! It uses 'neuron_m' module.
!!
!! @author Martin Beseda
!! @date 2018
module net_m
    use data_kinds_4neuro_m
    use time_measurement_m
    use neuron_m
    use connection_m
    use container_m

    implicit none

    public

    !-------------!------------------------------------------------------------------------------
    ! class net_t !
    !-------------!

    type :: container
        class(*), pointer :: content
    end type

    !> Class representing a general network
    type :: net_t
        private

        character(:), allocatable                 :: net_type              !< Type of the net
        integer(kind=integer_4neuro)              :: num_of_neurons        !< Number of neurons in the net
        character(:), allocatable                 :: training_method       !< Used training method

        class(container_t), allocatable           :: neuron_arr(:)         !< Array containing all neurons
        integer(kind=integer_4neuro), allocatable :: input_neuron_arr(:)   !< Array of input neuron indices
        integer(kind=integer_4neuro), allocatable :: output_neuron_arr(:)  !< Array of output neuron indices
        class(connection_t), allocatable          :: connection_arr(:)     !< Array of all connections

    contains
        !> Prints information about the network to the standard output.
        procedure :: print_info => print_info_impl

        !> Saves the network instance to the Fortran binary file
        procedure :: save_net_bin => save_net_bin_impl

        !> Implementation of write function enabling the storage of
        !! allocatable arrays.
        procedure :: write_sample => write_sample_impl

        !> Implementation of read function enabling to read
        !! the whole instance of net_t stored as binary file.
        procedure :: read_sample  => read_sample_impl

        generic   :: write(unformatted) => write_sample
        generic   :: read(unformatted) => read_sample
    end type net_t

    interface net_t
        !> Constructor of net_t class
        !! Loads complete info about network from file
        !! @param[in] filepath Path to the file with network configuration
        !! @return An instance of the class net_t
        module procedure :: new_net_1
    end interface net_t


    !------------------!---------------------------------------------------------------------
    ! class mock_net_t !
    !------------------!

    !> Mock net_t class
    type, extends(net_t) :: mock_net_t
    end type mock_net_t
    
    interface mock_net_t
        !> Non-parametric constructor of mock_net_t class
        !! @return An instance of the class mock_net_t
        module procedure ::  new_mock_net
    end interface mock_net_t

contains
    !------------------------!---------------------------------------------------------------
    ! Method implementations !
    !------------------------!

    !-------------!--------------------------------------------------------------------------
    ! class net_t !
    !-------------!

    !--------------!-------------------------------------------------------------------------
    ! Constructors !
    !--------------!

    !> Constructor of net_t class
    !! Loads complete info about network from Fortran binary file
    !! @param[in] filepath Path to the JSON file with network configuration
    !! @return An instance of the class net_t
    function new_net_1(filepath) result(new_obj)
        character(len=*), intent(in) :: filepath
        type(net_t)                  :: new_obj
        character(len=50)            :: str  !TODO udelat dynamicky, ne s fixni delkou
#ifdef TIME_PROFILING
        real                         :: start_time
        call time_profiling_start(start_time)
#endif
        open(unit=11, file=filepath, form="unformatted", access="stream")
        read(11) new_obj
        close(11)

        print *,new_obj%net_type

        !TODO dopsat
#ifdef TIME_PROFILING
        call time_profiling_stop(start_time, 'new_net')
#endif
    end function new_net_1

    !> Prints information about the network to the standard output.
    subroutine print_info_impl(this)
        class(net_t), intent(in) :: this
#ifdef TIME_PROFILING
        real                     :: start_time
        call time_profiling_start(start_time)
#endif
        write(*,*) '+--------------+'
        write(*,*) '| Network info |'
        write(*,*) '+--------------+'
        write(*,*) 'Type: ', this%net_type
        write(*,*) 'Number of neurons: ', this%num_of_neurons
        !TODO dopsat
#ifdef TIME_PROFILING
        call time_profiling_stop(start_time, 'print_info_impl')
#endif
    end subroutine print_info_impl

    !----------------!-----------------------------------------------------------------------
    ! Common methods !
    !----------------!
    
    !> Saves the network instance to the Fortran binary file
    !! @param[in] filename Name of the file, where the net will be saved into
    subroutine save_net_bin_impl(this, filename)
        class(net_t), intent(in)     :: this      !< Instance of the class 'net_t'
        character(len=*), intent(in) :: filename
#ifdef TIME_PROFILING
        real                         :: start_time
        call time_profiling_start(start_time)
#endif
        open(unit=11, file=filename, form="unformatted", access='stream', position='append')
        write(11) this
        close(unit=11)
#ifdef TIME_PROFILING
        call time_profiling_stop(start_time, 'save_net_bin_impl')
#endif
    end subroutine save_net_bin_impl

    !> Implementation of write function enabling the storage of
    !! allocatable arrays.
    !! @param[in] unit Unit (handler) where the file is written
    !! @param[out] iostat Diagnostic value "returned" by the subroutine
    !! @param[inout] iomsg Explaining note about error
    subroutine write_sample_impl(this, unit, iostat, iomsg)
        class(net_t), intent(in)    :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg
        integer                     :: i !< Counter
#ifdef TIME_PROFILING
        real                        :: start_time
        call time_profiling_start(start_time)
#endif
        ! Write a record giving sizes for the allocation
        write(unit, iostat=iostat, iomsg=iomsg) SIZE(this%neuron_arr), &
                                                SIZE(this%input_neuron_arr), &
                                                SIZE(this%output_neuron_arr), &
                                                SIZE(this%connection_arr)

        select type(tmp => this%neuron_arr)
            type is(container_t)
            select type(tmp2 => this%connection_arr)
                type is(connection_t)
                write(unit, iostat=iostat, iomsg=iomsg) (tmp(i)%content%get_id(), &
                                                         tmp(i)%get_potential(), &
                                                         tmp(i)%get_state(), &
                                                         i=1,SIZE(this%neuron_arr)), &
                                                        this%input_neuron_arr, &
                                                        this%output_neuron_arr, &
                                                        (tmp2(i)%get_input_neuron(), &
                                                         tmp2(i)%get_output_neuron(), &
                                                         tmp2(i)%get_weight(), &
                                                         i=1,SIZE(this%connection_arr))
            end select
        end select
#ifdef TIME_PROFILING
        call time_profiling_stop(start_time, 'write_net_sample')
#endif
    end subroutine write_sample_impl

    ! Unformatted reading for the sample derived type
    subroutine read_sample_impl(this, unit, iostat, iomsg)
        class(net_t), intent(inout) :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg
        integer                     :: i
        integer                     :: s1, s2, s3, s4  !< Sizes of stored allocatable properties
#ifdef TIME_PROFILING
        real                        :: start_time
        call time_profiling_start(start_time)
#endif
        ! We first have a record telling us the sizes of components
        read(unit, iostat=iostat, iomsg=iomsg) s1, s2, s3, s4

        ! So we do the allocation
        allocate(this%neuron_arr(s1), &
                 this%input_neuron_arr(s2), &
                 this%output_neuron_arr(s3), &
                 this%connection_arr(s4))

        ! And then finally the reading.
        select type(tmp => this%neuron_arr)
            type is(container_t)
            select type(tmp2 => this%connection_arr)
                type is(connection_t)
                read(unit, iostat=iostat, iomsg=iomsg) (tmp(i)%id, &
                                                        tmp(i)%potential, &
                                                        tmp(i)%state, &
                                                        i=1, SIZE(this%neuron_arr)), &
                                                       this%input_neuron_arr, &
                                                       this%output_neuron_arr, &
                                                       (tmp2(i)%input_neuron, &
                                                        tmp2(i)%output_neuron, &
                                                        tmp2(i)%weight, &
                                                        i=1, SIZE(this%connection_arr))
            end select
        end select
#ifdef TIME_PROFILING
        call time_profiling_stop(start_time, 'read_net_sample')
#endif
    end subroutine read_sample_impl

    !------------------!---------------------------------------------------------------------
    ! class mock_net_t !
    !------------------!

    !--------------!-------------------------------------------------------------------------
    ! Constructors !
    !--------------!
    
    !> Contructor of mock_net_t class
    !! @return An instance of the class mock_net_t
    function new_mock_net() result(new_obj)
        type(mock_net_t)         :: new_obj
        integer                  :: i !< Counter
        class(neuron_t), pointer :: n_p1, n_p2
        class(neuron_t), pointer :: n_p(:)
        type(mock_neuron_t), target           :: n_tmp
#ifdef TIME_PROFILING
        real             :: start_time
        call time_profiling_start(start_time)
#endif
        new_obj%net_type = 'MOCK NETWORK'
        new_obj%num_of_neurons = 5
        new_obj%training_method = 'MOCK TRAINING'

        ! Init object
        allocate(container_t :: new_obj%neuron_arr(5))
        select type(tmp => new_obj%neuron_arr) 
            type is (container_t)
            do i=1,5
                n_tmp = mock_neuron_t()
                tmp(i) = container_t(n_tmp)
            end do
        end select

        new_obj%input_neuron_arr = (/1, 2/)
        new_obj%output_neuron_arr = (/ 5 /)

        allocate(connection_t :: new_obj%connection_arr(4))
!        n_p => new_obj%neuron_arr
!        new_obj%connection_arr(1) = connection_t(n_p(1), n_p(3))

!        connection_arr_tmp(2)%content => connection_t(neuron_arr_tmp(2)%content, neuron_arr_tmp(4))
!        connection_arr_tmp(3)%content => connection_t(neuron_arr_tmp(3)%content, neuron_arr_tmp(5))
!        connection_arr_tmp(4)%content => connection_t(neuron_arr_tmp(4)%content, neuron_arr_tmp(5))


        !TODO dopsat init zbylych polozek
#ifdef TIME_PROFILING
        call time_profiling_stop(start_time, 'new_mock_net')
#endif
       
    end function new_mock_net
end module net_m