12 use,
intrinsic :: iso_c_binding
18 integer,
parameter ::
dp = kind(1.0d0)
46 integer function metis_setdefaultoptions(options) &
47 bind(C, name="METIS_SetDefaultOptions")
51 integer(kind=metis_index_kind),
intent(in) :: options(*)
53 end function metis_setdefaultoptions
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")
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(*)
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(*)
76 end function metis_partgraphkway
84 subroutine metis_setdefaultoptions_wrapper(options)
86 integer(kind=metis_index_kind),
intent(in) :: options(:)
89 result = metis_setdefaultoptions(options)
91 write(*, *)
"error calling METIS_SetDefaultOptions"
95 end subroutine metis_setdefaultoptions_wrapper
97 subroutine metis_partgraphkway_wrapper(nvtxs, ncon, xadj, adjncy, vwgt, &
98 vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part)
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(:)
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)
124 integer(kind=metis_index_kind) :: objval_metis(1)
125 integer(kind=metis_index_kind),
allocatable :: part_metis(:)
129 nvtxs_metis(1) = nvtxs
132 allocate(xadj_metis(
size(xadj)))
135 allocate(adjncy_metis(
size(adjncy)))
136 adjncy_metis = adjncy
138 if (
associated(vwgt))
then
139 allocate(vwgt_metis(
size(vwgt)))
143 if (
associated(vsize))
then
144 allocate(vsize_metis(
size(vsize)))
148 if (
associated(adjwgt))
then
149 allocate(adjwgt_metis(
size(adjwgt)))
150 adjwgt_metis = adjwgt
153 nparts_metis(1) = nparts
155 if (
associated(tpwgts))
then
156 allocate(tpwgts_metis(
size(tpwgts)))
157 tpwgts_metis = tpwgts
160 if (
associated(ubvec))
then
161 allocate(ubvec_metis(
size(ubvec)))
165 objval_metis(1) = objval
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"
175 if (
associated(vwgt_metis))
then
176 deallocate(vwgt_metis)
179 if (
associated(vsize_metis))
then
180 deallocate(vsize_metis)
183 if (
associated(adjwgt_metis))
then
184 deallocate(adjwgt_metis)
187 if (
associated(tpwgts_metis))
then
188 deallocate(tpwgts_metis)
191 if (
associated(ubvec_metis))
then
192 deallocate(ubvec_metis)
195 objval = objval_metis(1)
198 end subroutine metis_partgraphkway_wrapper
215 subroutine prg_metispartition(gp, ngroups, nnodes, xadj, adjncy, nparts, part, core_count, CH_count, Halo_count, sumCubes, &
216 maxCH, smooth_maxCH, pnorm)
222 integer(kind=metis_index_kind),
allocatable :: options(:)
223 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:), part(:)
224 integer,
intent(inout) :: nparts
225 integer :: ncon, objval
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()
237 real(8),
pointer :: tpwgts(:) => null(), ubvec(:) => null()
238 character(len=100) :: pname
240 allocate(options(40))
241 allocate(copy_core_count(nparts))
243 write(pname,
'("metisParts")')
247 call metis_setdefaultoptions_wrapper(options)
264 write(*,*)
"prg_metisPartition_test start ..."
274 call metis_partgraphkway_wrapper(gp%totalNodes, ncon, xadj, adjncy, vwgt, &
275 vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part)
279 call prg_costpartition(gp, xadj, adjncy, part, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
284 gp%nnodesInPartAll(i) = core_count(i)
285 copy_core_count(i) = core_count(i)
287 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
288 gp%nnodesInPart(i) = core_count(i)
292 do i = 1, gp%totalNodes
293 copy_core_count(part(i)) = copy_core_count(part(i)) - 1
297 gp%sgraph(part(i))%nodeInPart(core_count((part(i))) - copy_core_count(part(i)) ) = i -1
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 )
325 subroutine prg_costpartition(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
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(:,:)
340 totalparts = gp%totalParts
341 totalnodes = gp%totalNodes
349 ch_count(partnumber(i)) = ch_count(partnumber(i)) + 1
350 core_count(partnumber(i)) = core_count(partnumber(i)) + 1
351 do j = xadj(i), xadj(i + 1) - 1
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
356 halo_count(partnumber(i), neighbor) = 1
358 halo_count(partnumber(i), neighbor) = halo_count(partnumber(i), neighbor) + 1
365 if (core_count(i) <= 1)
then
366 print *,
"core count <= 1 for partition "//
to_string(i)//
"!"
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
376 smooth_maxch = smooth_maxch**(1/pnorm)
399 subroutine update_prg_costpartition(gp, xadj, adjncy, partNumber,core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH, pnorm, node, new_part)
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(:,:)
412 totalparts = gp%totalParts
413 totalnodes = gp%totalNodes
414 old_part = partnumber(node)
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
420 ch_count(new_part) = ch_count(new_part) + 1
421 do i=xadj(node), xadj(node+1) -1
423 if (node /= neighbor)
then
424 if(partnumber(neighbor) == old_part)
then
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
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
433 else if (partnumber(neighbor) == new_part)
then
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
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"
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
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"
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
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"
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
466 partnumber(node) = new_part
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)
478 smooth_maxch = smooth_maxch**(1/pnorm)
488 integer,
intent(in) :: it
489 real(dp),
intent(in) :: prg_delta
490 real,
intent(inout) :: r
494 if (prg_delta > 0)
then
495 r = exp(-(prg_delta/10.0)/temp)
506 real(dp),
intent (inout) :: cost, maxCH,smooth_maxCH, sumCubes
507 integer,
intent (inout) :: obj_fun
511 if (obj_fun .eq. 0)
then
513 else if (obj_fun .eq. 1)
then
515 else if (obj_fun .eq. 2)
then
526 type (graph_partitioning_t),
intent(inout) :: gp
527 integer,
intent(inout) :: node, seed
528 integer :: totalNodes, i, ssize
529 integer,
allocatable :: seedin(:)
533 call random_seed(size=ssize)
534 allocate(seedin(ssize))
536 call random_seed(put=seedin)
538 call random_number(u)
539 node = floor(gp%totalNodes*u) + 1
557 subroutine prg_simannealing(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH,pnorm, niter, seed)
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
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
573 character(len=100) :: pname
575 integer,
allocatable :: seedin(:)
577 totalparts = gp%totalParts
578 totalnodes = gp%totalNodes
579 totalnodes2 = gp%totalNodes2
580 allocate(copy_core_count(totalparts))
581 allocate(empty_parts(totalparts))
584 call random_seed(size=ssize)
585 allocate(seedin(ssize))
587 call random_seed(put=seedin)
589 write(*,*)
"SA called..."
590 if (totalnodes .lt. totalparts)
then
591 write(*,*)
"ERROR: Number of parts cannot be greater than number of nodes."
596 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
599 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
608 if (ch_count(min_ch_part) .gt. ch_count(k))
then
615 if (ch_count( partnumber(node) ) .eq. maxch)
then
616 do j = xadj(node), xadj(node+1)-1
618 part_backup = partnumber(neighbor)
620 smooth_maxch, pnorm, neighbor, min_ch_part)
621 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
624 call random_number(u)
626 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
632 if (ch_count( min_ch_part) .eq. 0)
then
633 do j = xadj(node), xadj(node+1)-1
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)
640 call random_number(u)
642 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
648 do j = xadj(node), xadj(node+1)-1
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)
655 call random_number(u)
657 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
670 if (ch_count(i) .eq. 0)
then
671 no_empty_parts = no_empty_parts + 1
672 empty_parts(no_empty_parts) = i
677 if (no_empty_parts .le. 0)
then
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 )
685 no_empty_parts = no_empty_parts - 1
688 do j = xadj(node), xadj(node+1)-1
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
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)
706 write(*,*)
"Cost of meTIS+SA", sumcubes, maxch, smooth_maxch
714 write(pname,
'("SAParts")')
717 gp%nnodesInPartAll(i) = core_count(i)
718 copy_core_count(i) = core_count(i)
720 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
721 gp%nnodesInPart(i) = core_count(i)
725 do i=1, gp%totalNodes
726 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
728 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
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 )
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"
771 subroutine prg_kernlin(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, nconverg, seed)
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
787 integer,
allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), empty_parts(:)
788 character(len=100) :: pname
790 totalnodes = gp%totalNodes
791 totalnodes2 = gp%totalNodes2
792 totalparts = gp%totalParts
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))
826 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
829 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
831 prev_iteration_cost = cost
837 do while ( converge .eq. 0 .and. iit .lt. nconverg)
844 do i=1, gp%totalNodes
848 minch = totalnodes + 1
850 if (ch_count(j) .lt. minch)
then
855 if (min_part .eq. -1)
then
856 min_part = partnumber(h)
857 do j = xadj(h), xadj(h+1)-1
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)
866 if (counter == totalparts)
then
875 write(*,*)
"error h =0"
880 do j = xadj(h), xadj(h+1)-1
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
891 no_locked_nodes = no_locked_nodes + climb_counter
901 vertex_locked(node_backup(climb_counter)) = 1
902 climb_counter = climb_counter - 1
908 node_part_backup = -1
911 if (climb_counter .lt. max_climb)
then
912 climb_counter = climb_counter + 1
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)
918 climb_counter = climb_counter - 1
920 if (prev_cost .ne. cost)
then
921 write(*,*)
"ERROR: There was an error in undo step 2", node, cost, prev_cost, j
932 if(prev_cost .ne. cost)
then
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)
942 if (prev_cost .ne. cost)
then
943 write(*,*)
"ERROR: Undo after hyperedge"
949 if (no_locked_nodes .eq. gp%totalNodes)
then
957 if (core_count(j) .eq. 0)
then
958 empty_counter = empty_counter +1
959 empty_parts(empty_counter) = j
962 if (empty_counter .gt. 0)
then
964 if (ch_count(partnumber(j) ) .eq. maxch)
then
965 do k = xadj(j), xadj(j+1)-1
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)
974 if (prev_maxch .lt. maxch)
then
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)
982 empty_counter = empty_counter - 1
983 if (empty_counter .eq. 0)
then
992 if (prev_iteration_cost .eq. cost)
then
993 convg_counter = convg_counter + 1
994 if (convg_counter .eq. nconverg)
then
998 prev_iteration_cost = cost
1009 if (ch_count(i) .eq. 0)
then
1010 no_empty_parts = no_empty_parts + 1
1011 empty_parts(no_empty_parts) = i
1015 do node=1,totalnodes
1016 if (no_empty_parts .le. 0)
then
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 )
1024 no_empty_parts = no_empty_parts - 1
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
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)
1051 write(*,*)
"Cost of KL:", cost, maxch,
"No iterations:", iit
1057 write(pname,
'("KLParts")')
1061 do i = 1, totalparts
1062 gp%nnodesInPartAll(i) = core_count(i)
1063 copy_core_count(i) = core_count(i)
1065 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1066 gp%nnodesInPart(i) = core_count(i)
1070 do i=1, gp%totalNodes
1071 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1073 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
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"
1084 deallocate(vertex_locked)
1085 deallocate(hedge_span)
1086 deallocate(node_backup)
1087 deallocate(node_part_backup)
1089 deallocate(copy_core_count)
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
1103 totalnodes = gp%totalNodes
1104 totalnodes2 = gp%totalNodes2
1105 totalparts = gp%totalParts
1106 allocate(copy_core_count(totalparts))
1111 write(pname,
'("Parts")')
1115 do i = 1, totalparts
1116 gp%nnodesInPartAll(i) = core_count(i)
1117 copy_core_count(i) = core_count(i)
1119 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1120 gp%nnodesInPart(i) = core_count(i)
1124 do i=1, gp%totalNodes
1125 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1127 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
1131 deallocate(copy_core_count)
1138 integer,
intent(inout) :: array(:), seed
1139 integer :: i, randpos, temp, ssize
1140 integer,
allocatable :: seedin(:)
1146 call random_seed(size=ssize)
1147 allocate(seedin(ssize))
1149 call random_seed(put=seedin)
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)
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
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
1180 if (check /= ch_count(i))
then
1182 write(*,*)
"ERROR: Halo_count is incorrect!"
1183 write(*,*)
"check=", check,
"CH_count(i)", ch_count(i)
1188 write(*,*)
"prg_check_arrays PASSED!"
1193 subroutine prg_kernlin_queue(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
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
1206 integer,
allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), emptyparts(:)
1207 character(len=100) :: pname
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"
1217 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, best_node, best_part)
1221 write(*,*)
"kl finished", gp%totalParts
1222 do i=1,gp%totalParts
1223 write(*,*)
"part=", i, core_count(i),
"ch=", ch_count(i)
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 )
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
1244 integer,
allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), emptyParts(:)
1245 character(len=100) :: pname
1250 totalnodes = gp%totalNodes
1251 totalnodes2 = gp%totalNodes2
1252 totalparts = gp%totalParts
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)
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)
1266 if (cost .le. best_obj_val)
then
1271 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, i, backup)
1277 subroutine prg_kernlin2(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
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(:)
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
1296 totalnodes = gp%totalNodes
1297 totalnodes2 = gp%totalNodes2
1298 totalparts = gp%totalParts
1301 allocate(copy_core_count(totalparts))
1302 allocate(empty_parts(totalparts))
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)
1308 do i = 1, totalparts
1312 call random_number(r)
1313 if (r .ge. 0.7)
then
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)
1323 if (ch_count(min_ch_part) .gt. ch_count(k))
then
1330 if (ch_count(partnumber(largest_hedge)) .eq. maxch)
then
1332 new_part = min_ch_part
1334 new_part = partnumber(largest_hedge)
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
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)
1362 if (ch_count(i) .eq. 0)
then
1363 no_empty_parts = no_empty_parts + 1
1364 empty_parts(no_empty_parts) = i
1369 do node=1,totalnodes
1370 if (no_empty_parts .le. 0)
then
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 )
1378 no_empty_parts = no_empty_parts - 1
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
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)
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 )
1401 no_empty_parts = no_empty_parts - 1
1410 write(pname,
'("KLParts")')
1414 do i = 1, totalparts
1415 gp%nnodesInPartAll(i) = core_count(i)
1416 copy_core_count(i) = core_count(i)
1418 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1419 gp%nnodesInPart(i) = core_count(i)
1423 do i=1, gp%totalNodes
1424 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1426 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
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"
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
1456 totalnodes = gp%totalNodes
1457 totalnodes2 = gp%totalNodes2
1458 totalparts = gp%totalParts
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)
1474 subroutine prg_simannealing_old(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH,pnorm, niter, seed)
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(:)
1489 character(len=100) :: pname
1491 totalparts = gp%totalParts
1492 totalnodes = gp%totalNodes
1493 totalnodes2 = gp%totalNodes2
1495 allocate(copy_core_count(totalparts))
1496 allocate(empty_parts(totalparts))
1498 write(*,*)
"SA called..."
1499 if (totalnodes .lt. totalparts)
then
1500 write(*,*)
"ERROR: Number of parts cannot be greater than number of nodes."
1505 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
1508 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
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)
1521 call random_number(u)
1523 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
1534 write(*,*)
"Cost of meTIS+SA", sumcubes, maxch, smooth_maxch
1542 write(pname,
'("SAParts")')
1544 do i = 1, totalparts
1545 gp%nnodesInPartAll(i) = core_count(i)
1546 copy_core_count(i) = core_count(i)
1548 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1549 gp%nnodesInPart(i) = core_count(i)
1553 do i=1, gp%totalNodes
1554 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1556 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
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 )
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"
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.
integer function, public printrank()
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.