module graphs use :: iso_c_binding, only : c_int, c_int64_t, c_double use :: fgsl use :: utilities use :: prob use :: sort implicit none private integer, parameter :: dp = c_double integer, parameter :: i4 = c_int integer, parameter :: i8 = c_int64_t type, public :: ContactGraph integer(kind=c_int64_t) :: order ! The number of nodes integer(kind=c_int64_t) :: size ! The number of edges integer(kind=c_int64_t), dimension(:), allocatable :: nodes integer(kind=c_int64_t), dimension(:), allocatable :: weights integer(kind=c_int64_t), dimension(:), allocatable :: degrees integer(kind=c_int64_t), dimension(:,:), allocatable :: edges integer(kind=c_int64_t) :: num_self_loops integer(kind=c_int64_t) :: rewiring_iterations integer(kind=c_int64_t), dimension(:,:), allocatable :: adjacency_matrix contains private procedure, pass(self) :: ChungLuGraph procedure, pass(self) :: FastChungLuGraph procedure, pass(self) :: ConfigurationGraph generic, public :: build => ConfigurationGraph procedure, pass(self) :: EdgesToAdjacency generic, public :: adjacency => EdgesToAdjacency end type ContactGraph interface ContactGraph module procedure init_ContactGraph end interface ContactGraph contains function init_ContactGraph(nodes, weights) result(self) implicit none type(ContactGraph) :: self integer(kind=c_int64_t), dimension(:), intent(in) :: nodes integer(kind=c_int64_t), dimension(:), intent(in) :: weights if (size(nodes) .ne. size(weights)) then call FatalErrorMessage('in init_ContactGraph, size of nodes and weights must be the same') end if allocate(self%weights, source=weights) ! self%weights = weights allocate(self%nodes, source=nodes) self%order = size(nodes) ! self%nodes = nodes ! call Qsort(self%weights, self%nodes, -1) allocate(self%degrees, mold=nodes) self%degrees(:) = 0 call self%build() call self%adjacency() return end function init_ContactGraph subroutine FastChungLuGraph(self) class(ContactGraph), intent(inout) :: self integer(kind=c_int64_t) :: N real(kind=c_double) :: S integer(kind=c_int64_t) :: u, v real(kind=c_double) :: p, q, r N = size(self%nodes) S = sum(self%weights)*1.0_dp do u=1,N-1 v = u+1 p = min(self%weights(u)*self%weights(v)/S, 1.0_dp) do while ((v0)) if ( abs(p - 1.0_dp) > meps ) then call pdists%unif_rvs(r, meps, 1.0_dp-meps) v = v + int(floor(log(r)/log(1.0_dp-p))) end if if (v