PROGRESS  master
prg_partition_mod.F90
Go to the documentation of this file.
1 
7 
8  use bml
9  use prg_graph_mod
11  use prg_extras_mod
12  use, intrinsic :: iso_c_binding
13 
14  implicit none
15 
16  private !Everything is private by default
17 
18  integer, parameter :: dp = kind(1.0d0)
19 
24  integer, parameter :: metis_index_kind = metis_index_kind
25 
30  integer, parameter :: metis_real_kind = kind(metis_real_kind)
31 
32  public :: prg_metispartition
33  public :: prg_costpartition
34  public :: update_prg_costpartition
35  public :: prg_simannealing
36  public :: prg_check_arrays
37  public :: prg_kernlin
38  public :: prg_kernlin2
39  public :: prg_kernlin_queue
40  public :: prg_update_gp
41  public :: prg_simannealing_old
42 
43 
44 #ifdef DO_GRAPHLIB
45  interface
46 
47  integer function metis_setdefaultoptions(options) &
48  bind(C, name="METIS_SetDefaultOptions")
49 
50  import metis_index_kind
51 
52  integer(kind=metis_index_kind), intent(in) :: options(*)
53 
54  end function metis_setdefaultoptions
55 
56  integer function metis_partgraphkway(nvtxs, ncon, xadj, adjncy, vwgt, &
57  vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part) &
58  bind(C, name="METIS_PartGraphKway")
59 
60  import metis_index_kind
61  import metis_real_kind
62 
63  integer(kind=metis_index_kind), intent(in) :: nvtxs(*)
64  integer(kind=metis_index_kind), intent(in) :: ncon(*)
65  integer(kind=metis_index_kind), intent(in) :: xadj(*)
66  integer(kind=metis_index_kind), intent(in) :: adjncy(*)
67  integer(kind=metis_index_kind), intent(in) :: vwgt(*)
68  integer(kind=metis_index_kind), intent(in) :: vsize(*)
69  integer(kind=metis_index_kind), intent(in) :: adjwgt(*)
70  integer(kind=metis_index_kind), intent(in) :: nparts(*)
71  real(kind=metis_real_kind), intent(in) :: tpwgts(*)
72  real(kind=metis_real_kind), intent(in) :: ubvec(*)
73  integer(kind=metis_index_kind), intent(in) :: options(*)
74  integer(kind=metis_index_kind), intent(inout) :: objval(*)
75  integer(kind=metis_index_kind), intent(inout) :: part(*)
76 
77  end function metis_partgraphkway
78 
79  end interface
80 #endif
81 
82 contains
83 
84 #ifdef DO_GRAPHLIB
85  subroutine metis_setdefaultoptions_wrapper(options)
86 
87  integer(kind=metis_index_kind), intent(in) :: options(:)
88  integer :: result
89 
90  result = metis_setdefaultoptions(options)
91  if (result /= 1) then
92  write(*, *) "error calling METIS_SetDefaultOptions"
93  stop
94  end if
95 
96  end subroutine metis_setdefaultoptions_wrapper
97 
98  subroutine metis_partgraphkway_wrapper(nvtxs, ncon, xadj, adjncy, vwgt, &
99  vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part)
100 
101  integer, intent(in) :: nvtxs
102  integer, intent(in) :: ncon
103  integer, intent(in) :: xadj(:)
104  integer, intent(in) :: adjncy(:)
105  integer, pointer, intent(in) :: vwgt(:)
106  integer, pointer, intent(in) :: vsize(:)
107  integer, pointer, intent(in) :: adjwgt(:)
108  integer, intent(in) :: nparts
109  double precision, pointer, intent(in) :: tpwgts(:)
110  double precision, pointer, intent(in) :: ubvec(:)
111  integer(kind=metis_index_kind), intent(in) :: options(:)
112  integer, intent(inout) :: objval
113  integer, intent(inout) :: part(:)
114 
115  integer(kind=metis_index_kind) :: nvtxs_metis(1)
116  integer(kind=metis_index_kind) :: ncon_metis(1)
117  integer(kind=metis_index_kind), allocatable :: xadj_metis(:)
118  integer(kind=metis_index_kind), allocatable :: adjncy_metis(:)
119  integer(kind=metis_index_kind), pointer :: vwgt_metis(:) => null()
120  integer(kind=metis_index_kind), pointer :: vsize_metis(:) => null()
121  integer(kind=metis_index_kind), pointer :: adjwgt_metis(:) => null()
122  integer(kind=metis_index_kind) :: nparts_metis(1)
123  real(kind=metis_real_kind), pointer :: tpwgts_metis(:) => null()
124  real(kind=metis_real_kind), pointer :: ubvec_metis(:) => null()
125  integer(kind=metis_index_kind) :: objval_metis(1)
126  integer(kind=metis_index_kind), allocatable :: part_metis(:)
127 
128  integer :: result
129 
130  nvtxs_metis(1) = nvtxs
131  ncon_metis(1) = ncon
132 
133  allocate(xadj_metis(size(xadj)))
134  xadj_metis = xadj
135 
136  allocate(adjncy_metis(size(adjncy)))
137  adjncy_metis = adjncy
138 
139  if (associated(vwgt)) then
140  allocate(vwgt_metis(size(vwgt)))
141  vwgt_metis = vwgt
142  end if
143 
144  if (associated(vsize)) then
145  allocate(vsize_metis(size(vsize)))
146  vsize_metis = vsize
147  end if
148 
149  if (associated(adjwgt)) then
150  allocate(adjwgt_metis(size(adjwgt)))
151  adjwgt_metis = adjwgt
152  end if
153 
154  nparts_metis(1) = nparts
155 
156  if (associated(tpwgts)) then
157  allocate(tpwgts_metis(size(tpwgts)))
158  tpwgts_metis = tpwgts
159  end if
160 
161  if (associated(ubvec)) then
162  allocate(ubvec_metis(size(ubvec)))
163  ubvec_metis = ubvec
164  end if
165 
166  objval_metis(1) = objval
167  part_metis = part
168 
169  result = metis_partgraphkway(nvtxs_metis, ncon_metis, xadj_metis, adjncy_metis, vwgt_metis, vsize_metis, adjwgt_metis, &
170  nparts_metis, tpwgts_metis, ubvec_metis, options, objval_metis, part_metis)
171  if (result /= 1) then
172  write(*, *) "error calling METIS_PartGraphKway"
173  stop
174  end if
175 
176  if (associated(vwgt_metis)) then
177  deallocate(vwgt_metis)
178  end if
179 
180  if (associated(vsize_metis)) then
181  deallocate(vsize_metis)
182  end if
183 
184  if (associated(adjwgt_metis)) then
185  deallocate(adjwgt_metis)
186  end if
187 
188  if (associated(tpwgts_metis)) then
189  deallocate(tpwgts_metis)
190  end if
191 
192  if (associated(ubvec_metis)) then
193  deallocate(ubvec_metis)
194  end if
195 
196  objval = objval_metis(1)
197  part = part_metis
198 
199  end subroutine metis_partgraphkway_wrapper
200 #endif
201 
216  subroutine prg_metispartition(gp, ngroups, nnodes, xadj, adjncy, nparts, part, core_count, CH_count, Halo_count, sumCubes, &
217  maxCH, smooth_maxCH, pnorm)
218 
219  implicit none
220 
221  type (graph_partitioning_t), intent(inout) :: gp
222 
223  integer(kind=metis_index_kind), allocatable :: options(:) ! options for metis (64-bit wide)
224  integer, allocatable, intent(inout) :: xadj(:), adjncy(:), part(:)
225  integer, intent(inout) :: nparts
226  integer :: ncon, objval
227  integer :: i, j
228  integer, target :: dummy_vwgt, dummy_vsize, dummy_adjwgt
229  real(8), target :: dummy_tpwgts, dummy_ubvec
230  real(dp), intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
231  integer, intent (in) :: ngroups, nnodes
232  integer, allocatable, intent(inout) :: ch_count(:), core_count(:)
233  integer, allocatable, intent(inout) :: halo_count(:,:)
234  integer, allocatable :: copy_core_count(:)
235  integer, pointer :: vwgt(:) => null(), vsize(:) => null(), adjwgt(:) => null()
236  ! type(c_ptr) :: vwgt, vsize, adjwgt
237  ! type(c_ptr) :: tpwgts, ubvec
238  real(8), pointer :: tpwgts(:) => null(), ubvec(:) => null()
239  character(len=100) :: pname
240 
241  allocate(options(40))
242  allocate(copy_core_count(nparts))
243 
244  write(pname, '("metisParts")')
245 
246  options=0
247 #ifdef DO_GRAPHLIB
248  call metis_setdefaultoptions_wrapper(options)
249 #endif
250 
251  ncon = 1
252  objval = 1
253 
254  options(1) = 1 !METIS_PTYPE_KWAY
255  options(2) = 0 !METIS_OBJTYPE_CUT
256  options(9) = 10 !METIS_OPTION_SEED
257  options(18) = 1 !Fortran-style numbering is assumed that starts from 1
258 
260  halo_count = 0
261  ch_count = 0
262  core_count = 0
263 
264  if (printrank() .eq. 1) then
265  write(*,*) "prg_metisPartition_test start ..."
266  endif
267  ! prg_initialize gp
268  call prg_initgraphpartitioning(gp, pname, nparts, ngroups, nnodes)
269 
271  !write(*,*) "The number of nodes in the graph is:", gp%totalNodes, &
272  ! gp%totalNodes2, ncon, nparts, objval
273 
274 #ifdef DO_GRAPHLIB
275  call metis_partgraphkway_wrapper(gp%totalNodes, ncon, xadj, adjncy, vwgt, &
276  vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part)
277 #endif
278 
280  call prg_costpartition(gp, xadj, adjncy, part, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
281 
282  !prg_initialize and fill up subgraph structure
283  !! Assign node ids (mapped to orbitals as rows) to each node in each
284  do i = 1, nparts
285  gp%nnodesInPartAll(i) = core_count(i)
286  copy_core_count(i) = core_count(i)
287  call prg_initsubgraph(gp%sgraph(i), i, nnodes)
288  allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
289  gp%nnodesInPart(i) = core_count(i)
290  enddo
291 
292  !Assign node ids to sgraph
293  do i = 1, gp%totalNodes
294  copy_core_count(part(i)) = copy_core_count(part(i)) - 1
295  ! --> core_count((part(i))) - copy_core_count(part(i)) <--- = 1,2,3, ..., core_count( partnumber ) with respect to i
296 
297  ! NOTE: nodes in gp%sgraph()%nodeInPart() are currently 0 based!
298  gp%sgraph(part(i))%nodeInPart(core_count((part(i))) - copy_core_count(part(i)) ) = i -1
299  end do
300  do i = 1, nparts
301  do j = 1, core_count(i)
302  if( part( gp%sgraph(i)%nodeInPart(j)+1 ) /= i) then
303  write(*,*) "ERROR: subgraph struc incorrect!!", "node=",gp%sgraph(i)%nodeInPart(j)+1 , &
304  "part=",i, "actual_part=", part(gp%sgraph(i)%nodeInPart(j)+1 )
305  stop
306  end if
307 
308  end do
309  end do
310 
311  end subroutine prg_metispartition
312 !
326  subroutine prg_costpartition(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
327 
328  type (graph_partitioning_t), intent(inout) :: gp
329  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
330  integer, allocatable, intent(in) :: partnumber(:)
331  integer, allocatable, intent(inout) :: core_count(:)
332  integer :: totalparts, totalnodes, i, j, neighbor
333  real(dp), intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
334  integer, allocatable, intent(inout) :: ch_count(:)
335  integer, allocatable, intent(inout) :: halo_count(:,:)
336  real(dp) :: temp
337 
338  maxch = 0
339  smooth_maxch = 0
340  sumcubes = 0
341  totalparts = gp%totalParts
342  totalnodes = gp%totalNodes
343 
345  halo_count = 0
346  ch_count = 0
347  core_count = 0
348 
349  do i = 1, totalnodes
350  ch_count(partnumber(i)) = ch_count(partnumber(i)) + 1 !core count
351  core_count(partnumber(i)) = core_count(partnumber(i)) + 1 !core count
352  do j = xadj(i), xadj(i + 1) - 1
353  neighbor = adjncy(j)
354  if (partnumber(i) /= partnumber(neighbor)) then
355  if (halo_count(partnumber(i) ,neighbor) == 0) then
356  ch_count(partnumber(i)) = ch_count(partnumber(i)) + 1 !halo count
357  halo_count(partnumber(i), neighbor) = 1
358  else
359  halo_count(partnumber(i), neighbor) = halo_count(partnumber(i), neighbor) + 1
360  end if
361  end if
362  end do
363  end do
364 
365  do i = 1, totalparts
366  if (core_count(i) <= 1) then
367  print *, "core count <= 1 for partition "//to_string(i)//"!"
368  stop
369  end if
370  temp = real(ch_count(i), dp)
371  sumcubes = sumcubes+ temp*temp*temp
372  smooth_maxch = smooth_maxch + temp**int(pnorm)
373  if (ch_count(i) > maxch) then
374  maxch = ch_count(i)
375  end if
376  end do
377  smooth_maxch = smooth_maxch**(1/pnorm)
378 
379  end subroutine prg_costpartition
380 
400  subroutine update_prg_costpartition(gp, xadj, adjncy, partNumber,core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH, pnorm, node, new_part)
401 
402  type (graph_partitioning_t), intent(inout) :: gp
403  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
404  integer, allocatable, intent(inout) :: partnumber(:), core_count(:)
405  integer :: totalparts, totalnodes, i, j, neighbor
406  real(dp), intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
407  integer, intent (in) :: node, new_part
408  integer, allocatable, intent(inout) :: ch_count(:)
409  integer, allocatable, intent(inout) :: halo_count(:,:)
410  integer :: old_part
411  real(dp) :: temp
412 
413  totalparts = gp%totalParts
414  totalnodes = gp%totalNodes
415  old_part = partnumber(node)
416 
417  if (old_part /= new_part) then
418  core_count(new_part) = core_count(new_part) + 1
419  core_count(old_part) = core_count(old_part) - 1
420  ch_count(old_part) = ch_count(old_part) - 1 !core--
421  ch_count(new_part) = ch_count(new_part) + 1 !core--
422  do i=xadj(node), xadj(node+1) -1
423  neighbor = adjncy(i)
424  if (node /= neighbor) then
425  if(partnumber(neighbor) == old_part) then !case 1
426  halo_count(old_part, node) = halo_count(old_part, node) + 1
427  if (halo_count(old_part, node) == 1) then
428  ch_count(old_part) = ch_count(old_part) + 1 !halo++
429  end if
430  halo_count(new_part, neighbor) = halo_count(new_part, neighbor) + 1
431  if (halo_count(new_part, neighbor) == 1) then
432  ch_count(new_part) = ch_count(new_part) + 1 !halo++
433  end if
434  else if (partnumber(neighbor) == new_part) then !case 2
435  halo_count(old_part, neighbor) = halo_count(old_part, neighbor) - 1
436  if (halo_count(old_part, neighbor) == 0) then
437  ch_count(old_part) = ch_count(old_part) - 1 !halo--
438  else if (halo_count(old_part, neighbor) < 0) then
439  write(*,*) "ERROR: Halo_count value cannot be negative, case 2i"
440  write(*,*) "input matrix should be perfectly symmetric"
441  stop
442  end if
443  halo_count(new_part, node) = halo_count(new_part, node) - 1
444  if (halo_count(new_part, node) == 0) then
445  ch_count(new_part) = ch_count(new_part) - 1 !halo--, halo has become a core
446  else if (halo_count(new_part, node) < 0) then
447  write(*,*) "ERROR: Halo_count value cannot be negative, case 2ii"
448  write(*,*) "input matrix should be perfectly symmetric"
449  stop
450  end if
451  else !case 3
452  halo_count(old_part, neighbor) = halo_count(old_part, neighbor) - 1
453  if (halo_count(old_part, neighbor) == 0) then
454  ch_count(old_part) = ch_count(old_part) - 1 !halo--
455  else if (halo_count(old_part, neighbor) < 0) then
456  write(*,*) "ERROR: Halo_count value cannot be negative, case 3"
457  write(*,*) "input matrix should be perfectly symmetric"
458  stop
459  end if
460  halo_count(new_part, neighbor) = halo_count(new_part, neighbor) + 1
461  if (halo_count(new_part, neighbor) == 1) then
462  ch_count(new_part) = ch_count(new_part) + 1 !halo++
463  end if
464  end if
465  end if
466  end do
467  partnumber(node) = new_part
468  sumcubes = 0
469  maxch = 0
470  smooth_maxch = 0
471  do i=1, totalparts
472  temp = real(ch_count(i), dp)
473  sumcubes = sumcubes+ temp*temp*temp
474  smooth_maxch = smooth_maxch + temp**int(pnorm)
475  if (ch_count(i) > maxch) then
476  maxch = real(ch_count(i),dp)
477  end if
478  end do
479  smooth_maxch = smooth_maxch**(1/pnorm)
480  end if
481 
482  end subroutine update_prg_costpartition
483 
488  subroutine prg_accept_prob(it, prg_delta, r)
489  integer, intent(in) :: it
490  real(dp), intent(in) :: prg_delta
491  real, intent(inout) :: r
492  real :: temp
493  temp = 1.0/it
494  r = 1
495  if (prg_delta > 0) then
496  r = exp(-(prg_delta/10.0)/temp)
497  end if
498 
499  end subroutine prg_accept_prob
500 
506  subroutine prg_costindex(cost, sumCubes, maxCH, smooth_maxCH, obj_fun)
507  real(dp), intent (inout) :: cost, maxCH,smooth_maxCH, sumCubes
508  integer, intent (inout) :: obj_fun
509 
510  cost = -1
511 
512  if (obj_fun .eq. 0) then
513  cost = sumcubes
514  else if (obj_fun .eq. 1) then
515  cost = maxch
516  else if (obj_fun .eq. 2) then
517  cost = smooth_maxch
518  end if
519 
520  end subroutine prg_costindex
521 
526  subroutine prg_rand_node(gp,node, seed)
527  type (graph_partitioning_t), intent(inout) :: gp
528  integer, intent(inout) :: node, seed
529  integer :: totalNodes, i, ssize
530  integer, allocatable :: seedin(:)
531  real :: u
532  !call srand(seed)
533  call random_seed()
534  call random_seed(size=ssize)
535  allocate(seedin(ssize))
536  seedin = seed
537  call random_seed(put=seedin)
538 
539  call random_number(u)
540  node = floor(gp%totalNodes*u) + 1
541 
542  end subroutine prg_rand_node
543 
558  subroutine prg_simannealing(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH,pnorm, niter, seed)
559 
560  type (graph_partitioning_t), intent(inout) :: gp
561  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
562  integer, allocatable, intent(inout) :: partnumber(:), core_count(:)
563  integer :: totalparts, totalnodes, it, i,j,k, neighbor, node, part_backup
564  integer :: totalnodes2
565  real(dp) :: cost, prev_cost, prg_delta, prev_maxch
566  real(dp), intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
567  integer, intent (in) :: niter
568  integer, intent(inout) :: seed
569  integer, allocatable, intent(inout) :: ch_count(:)
570  integer, allocatable, intent(inout) :: halo_count(:,:)
571  integer, allocatable :: copy_core_count(:), empty_parts(:)
572  integer :: obj_fun = 2, min_ch_part, no_empty_parts, new_part
573  real :: r, u
574  character(len=100) :: pname
575  integer :: ssize
576  integer, allocatable :: seedin(:)
577 
578  totalparts = gp%totalParts
579  totalnodes = gp%totalNodes
580  totalnodes2 = gp%totalNodes2
581  allocate(copy_core_count(totalparts))
582  allocate(empty_parts(totalparts))
583  !call srand(seed)
584  call random_seed()
585  call random_seed(size=ssize)
586  allocate(seedin(ssize))
587  seedin = seed
588  call random_seed(put=seedin)
589 
590  write(*,*) "SA called..."
591  if (totalnodes .lt. totalparts) then
592  write(*,*) "ERROR: Number of parts cannot be greater than number of nodes."
593  stop
594  end if
595 
597  call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
598 
600  call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
601  prev_cost = cost
602 
604  do it=1, niter
605  call prg_rand_node(gp, node, seed)
607  min_ch_part = 1
608  do k =1, totalparts
609  if (ch_count(min_ch_part) .gt. ch_count(k)) then
610  min_ch_part = k
611  end if
612  end do
613 
616  if (ch_count( partnumber(node) ) .eq. maxch) then
617  do j = xadj(node), xadj(node+1)-1
618  neighbor = adjncy(j)
619  part_backup = partnumber(neighbor)
620  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, &
621  smooth_maxch, pnorm, neighbor, min_ch_part)
622  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
623  prg_delta = cost - prev_cost
624  call prg_accept_prob(it, prg_delta, r)
625  call random_number(u)
626  if (u > r) then ! reject
627  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
628  else
629  prev_cost = cost
630  end if
631  end do
632  else
633  if (ch_count( min_ch_part) .eq. 0) then
634  do j = xadj(node), xadj(node+1)-1
635  neighbor = adjncy(j)
636  part_backup = partnumber(neighbor)
637  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, min_ch_part)
638  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
639  prg_delta = cost - prev_cost
640  call prg_accept_prob(it, prg_delta, r)
641  call random_number(u)
642  if (u > r) then ! reject
643  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
644  else
645  prev_cost = cost
646  end if
647  end do
648  else
649  do j = xadj(node), xadj(node+1)-1
650  neighbor = adjncy(j)
651  part_backup = partnumber(neighbor)
652  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, partnumber(node))
653  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
654  prg_delta = cost - prev_cost
655  call prg_accept_prob(it, prg_delta, r)
656  call random_number(u)
657  if (u > r) then ! reject
658  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
659  else
660  prev_cost = cost
661  end if
662  end do
663  end if
664  end if
665  end do
666 
669  no_empty_parts = 0
670  do i=1,totalparts
671  if (ch_count(i) .eq. 0) then
672  no_empty_parts = no_empty_parts + 1
673  empty_parts(no_empty_parts) = i
674  end if
675  end do
676  prev_maxch = maxch
677  do node=1,totalnodes
678  if (no_empty_parts .le. 0) then
679  exit
680  end if
681 
682  if (ch_count(partnumber(node)) .eq. maxch) then
683  new_part = empty_parts(no_empty_parts)
684  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
685  prev_maxch = maxch
686  no_empty_parts = no_empty_parts - 1
687 
689  do j = xadj(node), xadj(node+1)-1
690  neighbor = adjncy(j)
691  if (ch_count(partnumber(neighbor)) .eq. maxch) then
692  part_backup = partnumber(neighbor)
693  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, neighbor, new_part)
694  call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
695  if (maxch .ge. prev_maxch) then ! reject
696  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup )
697  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
698  else
699  prev_cost = cost
700  prev_maxch = maxch
701  end if
702  end if
703  end do
704  end if
705  end do
706 
707  write(*,*) "Cost of meTIS+SA", sumcubes, maxch, smooth_maxch
708 
709 
710 
712  !prg_initialize and fill up subgraph structure
713  !! Assign node ids (mapped to orbitals as rows) to each node in each
715  write(pname, '("SAParts")')
716  call prg_initgraphpartitioning(gp, pname, totalparts, totalnodes, totalnodes2)
717  do i = 1, totalparts
718  gp%nnodesInPartAll(i) = core_count(i)
719  copy_core_count(i) = core_count(i)
720  call prg_initsubgraph(gp%sgraph(i), i, gp%totalNodes2)
721  allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
722  gp%nnodesInPart(i) = core_count(i)
723  enddo
724 
725  !Assign node ids to sgraph
726  do i=1, gp%totalNodes
727  copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
728  ! core_count((part(i))) - copy_core_count(part(i)) = node postion in array
729  gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1 !NOTE: nodes in gp%sgraph()%nodeInPart() are currently 0 based!
730  end do
731 
732 
734  do i = 1, totalparts
735  do j = 1, core_count(i)
736  if( partnumber( gp%sgraph(i)%nodeInPart(j)+1 ) /= i) then
737  write(*,*) "ERROR: subgraph struc incorrect!!", "node=",gp%sgraph(i)%nodeInPart(j)+1 , "part=",i, "actual_part=", partnumber(gp%sgraph(i)%nodeInPart(j)+1 )
738  stop
739  end if
740  end do
741  end do
742  do i=1, totalparts
743  write(*,*) "part=",i, "C=", core_count(i), "CH=", ch_count(i)
744  if (ch_count(i) .eq. 0) then
745  write(*,*) "ERROR: SA produced an empty part"
746  stop
747  end if
748  end do
749  end subroutine prg_simannealing
750 
751 
770 
771 
772  subroutine prg_kernlin(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, nconverg, seed)
773 
774  type (graph_partitioning_t), intent(inout) :: gp
775  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
776  integer, allocatable, intent(inout) :: partnumber(:), core_count(:)
777  integer :: totalparts, totalnodes, i, iit, j,k, neighbor, node, part_backup, h, node2
778  real(dp), intent(inout) :: sumcubes, maxch, smooth_maxch, pnorm
779  real(dp) :: cost, prev_cost, prev_iteration_cost, prev_maxch, minch
780  integer, intent(inout) :: seed
781  integer, intent(in) :: nconverg
782  integer, allocatable, intent(inout) :: ch_count(:)
783  integer, allocatable, intent(inout) :: halo_count(:,:)
784  integer, allocatable :: copy_core_count(:)
785  integer :: obj_fun = 2, counter, min_part, max_climb = 1, climb_counter, temp, convg_counter, converge, no_locked_nodes, empty_counter, backup, best_node, best_part,no_empty_parts, new_part
786  integer :: totalnodes2
787  real :: r, u
788  integer, allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), empty_parts(:)
789  character(len=100) :: pname
790 
791  totalnodes = gp%totalNodes
792  totalnodes2 = gp%totalNodes2
793  totalparts = gp%totalParts
794 
796  allocate(vertex_locked(totalnodes))
797  allocate(hedge_span(totalparts))
798  allocate(node_backup(totalnodes))
799  allocate(node_part_backup(totalnodes))
800  allocate(nodes(totalnodes))
801  allocate(copy_core_count(totalparts))
802  allocate(empty_parts(totalparts))
803 
805  vertex_locked = 0
806  hedge_span = 0
807  counter = 0
808  climb_counter = 1
809  converge = 0
810  convg_counter = 0
811  iit = 0
812  core_count = 0
813  ch_count = 0
814  halo_count = 0
815  no_locked_nodes = 0
816 
818  do i = 1, totalnodes
819  nodes(i) = i
820  end do
821 
823  call prg_rand_shuffle(nodes, seed)
824 
825 
827  call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
828 
830  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
831  prev_cost = cost
832  prev_iteration_cost = cost
833  prev_maxch = maxch
834 
836 
837 
838  do while ( converge .eq. 0 .and. iit .lt. nconverg)
839  iit = iit + 1
840  vertex_locked=0 ! Free vertices
841  no_locked_nodes = 0
842  call prg_rand_shuffle(nodes, seed)
843 
845  do i=1, gp%totalNodes
846  h = nodes(i) !h represents a hyperedge
847 
849  minch = totalnodes + 1
850  do j = 1, totalparts
851  if (ch_count(j) .lt. minch) then
852  min_part = j
853  minch = ch_count(j)
854  end if
855  end do
856  if (min_part .eq. -1) then
857  min_part = partnumber(h) !hyperedge h contains node h
858  do j = xadj(h), xadj(h+1)-1
859  node = adjncy(j)
860  if (hedge_span( partnumber(node))==0) then
861  counter = counter + 1
862  hedge_span( partnumber(node)) = ch_count(partnumber(node))
863  if (ch_count(partnumber(node)) .le. ch_count(min_part)) then
864  min_part = partnumber(node)
865  end if
866  end if
867  if (counter == totalparts) then
868  counter = 0
869  exit
870  end if
871  end do
872  end if
873  hedge_span = 0
874 
875  if(h .eq. 0) then
876  write(*,*) "error h =0"
877  stop
878  end if
880  climb_counter = 1
881  do j = xadj(h), xadj(h+1)-1
882  node = adjncy(j)
883 
884  if (vertex_locked(node) .eq. 0 ) then
885  part_backup = partnumber(node)
886  node_part_backup(climb_counter) = part_backup
887  node_backup(climb_counter) = node
888  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node, min_part)
889  call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
890  if (cost .le. prev_cost) then !accept
891  prev_cost = cost
892  no_locked_nodes = no_locked_nodes + climb_counter
893  !write(*,*) maxCH
894 
899 
900  temp = climb_counter
901  do k=1, temp
902  vertex_locked(node_backup(climb_counter)) = 1
903  climb_counter = climb_counter - 1
904  end do
905 
907  climb_counter = 1
908  node_backup = -1 !for debug purposes
909  node_part_backup = -1 !for debug purposes
910 
911  else
912  if (climb_counter .lt. max_climb) then !climb
913  climb_counter = climb_counter + 1
914  else !undo climb
915  do k=1, max_climb
916  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node_backup(climb_counter), node_part_backup(climb_counter))
917  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
918 
919  climb_counter = climb_counter - 1
920  end do
921  if (prev_cost .ne. cost) then
922  write(*,*) "ERROR: There was an error in undo step 2", node, cost, prev_cost, j
923  stop
924  end if
925  climb_counter = 1 !reset
926  end if
927  end if
928  end if
929 
930  ! end if
931  end do
932  !end of hyperedge, undo any climbs
933  if(prev_cost .ne. cost) then
934  temp = climb_counter
935 
936  !if climb_counter = 1, we cannot have prev_cost /= cost
937  do k=1, temp-1
938  climb_counter = climb_counter - 1
939  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node_backup(climb_counter), node_part_backup(climb_counter))
940  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
941 
942  end do
943  if (prev_cost .ne. cost) then
944  write(*,*) "ERROR: Undo after hyperedge"
945  stop
946  end if
947  end if
948 
950  if (no_locked_nodes .eq. gp%totalNodes) then
951  exit
952  end if
953 
954 
956  empty_counter = 0
957  do j=1,totalparts
958  if (core_count(j) .eq. 0) then
959  empty_counter = empty_counter +1
960  empty_parts(empty_counter) = j
961  end if
962  end do
963  if (empty_counter .gt. 0) then
964  do j= 1,totalnodes
965  if (ch_count(partnumber(j) ) .eq. maxch) then
966  do k = xadj(j), xadj(j+1)-1
968  node2 = adjncy(k)
969  backup = partnumber(j)
970  if (partnumber(node2) .eq. partnumber(j) ) then
971  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node2,empty_parts(empty_counter) )
972  call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
973  prev_cost = cost
974  !prev_maxCH = maxCH
975  if (prev_maxch .lt. maxch) then !undo
976  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node2,backup )
977  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
978  prev_cost = cost
979  prev_maxch = maxch
980  end if
981  end if
982  end do
983  empty_counter = empty_counter - 1
984  if (empty_counter .eq. 0) then
985  exit
986  end if
987  end if
988  end do
989  end if
990  end do !End KL iterations
991 
993  if (prev_iteration_cost .eq. cost) then
994  convg_counter = convg_counter + 1
995  if (convg_counter .eq. nconverg) then
996  converge =1
997  end if
998  else
999  prev_iteration_cost = cost
1000  convg_counter = 0
1001  end if
1002 
1003  end do !while loop
1004 
1007  no_empty_parts = 0
1008 
1009  do i=1,totalparts
1010  if (ch_count(i) .eq. 0) then
1011  no_empty_parts = no_empty_parts + 1
1012  empty_parts(no_empty_parts) = i
1013  end if
1014  end do
1015  prev_maxch = maxch
1016  do node=1,totalnodes
1017  if (no_empty_parts .le. 0) then
1018  exit
1019  end if
1020 
1021  if (ch_count(partnumber(node)) .eq. maxch .and. core_count(partnumber(node)) .ne. 1 ) then
1022  new_part = empty_parts(no_empty_parts)
1023  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
1024  prev_maxch = maxch
1025  no_empty_parts = no_empty_parts - 1
1026 
1028  do j = xadj(node), xadj(node+1)-1
1029  neighbor = adjncy(j)
1030  if (ch_count(partnumber(neighbor)) .eq. maxch) then
1031  part_backup = partnumber(neighbor)
1032  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, neighbor, new_part)
1033  call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
1034  if (maxch .ge. prev_maxch) then ! reject
1035  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup )
1036  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1037 
1038  else
1039  prev_cost = cost
1040  prev_maxch = maxch
1041  end if
1042  end if
1043  end do
1044  end if
1045  end do
1046 
1047 
1048 
1049 
1050 
1051 
1052  write(*,*) "Cost of KL:", cost, maxch, "No iterations:", iit
1053 
1055  !prg_initialize and fill up subgraph structure
1056  !! Assign node ids (mapped to orbitals as rows) to each node in each
1058  write(pname, '("KLParts")')
1059  call prg_initgraphpartitioning(gp, pname, totalparts, totalnodes, totalnodes2)
1060 
1062  do i = 1, totalparts
1063  gp%nnodesInPartAll(i) = core_count(i)
1064  copy_core_count(i) = core_count(i)
1065  call prg_initsubgraph(gp%sgraph(i), i, gp%totalNodes2)
1066  allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1067  gp%nnodesInPart(i) = core_count(i)
1068  enddo
1069 
1071  do i=1, gp%totalNodes
1072  copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1073  !!>core_count((part(i))) - copy_core_count(part(i)) = node postion in array
1074  gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1 !NOTE: nodes in gp%sgraph()%nodeInPart() are currently 0 based!
1075  end do
1076 
1077 
1078  do i=1, totalparts
1079  write(*,*) "part=",i, "C=", core_count(i), "CH=", ch_count(i)
1080  if (ch_count(i) .eq. 0) then
1081  write(*,*) "ERROR: KL produced an empty part"
1082  stop
1083  end if
1084  end do
1085  deallocate(vertex_locked)
1086  deallocate(hedge_span)
1087  deallocate(node_backup)
1088  deallocate(node_part_backup)
1089  deallocate(nodes)
1090  deallocate(copy_core_count)
1091 
1092  end subroutine prg_kernlin
1093 
1094 
1095 
1096  subroutine prg_update_gp(gp, partNumber, core_count)
1097  type (graph_partitioning_t), intent(inout) :: gp
1098  integer, allocatable, intent(inout) :: partnumber(:), core_count(:)
1099  integer :: totalparts, totalnodes, i
1100  integer :: totalnodes2
1101  integer, allocatable :: copy_core_count(:)
1102  character(len=100) :: pname
1103 
1104  totalnodes = gp%totalNodes
1105  totalnodes2 = gp%totalNodes2
1106  totalparts = gp%totalParts
1107  allocate(copy_core_count(totalparts))
1109  !prg_initialize and fill up subgraph structure
1110  !! Assign node ids (mapped to orbitals as rows) to each node in each
1112  write(pname, '("Parts")')
1113  call prg_initgraphpartitioning(gp, pname, totalparts, totalnodes, totalnodes2)
1114 
1116  do i = 1, totalparts
1117  gp%nnodesInPartAll(i) = core_count(i)
1118  copy_core_count(i) = core_count(i)
1119  call prg_initsubgraph(gp%sgraph(i), i, gp%totalNodes2)
1120  allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1121  gp%nnodesInPart(i) = core_count(i)
1122  enddo
1123 
1125  do i=1, gp%totalNodes
1126  copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1127  !!>core_count((part(i))) - copy_core_count(part(i)) = node postion in array
1128  gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1 !NOTE: nodes in gp%sgraph()%nodeInPart() are currently 0 based!
1129  end do
1130 
1131 
1132  deallocate(copy_core_count)
1133  end subroutine prg_update_gp
1134 
1135 
1137  subroutine prg_rand_shuffle(array, seed)
1138 
1139  integer, intent(inout) :: array(:), seed
1140  integer :: i, randpos, temp, ssize
1141  integer, allocatable :: seedin(:)
1142  real :: r
1143 
1145  !call srand(seed)
1146  call random_seed()
1147  call random_seed(size=ssize)
1148  allocate(seedin(ssize))
1149  seedin = seed
1150  call random_seed(put=seedin)
1151 
1152 
1154  do i = size(array), 2, -1
1155  call random_number(r)
1156  randpos = int(r * i) + 1
1157  temp = array(randpos)
1158  array(randpos) = array(i)
1159  array(i) = temp
1160  end do
1161 
1162  end subroutine prg_rand_shuffle
1163 
1164 
1167  subroutine prg_check_arrays(gp, core_count, CH_count, Halo_count)
1168  type (graph_partitioning_t), intent(inout) :: gp
1169  integer, allocatable, intent(inout) :: core_count(:)
1170  integer, allocatable, intent(inout) :: ch_count(:)
1171  integer, allocatable, intent(inout) :: halo_count(:,:)
1172  integer :: i,j, check
1173 
1174  do i=1,gp%totalParts
1175  check = core_count(i)
1176  do j=1, gp%totalNodes
1177  if (halo_count(i,j) >0) then
1178  check = check + 1
1179  end if
1180  end do
1181  if (check /= ch_count(i)) then
1182 
1183  write(*,*) "ERROR: Halo_count is incorrect!"
1184  write(*,*) "check=", check, "CH_count(i)", ch_count(i)
1185  stop
1186  end if
1187  end do
1188 
1189  write(*,*) "prg_check_arrays PASSED!"
1190  end subroutine prg_check_arrays
1191 
1194  subroutine prg_kernlin_queue(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
1195 
1196  type (graph_partitioning_t), intent(inout) :: gp
1197  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
1198  integer, allocatable, intent(inout) :: partnumber(:), core_count(:)
1199  integer :: totalparts, totalnodes, i, iit, j,k, neighbor, node, part_backup, h, node2
1200  real(dp), intent(inout) :: sumcubes, maxch, smooth_maxch, pnorm
1201  real(dp) :: cost, prev_cost, prev_iteration_cost, prev_maxch, minch, best_obj_val, current_cost
1202  integer, allocatable, intent(inout) :: ch_count(:)
1203  integer, allocatable, intent(inout) :: halo_count(:,:)
1204  integer, allocatable :: copy_core_count(:)
1205  integer :: backup, best_node, best_part
1206  real :: r, u
1207  integer, allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), emptyparts(:)
1208  character(len=100) :: pname
1209 
1210 
1211 
1212  do i =1, 5
1213  call prg_find_best_move(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, best_node, best_part )
1214  if(best_node .eq. 0) then
1215  write(*,*) "error: node is 0"
1216  stop
1217  end if
1218  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, best_node, best_part)
1219 
1220 
1221  end do
1222  write(*,*) "kl finished", gp%totalParts
1223  do i=1,gp%totalParts
1224  write(*,*) "part=", i, core_count(i), "ch=", ch_count(i)
1225  end do
1226 
1227  end subroutine prg_kernlin_queue
1228 
1230  subroutine prg_find_best_move(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, best_node, best_part )
1231 
1232  type (graph_partitioning_t), intent(inout) :: gp
1233  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
1234  integer, allocatable, intent(inout) :: partNumber(:), core_count(:)
1235  integer :: totalParts, totalNodes, i, iit, j,k, neighbor, node, part_backup, h, node2
1236  integer :: totalNodes2
1237  real(dp), intent(inout) :: sumCubes, maxCH, smooth_maxCH, pnorm
1238  real(dp) :: cost, prev_cost, prev_iteration_cost, prev_maxCH, minCH, best_obj_val, current_cost
1239  integer, intent(inout) :: best_node, best_part
1240  integer, allocatable, intent(inout) :: CH_count(:)
1241  integer, allocatable, intent(inout) :: Halo_count(:,:)
1242  integer, allocatable :: copy_core_count(:)
1243  integer :: obj_fun = 2, backup
1244  real :: r, u
1245  integer, allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), emptyParts(:)
1246  character(len=100) :: pname
1247  !! iterate through hyperedges
1248  !! find min part and empty part
1249  !! move vertices into part incident to h with smalles CH_count or empty part if it exists
1250 
1251  totalnodes = gp%totalNodes
1252  totalnodes2 = gp%totalNodes2
1253  totalparts = gp%totalParts
1254 
1255  best_node = 0
1256  best_part = 0
1257  call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
1258  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1259  best_obj_val = cost
1260 
1261  do i=1, totalnodes
1262  do j=1,totalparts
1263  backup = partnumber(i)
1264  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, i, j)
1265  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1266 
1267  if (cost .le. best_obj_val) then
1268  best_node = i
1269  best_part = j
1270  best_obj_val = cost
1271  end if
1272  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, i, backup)
1273  end do
1274  end do
1275 
1276  end subroutine prg_find_best_move
1277 
1278  subroutine prg_kernlin2(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
1279 
1280  type (graph_partitioning_t), intent(inout) :: gp
1281  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
1282  integer, allocatable, intent(inout) :: partnumber(:), core_count(:)
1283  integer :: totalparts, totalnodes, i, it, iit, j,k, neighbor, node, part_backup
1284  integer :: totalnodes2
1285  real(dp), intent(inout) :: sumcubes, maxch, smooth_maxch, pnorm
1286  real(dp) :: cost, prev_cost, prev_maxch, minch
1287  integer, allocatable, intent(inout) :: ch_count(:)
1288  real :: r
1289  integer, allocatable, intent(inout) :: halo_count(:,:)
1290  integer, allocatable :: copy_core_count(:), empty_parts(:)
1291  integer :: obj_fun = 2, largest_hedge = -1, search_part, min_ch_part, new_part, no_empty_parts, seed =1
1292  character(len=100) :: pname
1293  !! iterate through hyperedges
1294  !! find min part and empty part
1295  !! move vertices into part incident to h with smalles CH_count or empty part if it exists
1296 
1297  totalnodes = gp%totalNodes
1298  totalnodes2 = gp%totalNodes2
1299  totalparts = gp%totalParts
1300 
1302  allocate(copy_core_count(totalparts))
1303  allocate(empty_parts(totalparts))
1304 
1305  call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
1306  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1307  prev_cost = cost
1308  do iit = 1, 40
1309  do i = 1, totalparts
1313  call random_number(r)
1314  if (r .ge. 0.7) then
1315  it = i
1316  call prg_get_largest_hedge_in_part(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, it, largest_hedge)
1317  else
1318  call prg_rand_node(gp, largest_hedge, seed)
1319 
1320  end if
1322  min_ch_part = 1
1323  do k =1, totalparts
1324  if (ch_count(min_ch_part) .gt. ch_count(k)) then
1325  min_ch_part = k
1326  end if
1327  end do
1328 
1331  if (ch_count(partnumber(largest_hedge)) .eq. maxch) then
1333  new_part = min_ch_part
1334  else
1335  new_part = partnumber(largest_hedge)
1336  end if
1337 
1339  do j = xadj(largest_hedge), xadj(largest_hedge + 1)-1
1340  neighbor = adjncy(j)
1341  part_backup = partnumber(neighbor)
1342  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, new_part)
1343  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1344  if (cost .gt. prev_cost) then ! reject
1345  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
1346  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1347  else
1348  prev_cost = cost
1349  end if
1350  end do
1351  end do
1352  end do
1353 
1356  !call prg_Kernlin_queue(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
1357 
1360  no_empty_parts = 0
1361 
1362  do i=1,totalparts
1363  if (ch_count(i) .eq. 0) then
1364  no_empty_parts = no_empty_parts + 1
1365  empty_parts(no_empty_parts) = i
1366  end if
1367  end do
1368 
1369  prev_maxch = maxch
1370  do node=1,totalnodes
1371  if (no_empty_parts .le. 0) then
1372  exit
1373  end if
1374 
1375  if (ch_count(partnumber(node)) .eq. maxch .and. core_count(partnumber(node)) .ne. 1 ) then
1376  new_part = empty_parts(no_empty_parts)
1377  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
1378  prev_maxch = maxch
1379  no_empty_parts = no_empty_parts - 1
1380 
1382  do j = xadj(node), xadj(node+1)-1
1383  neighbor = adjncy(j)
1384  if (ch_count(partnumber(neighbor)) .eq. maxch) then
1385  part_backup = partnumber(neighbor)
1386  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, neighbor, new_part)
1387  call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
1388  if (maxch .ge. prev_maxch) then ! reject
1389  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup )
1390  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1391 
1392  else
1393  prev_cost = cost
1394  prev_maxch = maxch
1395  end if
1396  end if
1397  end do
1398  else if (core_count(partnumber(node)) .ne. 1 ) then
1399  new_part = empty_parts(no_empty_parts)
1400  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
1401  prev_maxch = maxch
1402  no_empty_parts = no_empty_parts - 1
1403  end if
1404  end do
1405 
1406 
1408  !prg_initialize and fill up subgraph structure
1409  !! Assign node ids (mapped to orbitals as rows) to each node in each
1411  write(pname, '("KLParts")')
1412  call prg_initgraphpartitioning(gp, pname, totalparts, totalnodes, totalnodes2)
1413 
1415  do i = 1, totalparts
1416  gp%nnodesInPartAll(i) = core_count(i)
1417  copy_core_count(i) = core_count(i)
1418  call prg_initsubgraph(gp%sgraph(i), i, gp%totalNodes2)
1419  allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1420  gp%nnodesInPart(i) = core_count(i)
1421  enddo
1422 
1424  do i=1, gp%totalNodes
1425  copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1426  !!>core_count((part(i))) - copy_core_count(part(i)) = node postion in array
1427  gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1 !NOTE: nodes in gp%sgraph()%nodeInPart() are currently 0 based!
1428  end do
1429 
1430 
1431  do i=1, totalparts
1432  write(*,*) "part=",i, "C=", core_count(i), "CH=", ch_count(i)
1433  if (ch_count(i) .eq. 0) then
1434  write(*,*) "ERROR: KL produced an empty part"
1435  stop
1436  end if
1437  end do
1438 
1439  end subroutine prg_kernlin2
1440 
1441 
1442  subroutine prg_get_largest_hedge_in_part(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, search_part, largest_Hedge)
1443  type (graph_partitioning_t), intent(inout) :: gp
1444  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
1445  integer, allocatable, intent(inout) :: partNumber(:), core_count(:)
1446  integer :: totalParts, totalNodes, i, iit, j,k, neighbor, node
1447  integer :: totalNodes2
1448  real(dp), intent(inout) :: sumCubes, maxCH, smooth_maxCH, pnorm
1449  integer, allocatable, intent(inout) :: CH_count(:)
1450  integer, allocatable, intent(inout) :: Halo_count(:,:)
1451  integer, allocatable :: copy_core_count(:)
1452  integer :: obj_fun = 2, largest_hsize
1453  integer, intent(inout) :: search_part, largest_Hedge
1454  real :: r, u
1455 
1456 
1457  totalnodes = gp%totalNodes
1458  totalnodes2 = gp%totalNodes2
1459  totalparts = gp%totalParts
1462  largest_hsize = 0
1463  do i=1, totalnodes
1464  if (partnumber(i) .eq. search_part) then
1465  if ( xadj(i + 1) - xadj(i) .gt. largest_hsize) then
1466  largest_hsize = xadj(i + 1) - xadj(i)
1467  largest_hedge = i
1468  end if
1469  end if
1470  end do
1471 
1472  end subroutine prg_get_largest_hedge_in_part
1473 
1474 
1475  subroutine prg_simannealing_old(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH,pnorm, niter, seed)
1476 
1477  type (graph_partitioning_t), intent(inout) :: gp
1478  integer, allocatable, intent(inout) :: xadj(:), adjncy(:)
1479  integer, allocatable, intent(inout) :: partnumber(:), core_count(:)
1480  integer :: totalparts, totalnodes, it, i,j,k, neighbor, node, part_backup, obj_fun=0
1481  integer :: totalnodes2
1482  real(dp) :: cost, prev_cost, prg_delta, prev_maxch
1483  real(dp), intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
1484  integer, intent (in) :: niter
1485  integer, intent(inout) :: seed
1486  integer, allocatable, intent(inout) :: ch_count(:)
1487  integer, allocatable, intent(inout) :: halo_count(:,:)
1488  integer, allocatable :: copy_core_count(:), empty_parts(:)
1489  real :: r, u
1490  character(len=100) :: pname
1491 
1492  totalparts = gp%totalParts
1493  totalnodes = gp%totalNodes
1494  totalnodes2 = gp%totalNodes2
1495 
1496  allocate(copy_core_count(totalparts))
1497  allocate(empty_parts(totalparts))
1498  !call srand(seed)
1499  write(*,*) "SA called..."
1500  if (totalnodes .lt. totalparts) then
1501  write(*,*) "ERROR: Number of parts cannot be greater than number of nodes."
1502  stop
1503  end if
1504 
1506  call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
1507 
1509  call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
1510  prev_cost = cost
1511 
1513  do it=1, niter
1514  call prg_rand_node(gp, node, seed)
1515  do j = xadj(node), xadj(node+1)-1
1516  neighbor = adjncy(j)
1517  part_backup = partnumber(neighbor)
1518  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, partnumber(node))
1519  call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1520  prg_delta = cost - prev_cost
1521  call prg_accept_prob(it, prg_delta, r)
1522  call random_number(u)
1523  if (u > r) then ! reject
1524  call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
1525  else
1526  prev_cost = cost
1527  !write(*,*) maxCH
1528  end if
1529  end do
1530 
1531  end do
1532 
1533 
1534 
1535  write(*,*) "Cost of meTIS+SA", sumcubes, maxch, smooth_maxch
1536 
1537 
1538 
1540  !prg_initialize and fill up subgraph structure
1541  !! Assign node ids (mapped to orbitals as rows) to each node in each
1543  write(pname, '("SAParts")')
1544  call prg_initgraphpartitioning(gp, pname, totalparts, totalnodes, totalnodes2)
1545  do i = 1, totalparts
1546  gp%nnodesInPartAll(i) = core_count(i)
1547  copy_core_count(i) = core_count(i)
1548  call prg_initsubgraph(gp%sgraph(i), i, gp%totalNodes2)
1549  allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1550  gp%nnodesInPart(i) = core_count(i)
1551  enddo
1552 
1553  !Assign node ids to sgraph
1554  do i=1, gp%totalNodes
1555  copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1556  ! core_count((part(i))) - copy_core_count(part(i)) = node postion in array
1557  gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1 !NOTE: nodes in gp%sgraph()%nodeInPart() are currently 0 based!
1558  end do
1559 
1560 
1562  do i = 1, totalparts
1563  do j = 1, core_count(i)
1564  if( partnumber( gp%sgraph(i)%nodeInPart(j)+1 ) /= i) then
1565  write(*,*) "ERROR: subgraph struc incorrect!!", "node=",gp%sgraph(i)%nodeInPart(j)+1 , "part=",i, "actual_part=", partnumber(gp%sgraph(i)%nodeInPart(j)+1 )
1566  stop
1567  end if
1568  end do
1569  end do
1570  do i=1, totalparts
1571  write(*,*) "part=",i, "C=", core_count(i), "CH=", ch_count(i)
1572  if (ch_count(i) .eq. 0) then
1573  write(*,*) "ERROR: SA produced an empty part"
1574 
1575  end if
1576  end do
1577  end subroutine prg_simannealing_old
1578 
1579 
1580 end module prg_partition_mod
Extra routines.
subroutine, public prg_delta(x, s, nn, dta)
Delta function ||X^tSX - I||.
integer, parameter dp
The graph module.
subroutine, public prg_initgraphpartitioning(gp, pname, np, nnodes, nnodes2)
Initialize graph partitioning.
subroutine, public prg_initsubgraph(sg, pnum, hsize)
Initialize subgraph.
subroutine, public prg_destroygraphpartitioning(gp)
Destroy graph partitioning.
The parallel module.
integer function, public printrank()
The partition module.
subroutine, public update_prg_costpartition(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, node, new_part)
Update cost of partition and the different parameters node is moves into new_part For each neighbor o...
subroutine prg_accept_prob(it, prg_delta, r)
Compute acceptance probability for simulated annealing.
subroutine prg_get_largest_hedge_in_part(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, search_part, largest_Hedge)
subroutine, public prg_kernlin_queue(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
Greedy algorithm. At each step it chooses the (vertex, new_part) pair with highest gain Currently imp...
integer, parameter metis_real_kind
From /usr/include/metis.h.
subroutine, public prg_update_gp(gp, partNumber, core_count)
subroutine, public prg_check_arrays(gp, core_count, CH_count, Halo_count)
Error checking Checking that core_count, CH_count, Halo_count match.
integer, parameter metis_index_kind
From /usr/include/metis.h.
subroutine, public prg_kernlin2(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
subroutine prg_rand_node(gp, node, seed)
Pick a random node.
subroutine, public prg_costpartition(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
Compute cost of a partition.
subroutine prg_find_best_move(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, best_node, best_part)
For kerlin_queue to find (vertex, new_part) pair with highest gain.
subroutine, public prg_simannealing_old(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, niter, seed)
subroutine prg_costindex(cost, sumCubes, maxCH, smooth_maxCH, obj_fun)
Choose objective function to work with.
subroutine, public prg_kernlin(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, nconverg, seed)
Graph partitioning based on inspired by Kernighan-Lin Review METiS manual for description of k-way im...
subroutine, public prg_simannealing(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, niter, seed)
Graph partitioning based on Simulated Annealing.
subroutine, public prg_metispartition(gp, ngroups, nnodes, xadj, adjncy, nparts, part, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
Create graph partitions minizing number of cut edges.
subroutine prg_rand_shuffle(array, seed)
Randomly shuffle array.