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