Skip to content

Instantly share code, notes, and snippets.

@szaghi
Created May 11, 2016 08:09
Show Gist options
  • Save szaghi/d5bb089c6a4938c13468d8eb60f10216 to your computer and use it in GitHub Desktop.
Save szaghi/d5bb089c6a4938c13468d8eb60f10216 to your computer and use it in GitHub Desktop.
Directed Graph Traverse (for entropy)

Discussion on API design of a D(A)G Traverse algorithm

Baseline classes

Plant, the DG

The main DG class built on top of component one.

type, public :: plant 
  private 
  character(len=:), allocatable :: name       ! DG name.
  character(len=:), allocatable :: start_comp ! Start (first?) component.
  type(component),  allocatable :: comp(:)    ! DG components.
contains 
  procedure, public :: plant_traverse ! Method to traverse the DG. 
end type plant

interface 
  subroutine plant_traverse(self, traverse_callback)
  import plant
  class(plant)                      :: self 
  procedure(traverse_callback_comp) :: traverse_callback
end interface

Component, the DG component member

The building-block of the DG.

type, public :: component 
  private 
  character(len=:),     allocatable :: name              ! Component name.
  real,                 allocatable :: in(:)             ! Some input of the component.
  real,                 allocatable :: out(:)            ! Some output of the component.
  real                              :: content=0.0       ! Content of the component.
  type(varying_string), allocatable :: next_comp(:)      ! Next component in the current DG branch (a string?).
  logical                           :: processed=.false. ! Processing status. 
  contains
    procedure, public :: traverse_callback_comp ! Traverse the (children?) components.
end type component 

interface 
  subroutine traverse_callback_comp(self, next_comp) 
    import :: component 
    class(component)                       :: self      ! which is the intended intent?
    class(component), intent(in), optional :: next_comp 
  end subroutine traverse_callback_comp 
end interface 

Open questions:

  • why next_comp is a string and not a pointer to the another component?
  • the traverse_callback_comp is somehow obscure in its aims/API-definition.

Auxiliary classes

Varying string

A wrapper for deferred length allocatable string to allow array of varying strings.

type, public :: varying_string 
  character(len=:), allocatable :: s 
end type varying_string 

The TRAVERSE method

subroutine plant_traverse(self, traverse_callback) 
  class(plant)                      :: self              ! The plant.
  procedure(traverse_callback_comp) :: traverse_callback ! The callback procedure to traverse components. 
  type(component)                   :: curr_comp         ! (pointer-like to) Current component.
  type(component)                   :: next_comp         ! (pointer-like to) Next component.
  
  curr_comp = self%get_plant_comp( self%get_plant_start_comp() ) ! the get_plant_comp API is missing, but should be clear its aims.

  call curr_comp%traverse_callback() ! this is somehow obscure 

  do 
    ! a lot of ancillary logic elided for brevity here 
    ! ... 
    next_comp = self%get_plant_comp( curr_comp%get_next_comp_name() ) 
    call curr_comp%traverse_callback(next_comp) 
    curr_comp = next_comp 
    ! ... 
  end do 
end subroutine plant_traverse 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment