GAClass.f90 Source File


Contents

Source Code


Source Code

module GAClass
    use RandomClass
    use ArrayClass
    use MathClass
    implicit none

    type :: GA_annotaton
        character(:),allocatable :: annotation
    end type

    type :: GA_Individual_
        real(real64),allocatable  :: realParameter(:)
        integer(int32),allocatable:: intParameter(:)
        type(GA_annotaton),allocatable :: realAnnotaton(:)
        type(GA_annotaton),allocatable :: intAnnotaton(:)
        logical,allocatable :: realRegistered(:) 
        logical,allocatable :: intRegistered(:)  
    contains
        procedure,public :: init => initGA_Individual
    end type

    type :: GA_
        type(GA_Individual_),allocatable :: plants(:)
        real(real64),allocatable :: score(:)
        integer(int32),allocatable :: selected(:)
        real(real64),allocatable :: selectedScore(:)
        integer(int32) :: num_individual
        logical :: initialized = .false.
        logical :: registered = .false.
        logical :: realRegistered = .false.
        logical :: intRegistered  = .false.  
    contains
        procedure, public :: init => initGA
        procedure, public :: setup => setupGA 
        procedure, public :: show => showGA
        procedure, public :: parse => parseGA
        procedure, public :: select => selectGA
        procedure, public :: cross => crossGA
        procedure, public :: mutate => mutateGA
    end type
contains

! #################################################################
subroutine initGA_Individual(obj,num_real,num_int)
    class(GA_Individual_),intent(inout) :: obj
    integer(int32),intent(in) :: num_real,num_int
    
    if(num_real/=0)then
        obj%realParameter = zeros(num_real)
        allocate(obj%realAnnotaton(num_real) )
        allocate(obj%realRegistered(num_real) )
        obj%realRegistered(:) = .false.
    endif
    

    if(num_int/=0)then
        obj%intParameter = zeros(num_int)
        allocate(obj%intAnnotaton(num_int) )
        allocate(obj%intRegistered(num_int) )
        obj%intRegistered(:) = .false.
    endif
    
    !if(num_real==0) then
    !    obj%realRegistered = .true.
    !endif

    !if(num_int==0) then
    !    obj%intRegistered = .true.
    !endif
end subroutine
! #################################################################
! #################################################################
! #################################################################
! #################################################################




! #################################################################
subroutine initGA(obj,num_individual,num_real,num_int)
    class(GA_),intent(inout) :: obj
    integer(int32),intent(in) :: num_individual
    integer(int32),intent(in) :: num_real,num_int
    integer(int32) :: i


    if(allocated(obj%plants) ) deallocate(obj%plants)

    if(num_real < 0 .or. num_int < 0)then
        print *, "ERROR :: initGA >> invalid num_real/num_int >> both should be >= 0"
        stop
    endif
    ! generate individuals
    allocate(obj%plants(num_individual) )
    obj%score=zeros(num_individual) 
    obj%num_individual = num_individual

    ! fill zero to initialize
    do i=1, num_individual
        call obj%plants(i)%init(num_real=num_real,num_int=num_int)
    enddo


    obj%initialized = .true.
    
end subroutine
! #####################################################################


! #####################################################################
subroutine setupGA(obj,DataType,DataID,DataRange,DataAnnotation)
    class(GA_),intent(inout) :: obj
    integer(int32),intent(in) :: DataType,DataID
    real(real32),intent(in) :: DataRange(2)
    character(*),intent(in) :: DataAnnotation

    real(real32) :: DRange(2)
    real(real64) :: theta
    type(Random_) :: random
    integer(int32):: i

    DRange(1) = minval(DataRange)
    DRange(2) = maxval(DataRange)

    if(.not. obj%initialized)then
        print *, "ERROR :: setupGA >> not initialized. please call %init()"
        stop
    endif
    
    if(DataType==real64)then
        do i=1,size(obj%plants)
            ! set random data
            ! by DRange
            theta = random%random()
            obj%plants(i)%realParameter(DataID) = (1.0d0-theta)*Drange(1) + theta*Drange(2)
            obj%plants(i)%realAnnotaton(DataID)%annotation = DataAnnotation
            obj%plants(i)%realRegistered(DataID) = .true.
        enddo

    elseif(DataType==int32)then
        do i=1,size(obj%plants)
            ! set random data
            ! by DRange
            theta = random%random()
            obj%plants(i)%intParameter(DataID) = int((1.0d0-theta)*Drange(1) + theta*Drange(2))
            obj%plants(i)%intAnnotaton(DataID)%annotation = DataAnnotation
            obj%plants(i)%intRegistered(DataID) = .true.
        enddo

    else
        print *, "ERROR :: setupGA >> unknown datatype. please input real64 or int32"
        stop
    endif
    

end subroutine
! #####################################################################

! #####################################################################
subroutine showGA(obj,KeyWord)
    class(GA_),intent(in) :: obj
    character(*),intent(in) :: KeyWord
    logical :: found=.false.
    integer(int32) :: i,j

    if(.not.obj%initialized)then
        print *, "[CAUTION] >> showGA >>  not initialized"
        return
    endif

    if(allocated(obj%plants(1)%realParameter) )then
        do i=1,size(obj%plants(1)%realAnnotaton)
            if( index(obj%plants(1)%realAnnotaton(i)%annotation,KeyWord)/=0)then
                print *, "Data :: "//obj%plants(1)%realAnnotaton(i)%annotation//" DataType :: Real64"
                do j=1,size(obj%plants)
                    print *, "IndvID: ",j," Value:",obj%plants(j)%realParameter(i)
                enddo
                found = .true.
            endif
        enddo
    endif

    if(allocated(obj%plants(1)%intParameter) )then
        do i=1,size(obj%plants(1)%intParameter)
            if( index(obj%plants(1)%intAnnotaton(i)%annotation,KeyWord)/=0)then
                print *, "Data :: "//obj%plants(1)%intAnnotaton(i)%annotation//" DataType :: int32"
                do j=1,size(obj%plants)
                    print *, "IndvID: ",j," Value:",obj%plants(j)%intParameter(i)
                enddo
                found = .true.
            endif
        enddo
    endif

    if(.not.found)then
        print *, "Not Found."
    endif

end subroutine
! #####################################################################

! #####################################################################
function parseGA(obj,KeyWord) result(ret)
    class(GA_),intent(in) :: obj
    character(*),intent(in) :: KeyWord
    real(real64),allocatable :: ret(:)
    logical :: found=.false.
    integer(int32) :: i,j

    ret = zeros(obj%num_individual)

    if(.not.obj%initialized)then
        print *, "[CAUTION] >> showGA >>  not initialized"
        return
    endif

    if(allocated(obj%plants(1)%realParameter) )then
        do i=1,size(obj%plants(1)%realAnnotaton)
            if( index(obj%plants(1)%realAnnotaton(i)%annotation,KeyWord)/=0)then
                do j=1,size(obj%plants)
                    ret(j) = obj%plants(j)%realParameter(i)
                enddo
                found = .true.
            endif
        enddo
        return
    endif

    if(allocated(obj%plants(1)%intParameter) )then
        do i=1,size(obj%plants(1)%intParameter)
            if( index(obj%plants(1)%intAnnotaton(i)%annotation,KeyWord)/=0)then
                do j=1,size(obj%plants)
                    ret(j) = dble(obj%plants(j)%intParameter(i))
                enddo
                found = .true.
            endif
        enddo
        return
    endif

    if(.not.found)then
        print *, "Not Found."
    endif

end function
! #####################################################################



! #####################################################################
subroutine selectGA(obj,score,SurvivalRate)
    class(GA_),intent(inout) :: obj
    real(real64),intent(in) :: score(:),SurvivalRate
    integer(int32) :: num_selection ,i,n
    real(real64),allocatable :: id(:),score_val(:)

    num_selection = int( SurvivalRate*obj%num_individual )
    if(num_selection==0)then
        num_selection=1
    endif
    id = zeros(obj%num_individual)
    do i=1,size(id)
        id(i) = i
    enddo
    score_val = score
    n = obj%num_individual
    call heapsort(array=score_val,val=id, n=obj%num_individual )
    obj%selected = id(n-num_selection+1:n)
    obj%selectedScore = score_val(n-num_selection+1:n)


end subroutine
! #####################################################################


! #####################################################################
subroutine crossGA(obj)
    class(GA_),intent(inout) :: obj
    type(GA_) :: copy
    type(Random_) :: random
    integer(int32) :: i,j,num_select,itr,parent1, parent2
    real(real64),allocatable :: realbuf(:)
    real(real64) :: theta

    copy = obj
    num_select = size(obj%selected)
    realbuf = zeros(num_select)

    if(allocated(obj%plants(1)%realParameter) )then
        ! real parameter exists
        ! for all new individuals, update info.
        do i=1,obj%num_individual
            ! determine parents
            parent1 = obj%selected( random%randint(from=1,to=num_select) )
            parent2 = obj%selected( random%randint(from=1,to=num_select) )
            ! create new data
            ! weighted averaging
            do j=1,size(obj%plants(i)%realParameter)
                theta = random%random() ! 0 < theta < 1
                obj%plants(i)%realParameter(j) = &
                    (1.0d0-theta)*copy%plants(parent1)%realParameter(j) + &
                    theta*copy%plants(parent2)%realParameter(j) 
            enddo
        enddo
    endif



    if(allocated(obj%plants(1)%intParameter) )then
        ! int parameter exists
        ! for all new individuals, update info.
        do i=1,obj%num_individual
            ! determine parents
            parent1 = obj%selected( random%randint(from=1,to=num_select) )
            parent2 = obj%selected( random%randint(from=1,to=num_select) )
            ! create new data
            ! random selection
            do j=1,size(obj%plants(i)%intParameter)
                theta = random%random()
                if(theta >= 0.50d0)then
                    obj%plants(i)%intParameter(j) = copy%plants(parent1)%intParameter(j)
                else
                    obj%plants(i)%intParameter(j) = copy%plants(parent2)%intParameter(j)
                endif
            enddo
        enddo
    endif

    

end subroutine
! #####################################################################

! #####################################################################
subroutine mutateGA(obj,KeyWord,sigma)
    class(GA_),intent(inout) :: obj
    character(*),intent(in) :: KeyWord
    real(real64),intent(in) :: sigma
    type(Random_) :: random
    logical :: found = .false.
    integer(int32) :: i,j
    

    if(allocated(obj%plants(1)%realParameter) )then
        do i=1,size(obj%plants(1)%realAnnotaton)
            if( index(obj%plants(1)%realAnnotaton(i)%annotation,KeyWord)/=0)then
                do j=1,size(obj%plants)
                    obj%plants(j)%realParameter(i) = &
                    obj%plants(j)%realParameter(i) + random%gauss(mu=0.0d0,sigma=sigma)
                enddo
                found = .true.
            endif
        enddo
        return
    endif

    if(allocated(obj%plants(1)%intParameter) )then
        do i=1,size(obj%plants(1)%intParameter)
            if( index(obj%plants(1)%intAnnotaton(i)%annotation,KeyWord)/=0)then
                do j=1,size(obj%plants)
                    obj%plants(j)%intParameter(i) = &
                    int(dble(obj%plants(j)%intParameter(i))+random%gauss(mu=0.0d0,sigma=sigma))
                enddo
                found = .true.
            endif
        enddo
        return
    endif

    if(.not.found)then
        print *, "Not Found."
    endif

    
end subroutine
! #####################################################################

end module