12 use,
intrinsic :: iso_c_binding
18 integer,
parameter ::
dp = kind(1.0d0)
47 integer function metis_setdefaultoptions(options) &
48 bind(C, name="METIS_SetDefaultOptions")
52 integer(kind=metis_index_kind),
intent(in) :: options(*)
54 end function metis_setdefaultoptions
56 integer function metis_partgraphkway(nvtxs, ncon, xadj, adjncy, vwgt, &
57 vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part) &
58 bind(C, name="METIS_PartGraphKway")
63 integer(kind=metis_index_kind),
intent(in) :: nvtxs(*)
64 integer(kind=metis_index_kind),
intent(in) :: ncon(*)
65 integer(kind=metis_index_kind),
intent(in) :: xadj(*)
66 integer(kind=metis_index_kind),
intent(in) :: adjncy(*)
67 integer(kind=metis_index_kind),
intent(in) :: vwgt(*)
68 integer(kind=metis_index_kind),
intent(in) :: vsize(*)
69 integer(kind=metis_index_kind),
intent(in) :: adjwgt(*)
70 integer(kind=metis_index_kind),
intent(in) :: nparts(*)
73 integer(kind=metis_index_kind),
intent(in) :: options(*)
74 integer(kind=metis_index_kind),
intent(inout) :: objval(*)
75 integer(kind=metis_index_kind),
intent(inout) :: part(*)
77 end function metis_partgraphkway
85 subroutine metis_setdefaultoptions_wrapper(options)
87 integer(kind=metis_index_kind),
intent(in) :: options(:)
90 result = metis_setdefaultoptions(options)
92 write(*, *)
"error calling METIS_SetDefaultOptions"
96 end subroutine metis_setdefaultoptions_wrapper
98 subroutine metis_partgraphkway_wrapper(nvtxs, ncon, xadj, adjncy, vwgt, &
99 vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part)
101 integer,
intent(in) :: nvtxs
102 integer,
intent(in) :: ncon
103 integer,
intent(in) :: xadj(:)
104 integer,
intent(in) :: adjncy(:)
105 integer,
pointer,
intent(in) :: vwgt(:)
106 integer,
pointer,
intent(in) :: vsize(:)
107 integer,
pointer,
intent(in) :: adjwgt(:)
108 integer,
intent(in) :: nparts
109 double precision,
pointer,
intent(in) :: tpwgts(:)
110 double precision,
pointer,
intent(in) :: ubvec(:)
111 integer(kind=metis_index_kind),
intent(in) :: options(:)
112 integer,
intent(inout) :: objval
113 integer,
intent(inout) :: part(:)
115 integer(kind=metis_index_kind) :: nvtxs_metis(1)
116 integer(kind=metis_index_kind) :: ncon_metis(1)
117 integer(kind=metis_index_kind),
allocatable :: xadj_metis(:)
118 integer(kind=metis_index_kind),
allocatable :: adjncy_metis(:)
119 integer(kind=metis_index_kind),
pointer :: vwgt_metis(:) => null()
120 integer(kind=metis_index_kind),
pointer :: vsize_metis(:) => null()
121 integer(kind=metis_index_kind),
pointer :: adjwgt_metis(:) => null()
122 integer(kind=metis_index_kind) :: nparts_metis(1)
125 integer(kind=metis_index_kind) :: objval_metis(1)
126 integer(kind=metis_index_kind),
allocatable :: part_metis(:)
130 nvtxs_metis(1) = nvtxs
133 allocate(xadj_metis(
size(xadj)))
136 allocate(adjncy_metis(
size(adjncy)))
137 adjncy_metis = adjncy
139 if (
associated(vwgt))
then
140 allocate(vwgt_metis(
size(vwgt)))
144 if (
associated(vsize))
then
145 allocate(vsize_metis(
size(vsize)))
149 if (
associated(adjwgt))
then
150 allocate(adjwgt_metis(
size(adjwgt)))
151 adjwgt_metis = adjwgt
154 nparts_metis(1) = nparts
156 if (
associated(tpwgts))
then
157 allocate(tpwgts_metis(
size(tpwgts)))
158 tpwgts_metis = tpwgts
161 if (
associated(ubvec))
then
162 allocate(ubvec_metis(
size(ubvec)))
166 objval_metis(1) = objval
169 result = metis_partgraphkway(nvtxs_metis, ncon_metis, xadj_metis, adjncy_metis, vwgt_metis, vsize_metis, adjwgt_metis, &
170 nparts_metis, tpwgts_metis, ubvec_metis, options, objval_metis, part_metis)
171 if (result /= 1)
then
172 write(*, *)
"error calling METIS_PartGraphKway"
176 if (
associated(vwgt_metis))
then
177 deallocate(vwgt_metis)
180 if (
associated(vsize_metis))
then
181 deallocate(vsize_metis)
184 if (
associated(adjwgt_metis))
then
185 deallocate(adjwgt_metis)
188 if (
associated(tpwgts_metis))
then
189 deallocate(tpwgts_metis)
192 if (
associated(ubvec_metis))
then
193 deallocate(ubvec_metis)
196 objval = objval_metis(1)
199 end subroutine metis_partgraphkway_wrapper
216 subroutine prg_metispartition(gp, ngroups, nnodes, xadj, adjncy, nparts, part, core_count, CH_count, Halo_count, sumCubes, &
217 maxCH, smooth_maxCH, pnorm)
223 integer(kind=metis_index_kind),
allocatable :: options(:)
224 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:), part(:)
225 integer,
intent(inout) :: nparts
226 integer :: ncon, objval
228 integer,
target :: dummy_vwgt, dummy_vsize, dummy_adjwgt
229 real(8),
target :: dummy_tpwgts, dummy_ubvec
230 real(
dp),
intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
231 integer,
intent (in) :: ngroups, nnodes
232 integer,
allocatable,
intent(inout) :: ch_count(:), core_count(:)
233 integer,
allocatable,
intent(inout) :: halo_count(:,:)
234 integer,
allocatable :: copy_core_count(:)
235 integer,
pointer :: vwgt(:) => null(), vsize(:) => null(), adjwgt(:) => null()
238 real(8),
pointer :: tpwgts(:) => null(), ubvec(:) => null()
239 character(len=100) :: pname
241 allocate(options(40))
242 allocate(copy_core_count(nparts))
244 write(pname,
'("metisParts")')
248 call metis_setdefaultoptions_wrapper(options)
265 write(*,*)
"prg_metisPartition_test start ..."
275 call metis_partgraphkway_wrapper(gp%totalNodes, ncon, xadj, adjncy, vwgt, &
276 vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part)
280 call prg_costpartition(gp, xadj, adjncy, part, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
285 gp%nnodesInPartAll(i) = core_count(i)
286 copy_core_count(i) = core_count(i)
288 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
289 gp%nnodesInPart(i) = core_count(i)
293 do i = 1, gp%totalNodes
294 copy_core_count(part(i)) = copy_core_count(part(i)) - 1
298 gp%sgraph(part(i))%nodeInPart(core_count((part(i))) - copy_core_count(part(i)) ) = i -1
301 do j = 1, core_count(i)
302 if( part( gp%sgraph(i)%nodeInPart(j)+1 ) /= i)
then
303 write(*,*)
"ERROR: subgraph struc incorrect!!",
"node=",gp%sgraph(i)%nodeInPart(j)+1 , &
304 "part=",i,
"actual_part=", part(gp%sgraph(i)%nodeInPart(j)+1 )
326 subroutine prg_costpartition(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
329 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
330 integer,
allocatable,
intent(in) :: partnumber(:)
331 integer,
allocatable,
intent(inout) :: core_count(:)
332 integer :: totalparts, totalnodes, i, j, neighbor
333 real(
dp),
intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
334 integer,
allocatable,
intent(inout) :: ch_count(:)
335 integer,
allocatable,
intent(inout) :: halo_count(:,:)
341 totalparts = gp%totalParts
342 totalnodes = gp%totalNodes
350 ch_count(partnumber(i)) = ch_count(partnumber(i)) + 1
351 core_count(partnumber(i)) = core_count(partnumber(i)) + 1
352 do j = xadj(i), xadj(i + 1) - 1
354 if (partnumber(i) /= partnumber(neighbor))
then
355 if (halo_count(partnumber(i) ,neighbor) == 0)
then
356 ch_count(partnumber(i)) = ch_count(partnumber(i)) + 1
357 halo_count(partnumber(i), neighbor) = 1
359 halo_count(partnumber(i), neighbor) = halo_count(partnumber(i), neighbor) + 1
366 if (core_count(i) <= 1)
then
367 print *,
"core count <= 1 for partition "//
to_string(i)//
"!"
370 temp = real(ch_count(i),
dp)
371 sumcubes = sumcubes+ temp*temp*temp
372 smooth_maxch = smooth_maxch + temp**int(pnorm)
373 if (ch_count(i) > maxch)
then
377 smooth_maxch = smooth_maxch**(1/pnorm)
400 subroutine update_prg_costpartition(gp, xadj, adjncy, partNumber,core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH, pnorm, node, new_part)
403 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
404 integer,
allocatable,
intent(inout) :: partnumber(:), core_count(:)
405 integer :: totalparts, totalnodes, i, j, neighbor
406 real(
dp),
intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
407 integer,
intent (in) :: node, new_part
408 integer,
allocatable,
intent(inout) :: ch_count(:)
409 integer,
allocatable,
intent(inout) :: halo_count(:,:)
413 totalparts = gp%totalParts
414 totalnodes = gp%totalNodes
415 old_part = partnumber(node)
417 if (old_part /= new_part)
then
418 core_count(new_part) = core_count(new_part) + 1
419 core_count(old_part) = core_count(old_part) - 1
420 ch_count(old_part) = ch_count(old_part) - 1
421 ch_count(new_part) = ch_count(new_part) + 1
422 do i=xadj(node), xadj(node+1) -1
424 if (node /= neighbor)
then
425 if(partnumber(neighbor) == old_part)
then
426 halo_count(old_part, node) = halo_count(old_part, node) + 1
427 if (halo_count(old_part, node) == 1)
then
428 ch_count(old_part) = ch_count(old_part) + 1
430 halo_count(new_part, neighbor) = halo_count(new_part, neighbor) + 1
431 if (halo_count(new_part, neighbor) == 1)
then
432 ch_count(new_part) = ch_count(new_part) + 1
434 else if (partnumber(neighbor) == new_part)
then
435 halo_count(old_part, neighbor) = halo_count(old_part, neighbor) - 1
436 if (halo_count(old_part, neighbor) == 0)
then
437 ch_count(old_part) = ch_count(old_part) - 1
438 else if (halo_count(old_part, neighbor) < 0)
then
439 write(*,*)
"ERROR: Halo_count value cannot be negative, case 2i"
440 write(*,*)
"input matrix should be perfectly symmetric"
443 halo_count(new_part, node) = halo_count(new_part, node) - 1
444 if (halo_count(new_part, node) == 0)
then
445 ch_count(new_part) = ch_count(new_part) - 1
446 else if (halo_count(new_part, node) < 0)
then
447 write(*,*)
"ERROR: Halo_count value cannot be negative, case 2ii"
448 write(*,*)
"input matrix should be perfectly symmetric"
452 halo_count(old_part, neighbor) = halo_count(old_part, neighbor) - 1
453 if (halo_count(old_part, neighbor) == 0)
then
454 ch_count(old_part) = ch_count(old_part) - 1
455 else if (halo_count(old_part, neighbor) < 0)
then
456 write(*,*)
"ERROR: Halo_count value cannot be negative, case 3"
457 write(*,*)
"input matrix should be perfectly symmetric"
460 halo_count(new_part, neighbor) = halo_count(new_part, neighbor) + 1
461 if (halo_count(new_part, neighbor) == 1)
then
462 ch_count(new_part) = ch_count(new_part) + 1
467 partnumber(node) = new_part
472 temp = real(ch_count(i),
dp)
473 sumcubes = sumcubes+ temp*temp*temp
474 smooth_maxch = smooth_maxch + temp**int(pnorm)
475 if (ch_count(i) > maxch)
then
476 maxch = real(ch_count(i),
dp)
479 smooth_maxch = smooth_maxch**(1/pnorm)
489 integer,
intent(in) :: it
490 real(dp),
intent(in) :: prg_delta
491 real,
intent(inout) :: r
495 if (prg_delta > 0)
then
496 r = exp(-(prg_delta/10.0)/temp)
507 real(dp),
intent (inout) :: cost, maxCH,smooth_maxCH, sumCubes
508 integer,
intent (inout) :: obj_fun
512 if (obj_fun .eq. 0)
then
514 else if (obj_fun .eq. 1)
then
516 else if (obj_fun .eq. 2)
then
527 type (graph_partitioning_t),
intent(inout) :: gp
528 integer,
intent(inout) :: node, seed
529 integer :: totalNodes, i, ssize
530 integer,
allocatable :: seedin(:)
534 call random_seed(size=ssize)
535 allocate(seedin(ssize))
537 call random_seed(put=seedin)
539 call random_number(u)
540 node = floor(gp%totalNodes*u) + 1
558 subroutine prg_simannealing(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH,pnorm, niter, seed)
561 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
562 integer,
allocatable,
intent(inout) :: partnumber(:), core_count(:)
563 integer :: totalparts, totalnodes, it, i,j,k, neighbor, node, part_backup
564 integer :: totalnodes2
566 real(
dp),
intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
567 integer,
intent (in) :: niter
568 integer,
intent(inout) :: seed
569 integer,
allocatable,
intent(inout) :: ch_count(:)
570 integer,
allocatable,
intent(inout) :: halo_count(:,:)
571 integer,
allocatable :: copy_core_count(:), empty_parts(:)
572 integer :: obj_fun = 2, min_ch_part, no_empty_parts, new_part
574 character(len=100) :: pname
576 integer,
allocatable :: seedin(:)
578 totalparts = gp%totalParts
579 totalnodes = gp%totalNodes
580 totalnodes2 = gp%totalNodes2
581 allocate(copy_core_count(totalparts))
582 allocate(empty_parts(totalparts))
585 call random_seed(size=ssize)
586 allocate(seedin(ssize))
588 call random_seed(put=seedin)
590 write(*,*)
"SA called..."
591 if (totalnodes .lt. totalparts)
then
592 write(*,*)
"ERROR: Number of parts cannot be greater than number of nodes."
597 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
600 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
609 if (ch_count(min_ch_part) .gt. ch_count(k))
then
616 if (ch_count( partnumber(node) ) .eq. maxch)
then
617 do j = xadj(node), xadj(node+1)-1
619 part_backup = partnumber(neighbor)
621 smooth_maxch, pnorm, neighbor, min_ch_part)
622 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
625 call random_number(u)
627 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
633 if (ch_count( min_ch_part) .eq. 0)
then
634 do j = xadj(node), xadj(node+1)-1
636 part_backup = partnumber(neighbor)
637 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, min_ch_part)
638 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
641 call random_number(u)
643 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
649 do j = xadj(node), xadj(node+1)-1
651 part_backup = partnumber(neighbor)
652 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, partnumber(node))
653 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
656 call random_number(u)
658 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
671 if (ch_count(i) .eq. 0)
then
672 no_empty_parts = no_empty_parts + 1
673 empty_parts(no_empty_parts) = i
678 if (no_empty_parts .le. 0)
then
682 if (ch_count(partnumber(node)) .eq. maxch)
then
683 new_part = empty_parts(no_empty_parts)
684 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
686 no_empty_parts = no_empty_parts - 1
689 do j = xadj(node), xadj(node+1)-1
691 if (ch_count(partnumber(neighbor)) .eq. maxch)
then
692 part_backup = partnumber(neighbor)
693 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, neighbor, new_part)
694 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
695 if (maxch .ge. prev_maxch)
then
696 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup )
697 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
707 write(*,*)
"Cost of meTIS+SA", sumcubes, maxch, smooth_maxch
715 write(pname,
'("SAParts")')
718 gp%nnodesInPartAll(i) = core_count(i)
719 copy_core_count(i) = core_count(i)
721 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
722 gp%nnodesInPart(i) = core_count(i)
726 do i=1, gp%totalNodes
727 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
729 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
735 do j = 1, core_count(i)
736 if( partnumber( gp%sgraph(i)%nodeInPart(j)+1 ) /= i)
then
737 write(*,*)
"ERROR: subgraph struc incorrect!!",
"node=",gp%sgraph(i)%nodeInPart(j)+1 ,
"part=",i,
"actual_part=", partnumber(gp%sgraph(i)%nodeInPart(j)+1 )
743 write(*,*)
"part=",i,
"C=", core_count(i),
"CH=", ch_count(i)
744 if (ch_count(i) .eq. 0)
then
745 write(*,*)
"ERROR: SA produced an empty part"
772 subroutine prg_kernlin(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, nconverg, seed)
775 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
776 integer,
allocatable,
intent(inout) :: partnumber(:), core_count(:)
777 integer :: totalparts, totalnodes, i, iit, j,k, neighbor, node, part_backup, h, node2
778 real(
dp),
intent(inout) :: sumcubes, maxch, smooth_maxch, pnorm
779 real(
dp) :: cost, prev_cost, prev_iteration_cost, prev_maxch, minch
780 integer,
intent(inout) :: seed
781 integer,
intent(in) :: nconverg
782 integer,
allocatable,
intent(inout) :: ch_count(:)
783 integer,
allocatable,
intent(inout) :: halo_count(:,:)
784 integer,
allocatable :: copy_core_count(:)
785 integer :: obj_fun = 2, counter, min_part, max_climb = 1, climb_counter, temp, convg_counter, converge, no_locked_nodes, empty_counter, backup, best_node, best_part,no_empty_parts, new_part
786 integer :: totalnodes2
788 integer,
allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), empty_parts(:)
789 character(len=100) :: pname
791 totalnodes = gp%totalNodes
792 totalnodes2 = gp%totalNodes2
793 totalparts = gp%totalParts
796 allocate(vertex_locked(totalnodes))
797 allocate(hedge_span(totalparts))
798 allocate(node_backup(totalnodes))
799 allocate(node_part_backup(totalnodes))
800 allocate(nodes(totalnodes))
801 allocate(copy_core_count(totalparts))
802 allocate(empty_parts(totalparts))
827 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
830 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
832 prev_iteration_cost = cost
838 do while ( converge .eq. 0 .and. iit .lt. nconverg)
845 do i=1, gp%totalNodes
849 minch = totalnodes + 1
851 if (ch_count(j) .lt. minch)
then
856 if (min_part .eq. -1)
then
857 min_part = partnumber(h)
858 do j = xadj(h), xadj(h+1)-1
860 if (hedge_span( partnumber(node))==0)
then
861 counter = counter + 1
862 hedge_span( partnumber(node)) = ch_count(partnumber(node))
863 if (ch_count(partnumber(node)) .le. ch_count(min_part))
then
864 min_part = partnumber(node)
867 if (counter == totalparts)
then
876 write(*,*)
"error h =0"
881 do j = xadj(h), xadj(h+1)-1
884 if (vertex_locked(node) .eq. 0 )
then
885 part_backup = partnumber(node)
886 node_part_backup(climb_counter) = part_backup
887 node_backup(climb_counter) = node
888 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node, min_part)
889 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
890 if (cost .le. prev_cost)
then
892 no_locked_nodes = no_locked_nodes + climb_counter
902 vertex_locked(node_backup(climb_counter)) = 1
903 climb_counter = climb_counter - 1
909 node_part_backup = -1
912 if (climb_counter .lt. max_climb)
then
913 climb_counter = climb_counter + 1
916 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node_backup(climb_counter), node_part_backup(climb_counter))
917 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
919 climb_counter = climb_counter - 1
921 if (prev_cost .ne. cost)
then
922 write(*,*)
"ERROR: There was an error in undo step 2", node, cost, prev_cost, j
933 if(prev_cost .ne. cost)
then
938 climb_counter = climb_counter - 1
939 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node_backup(climb_counter), node_part_backup(climb_counter))
940 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
943 if (prev_cost .ne. cost)
then
944 write(*,*)
"ERROR: Undo after hyperedge"
950 if (no_locked_nodes .eq. gp%totalNodes)
then
958 if (core_count(j) .eq. 0)
then
959 empty_counter = empty_counter +1
960 empty_parts(empty_counter) = j
963 if (empty_counter .gt. 0)
then
965 if (ch_count(partnumber(j) ) .eq. maxch)
then
966 do k = xadj(j), xadj(j+1)-1
969 backup = partnumber(j)
970 if (partnumber(node2) .eq. partnumber(j) )
then
971 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node2,empty_parts(empty_counter) )
972 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
975 if (prev_maxch .lt. maxch)
then
976 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, node2,backup )
977 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
983 empty_counter = empty_counter - 1
984 if (empty_counter .eq. 0)
then
993 if (prev_iteration_cost .eq. cost)
then
994 convg_counter = convg_counter + 1
995 if (convg_counter .eq. nconverg)
then
999 prev_iteration_cost = cost
1010 if (ch_count(i) .eq. 0)
then
1011 no_empty_parts = no_empty_parts + 1
1012 empty_parts(no_empty_parts) = i
1016 do node=1,totalnodes
1017 if (no_empty_parts .le. 0)
then
1021 if (ch_count(partnumber(node)) .eq. maxch .and. core_count(partnumber(node)) .ne. 1 )
then
1022 new_part = empty_parts(no_empty_parts)
1023 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
1025 no_empty_parts = no_empty_parts - 1
1028 do j = xadj(node), xadj(node+1)-1
1029 neighbor = adjncy(j)
1030 if (ch_count(partnumber(neighbor)) .eq. maxch)
then
1031 part_backup = partnumber(neighbor)
1032 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, neighbor, new_part)
1033 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
1034 if (maxch .ge. prev_maxch)
then
1035 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup )
1036 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1052 write(*,*)
"Cost of KL:", cost, maxch,
"No iterations:", iit
1058 write(pname,
'("KLParts")')
1062 do i = 1, totalparts
1063 gp%nnodesInPartAll(i) = core_count(i)
1064 copy_core_count(i) = core_count(i)
1066 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1067 gp%nnodesInPart(i) = core_count(i)
1071 do i=1, gp%totalNodes
1072 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1074 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
1079 write(*,*)
"part=",i,
"C=", core_count(i),
"CH=", ch_count(i)
1080 if (ch_count(i) .eq. 0)
then
1081 write(*,*)
"ERROR: KL produced an empty part"
1085 deallocate(vertex_locked)
1086 deallocate(hedge_span)
1087 deallocate(node_backup)
1088 deallocate(node_part_backup)
1090 deallocate(copy_core_count)
1098 integer,
allocatable,
intent(inout) :: partnumber(:), core_count(:)
1099 integer :: totalparts, totalnodes, i
1100 integer :: totalnodes2
1101 integer,
allocatable :: copy_core_count(:)
1102 character(len=100) :: pname
1104 totalnodes = gp%totalNodes
1105 totalnodes2 = gp%totalNodes2
1106 totalparts = gp%totalParts
1107 allocate(copy_core_count(totalparts))
1112 write(pname,
'("Parts")')
1116 do i = 1, totalparts
1117 gp%nnodesInPartAll(i) = core_count(i)
1118 copy_core_count(i) = core_count(i)
1120 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1121 gp%nnodesInPart(i) = core_count(i)
1125 do i=1, gp%totalNodes
1126 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1128 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
1132 deallocate(copy_core_count)
1139 integer,
intent(inout) :: array(:), seed
1140 integer :: i, randpos, temp, ssize
1141 integer,
allocatable :: seedin(:)
1147 call random_seed(size=ssize)
1148 allocate(seedin(ssize))
1150 call random_seed(put=seedin)
1154 do i =
size(array), 2, -1
1155 call random_number(r)
1156 randpos = int(r * i) + 1
1157 temp = array(randpos)
1158 array(randpos) = array(i)
1169 integer,
allocatable,
intent(inout) :: core_count(:)
1170 integer,
allocatable,
intent(inout) :: ch_count(:)
1171 integer,
allocatable,
intent(inout) :: halo_count(:,:)
1172 integer :: i,j, check
1174 do i=1,gp%totalParts
1175 check = core_count(i)
1176 do j=1, gp%totalNodes
1177 if (halo_count(i,j) >0)
then
1181 if (check /= ch_count(i))
then
1183 write(*,*)
"ERROR: Halo_count is incorrect!"
1184 write(*,*)
"check=", check,
"CH_count(i)", ch_count(i)
1189 write(*,*)
"prg_check_arrays PASSED!"
1194 subroutine prg_kernlin_queue(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
1197 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
1198 integer,
allocatable,
intent(inout) :: partnumber(:), core_count(:)
1199 integer :: totalparts, totalnodes, i, iit, j,k, neighbor, node, part_backup, h, node2
1200 real(
dp),
intent(inout) :: sumcubes, maxch, smooth_maxch, pnorm
1201 real(
dp) :: cost, prev_cost, prev_iteration_cost, prev_maxch, minch, best_obj_val, current_cost
1202 integer,
allocatable,
intent(inout) :: ch_count(:)
1203 integer,
allocatable,
intent(inout) :: halo_count(:,:)
1204 integer,
allocatable :: copy_core_count(:)
1205 integer :: backup, best_node, best_part
1207 integer,
allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), emptyparts(:)
1208 character(len=100) :: pname
1213 call prg_find_best_move(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, best_node, best_part )
1214 if(best_node .eq. 0)
then
1215 write(*,*)
"error: node is 0"
1218 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, best_node, best_part)
1222 write(*,*)
"kl finished", gp%totalParts
1223 do i=1,gp%totalParts
1224 write(*,*)
"part=", i, core_count(i),
"ch=", ch_count(i)
1230 subroutine prg_find_best_move(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, best_node, best_part )
1232 type (graph_partitioning_t),
intent(inout) :: gp
1233 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
1234 integer,
allocatable,
intent(inout) :: partNumber(:), core_count(:)
1235 integer :: totalParts, totalNodes, i, iit, j,k, neighbor, node, part_backup, h, node2
1236 integer :: totalNodes2
1237 real(dp),
intent(inout) :: sumCubes, maxCH, smooth_maxCH, pnorm
1238 real(dp) :: cost, prev_cost, prev_iteration_cost, prev_maxCH, minCH, best_obj_val, current_cost
1239 integer,
intent(inout) :: best_node, best_part
1240 integer,
allocatable,
intent(inout) :: CH_count(:)
1241 integer,
allocatable,
intent(inout) :: Halo_count(:,:)
1242 integer,
allocatable :: copy_core_count(:)
1243 integer :: obj_fun = 2, backup
1245 integer,
allocatable :: vertex_locked(:), hedge_span(:), node_backup(:), node_part_backup(:), nodes(:), emptyParts(:)
1246 character(len=100) :: pname
1251 totalnodes = gp%totalNodes
1252 totalnodes2 = gp%totalNodes2
1253 totalparts = gp%totalParts
1257 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
1258 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1263 backup = partnumber(i)
1264 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, i, j)
1265 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1267 if (cost .le. best_obj_val)
then
1272 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, i, backup)
1278 subroutine prg_kernlin2(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm)
1281 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
1282 integer,
allocatable,
intent(inout) :: partnumber(:), core_count(:)
1283 integer :: totalparts, totalnodes, i, it, iit, j,k, neighbor, node, part_backup
1284 integer :: totalnodes2
1285 real(
dp),
intent(inout) :: sumcubes, maxch, smooth_maxch, pnorm
1286 real(
dp) :: cost, prev_cost, prev_maxch, minch
1287 integer,
allocatable,
intent(inout) :: ch_count(:)
1289 integer,
allocatable,
intent(inout) :: halo_count(:,:)
1290 integer,
allocatable :: copy_core_count(:), empty_parts(:)
1291 integer :: obj_fun = 2, largest_hedge = -1, search_part, min_ch_part, new_part, no_empty_parts, seed =1
1292 character(len=100) :: pname
1297 totalnodes = gp%totalNodes
1298 totalnodes2 = gp%totalNodes2
1299 totalparts = gp%totalParts
1302 allocate(copy_core_count(totalparts))
1303 allocate(empty_parts(totalparts))
1305 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
1306 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1309 do i = 1, totalparts
1313 call random_number(r)
1314 if (r .ge. 0.7)
then
1316 call prg_get_largest_hedge_in_part(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, it, largest_hedge)
1324 if (ch_count(min_ch_part) .gt. ch_count(k))
then
1331 if (ch_count(partnumber(largest_hedge)) .eq. maxch)
then
1333 new_part = min_ch_part
1335 new_part = partnumber(largest_hedge)
1339 do j = xadj(largest_hedge), xadj(largest_hedge + 1)-1
1340 neighbor = adjncy(j)
1341 part_backup = partnumber(neighbor)
1342 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, new_part)
1343 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1344 if (cost .gt. prev_cost)
then
1345 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
1346 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1363 if (ch_count(i) .eq. 0)
then
1364 no_empty_parts = no_empty_parts + 1
1365 empty_parts(no_empty_parts) = i
1370 do node=1,totalnodes
1371 if (no_empty_parts .le. 0)
then
1375 if (ch_count(partnumber(node)) .eq. maxch .and. core_count(partnumber(node)) .ne. 1 )
then
1376 new_part = empty_parts(no_empty_parts)
1377 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
1379 no_empty_parts = no_empty_parts - 1
1382 do j = xadj(node), xadj(node+1)-1
1383 neighbor = adjncy(j)
1384 if (ch_count(partnumber(neighbor)) .eq. maxch)
then
1385 part_backup = partnumber(neighbor)
1386 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch,smooth_maxch, pnorm, neighbor, new_part)
1387 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
1388 if (maxch .ge. prev_maxch)
then
1389 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup )
1390 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1398 else if (core_count(partnumber(node)) .ne. 1 )
then
1399 new_part = empty_parts(no_empty_parts)
1400 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, node,new_part )
1402 no_empty_parts = no_empty_parts - 1
1411 write(pname,
'("KLParts")')
1415 do i = 1, totalparts
1416 gp%nnodesInPartAll(i) = core_count(i)
1417 copy_core_count(i) = core_count(i)
1419 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1420 gp%nnodesInPart(i) = core_count(i)
1424 do i=1, gp%totalNodes
1425 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1427 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
1432 write(*,*)
"part=",i,
"C=", core_count(i),
"CH=", ch_count(i)
1433 if (ch_count(i) .eq. 0)
then
1434 write(*,*)
"ERROR: KL produced an empty part"
1442 subroutine prg_get_largest_hedge_in_part(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH, smooth_maxCH, pnorm, search_part, largest_Hedge)
1443 type (graph_partitioning_t),
intent(inout) :: gp
1444 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
1445 integer,
allocatable,
intent(inout) :: partNumber(:), core_count(:)
1446 integer :: totalParts, totalNodes, i, iit, j,k, neighbor, node
1447 integer :: totalNodes2
1448 real(dp),
intent(inout) :: sumCubes, maxCH, smooth_maxCH, pnorm
1449 integer,
allocatable,
intent(inout) :: CH_count(:)
1450 integer,
allocatable,
intent(inout) :: Halo_count(:,:)
1451 integer,
allocatable :: copy_core_count(:)
1452 integer :: obj_fun = 2, largest_hsize
1453 integer,
intent(inout) :: search_part, largest_Hedge
1457 totalnodes = gp%totalNodes
1458 totalnodes2 = gp%totalNodes2
1459 totalparts = gp%totalParts
1464 if (partnumber(i) .eq. search_part)
then
1465 if ( xadj(i + 1) - xadj(i) .gt. largest_hsize)
then
1466 largest_hsize = xadj(i + 1) - xadj(i)
1475 subroutine prg_simannealing_old(gp, xadj, adjncy, partNumber, core_count, CH_count, Halo_count, sumCubes, maxCH,smooth_maxCH,pnorm, niter, seed)
1478 integer,
allocatable,
intent(inout) :: xadj(:), adjncy(:)
1479 integer,
allocatable,
intent(inout) :: partnumber(:), core_count(:)
1480 integer :: totalparts, totalnodes, it, i,j,k, neighbor, node, part_backup, obj_fun=0
1481 integer :: totalnodes2
1482 real(
dp) :: cost, prev_cost,
prg_delta, prev_maxch
1483 real(
dp),
intent (inout) :: sumcubes, maxch, smooth_maxch, pnorm
1484 integer,
intent (in) :: niter
1485 integer,
intent(inout) :: seed
1486 integer,
allocatable,
intent(inout) :: ch_count(:)
1487 integer,
allocatable,
intent(inout) :: halo_count(:,:)
1488 integer,
allocatable :: copy_core_count(:), empty_parts(:)
1490 character(len=100) :: pname
1492 totalparts = gp%totalParts
1493 totalnodes = gp%totalNodes
1494 totalnodes2 = gp%totalNodes2
1496 allocate(copy_core_count(totalparts))
1497 allocate(empty_parts(totalparts))
1499 write(*,*)
"SA called..."
1500 if (totalnodes .lt. totalparts)
then
1501 write(*,*)
"ERROR: Number of parts cannot be greater than number of nodes."
1506 call prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm)
1509 call prg_costindex(cost, sumcubes, maxch,smooth_maxch, obj_fun)
1515 do j = xadj(node), xadj(node+1)-1
1516 neighbor = adjncy(j)
1517 part_backup = partnumber(neighbor)
1518 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, partnumber(node))
1519 call prg_costindex(cost, sumcubes, maxch, smooth_maxch, obj_fun)
1522 call random_number(u)
1524 call update_prg_costpartition(gp, xadj, adjncy, partnumber, core_count, ch_count, halo_count, sumcubes, maxch, smooth_maxch, pnorm, neighbor, part_backup)
1535 write(*,*)
"Cost of meTIS+SA", sumcubes, maxch, smooth_maxch
1543 write(pname,
'("SAParts")')
1545 do i = 1, totalparts
1546 gp%nnodesInPartAll(i) = core_count(i)
1547 copy_core_count(i) = core_count(i)
1549 allocate(gp%sgraph(i)%nodeInPart(core_count(i)))
1550 gp%nnodesInPart(i) = core_count(i)
1554 do i=1, gp%totalNodes
1555 copy_core_count(partnumber(i)) =copy_core_count(partnumber(i)) - 1
1557 gp%sgraph(partnumber(i))%nodeInPart(core_count((partnumber(i))) - copy_core_count(partnumber(i)) ) = i -1
1562 do i = 1, totalparts
1563 do j = 1, core_count(i)
1564 if( partnumber( gp%sgraph(i)%nodeInPart(j)+1 ) /= i)
then
1565 write(*,*)
"ERROR: subgraph struc incorrect!!",
"node=",gp%sgraph(i)%nodeInPart(j)+1 ,
"part=",i,
"actual_part=", partnumber(gp%sgraph(i)%nodeInPart(j)+1 )
1571 write(*,*)
"part=",i,
"C=", core_count(i),
"CH=", ch_count(i)
1572 if (ch_count(i) .eq. 0)
then
1573 write(*,*)
"ERROR: SA produced an empty part"
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.