add Module Subroutine

module subroutine add(this, layer, input_list, output_list, operator)

Add a layer to the network

Arguments

Type IntentOptional Attributes Name
class(network_type), intent(inout) :: this

Instance of network

class(base_layer_type), intent(in) :: layer

Layer to add to the network

integer, intent(in), optional, dimension(:) :: input_list

List of input layers

integer, intent(in), optional, dimension(:) :: output_list

List of output layers

class(*), intent(in), optional :: operator

Operator to use to connect the layers


Source Code

  module subroutine add(this, layer, input_list, output_list, operator)
    !! Add a layer to the network
    implicit none

    ! Arguments
    class(network_type), intent(inout) :: this
    !! Instance of network
    class(base_layer_type), intent(in) :: layer
    !! Layer to add to the network
    integer, dimension(:), optional, intent(in) :: input_list
    !! List of input layers
    integer, dimension(:), optional, intent(in) :: output_list
    !! List of output layers
    class(*), optional, intent(in) :: operator
    !! Operator to use to connect the layers

    ! Local variables
    integer :: i, vertex_index
    !! Loop index
    integer :: operator_
    !! Operator to use to connect the layers
    character(256) :: err_msg
    !! Error message
    integer, dimension(2) :: vertex_indices
    !! Indices of the vertices to connect
    type(container_layer_type), allocatable, dimension(:) :: model
    !! Model to add the layer to



    if(.not.allocated(this%model))then
       this%model = [container_layer_type()]
       this%num_layers = 1
    else
       allocate(model(size(this%model,dim=1)+1))
       do i = 1, size(this%model,dim=1)
          allocate(model(i)%layer, source=this%model(i)%layer)
       end do
       call move_alloc(model, this%model)
       this%num_layers = this%num_layers + 1
    end if
    allocate(this%model(size(this%model,dim=1))%layer, source=layer)
    this%model(size(this%model,dim=1))%layer%id = this%num_layers


    operator_ = 1
    if(present(operator))then
       select type(operator)
       type is(integer)
          operator_ = operator
       type is(character(*))
          select case(trim(to_lower(operator)))
          case("||", "concat", "concatenate", "append")
             operator_ = 1
          case("+", "add")
             operator_ = 2
          case("*", "x", "mul", "multiply")
             operator_ = 3
          end select
       end select
    end if
    if(operator_.gt.2.or.operator_.lt.1)then
       call stop_program("invalid operator")
       return
    end if

    ! edge_index(1) = index of the previous layer
    ! abs(edge_index(2)) = index of the current layer
    ! the -ve sign of edge_index(2) indicates that the edge goes from the
    !   previous layer to the current layer
    !   i.e. forward pass flows from positive to negative
    ! adjacency(i,:) is all of the layers that i feeds forward to
    ! adjacency(:,i) is all of the layers that feed forward to i
    !   (i.e. the backward pass)
    this%auto_graph%directed = .true.
    call this%auto_graph%add_vertex( &
         feature=[1._real32], id=this%num_layers, update_adjacency=.true. &
    )
    if(present(input_list))then
       do i = 1, size(input_list), 1
          if(input_list(i).eq.0)then
             vertex_index = 0
          elseif( &
               input_list(i).le.-this%auto_graph%num_vertices .or. &
               input_list(i).gt.this%auto_graph%num_vertices &
          )then
             write(err_msg, &
                  '("input vertex index ",I0," out of range (",I0,":",I0,")")' &
             ) &
                  input_list(i), &
                  -this%auto_graph%num_vertices +1, &
                  this%auto_graph%num_vertices
             call stop_program(err_msg)
             return
          elseif(input_list(i).lt.0)then
             vertex_index = this%auto_graph%num_vertices + input_list(i)
          else
             vertex_index = findloc( &
                  [this%auto_graph%vertex(:)%id], &
                  input_list(i), 1 &
             )
          end if
          vertex_indices = [ vertex_index, -this%auto_graph%num_vertices ]
          call this%auto_graph%add_edge( &
               index = vertex_indices, &
               feature = [ 1._real32 ], &
               id = operator_, &
               update_adjacency = .true. &
          )
       end do
    elseif(trim(layer%type).ne."inpt".and.this%auto_graph%num_vertices.gt.1)then
       vertex_indices = [ &
            this%auto_graph%num_vertices - 1, &
            -this%auto_graph%num_vertices &
       ]
       call this%auto_graph%add_edge( &
            index = vertex_indices, &
            feature = [ 1._real32 ], &
            id = operator_, &
            update_adjacency = .true. &
       )
    end if

    if(present(output_list))then
       do i = 1, size(output_list), 1
          vertex_index = findloc( &
               [this%auto_graph%vertex(:)%id], &
               output_list(i), 1 &
          )
          vertex_indices = [ this%auto_graph%num_vertices, -vertex_index ]
          call this%auto_graph%add_edge( &
               index = vertex_indices, &
               feature = [ 1._real32 ], &
               id = operator_, &
               update_adjacency = .true. &
          )
       end do
    end if

  end subroutine add