20 public :: hecmwst_mf_symbolic
32 type hecmwst_mf_symbolic
33 integer(kind=kint) :: nnode = 0
34 integer(kind=kint) :: nsuper = 0
35 integer(kind=kint) :: nmerge = 0
36 integer(kind=kint),
allocatable :: perm(:)
37 integer(kind=kint),
allocatable :: invp(:)
38 integer(kind=kint),
allocatable :: ndof(:)
39 integer(kind=kint),
allocatable :: parent(:)
40 integer(kind=kint),
allocatable :: colcnt(:)
41 integer(kind=kint),
allocatable :: sptr(:)
42 integer(kind=kint),
allocatable :: sparent(:)
43 integer(kind=kint),
allocatable :: rptr(:)
44 integer(kind=kint),
allocatable :: rlist(:)
46 integer(kind=kint),
allocatable :: cmap_ptr(:)
47 integer(kind=kint),
allocatable :: cmap(:)
49 integer(kind=kint) :: max_front = 0
50 integer(kind=8) :: factor_nnz = 0
51 integer(kind=8) :: flops = 0
52 end type hecmwst_mf_symbolic
63 type(hecmwst_mf_graph),
intent(in) :: graph
64 integer(kind=kint),
intent(in) :: perm(:)
65 integer(kind=kint),
intent(in) :: relax_nodes
66 type(hecmwst_mf_symbolic),
intent(out) :: sym
67 integer(kind=kint),
allocatable :: post(:)
68 integer(kind=kint) :: n, k
72 allocate(sym%perm(n), sym%invp(n), sym%ndof(n), sym%parent(n), sym%colcnt(n))
74 sym%perm(1:n) = perm(1:n)
76 sym%invp(sym%perm(k)) = k
79 call mf_etree(graph, sym%perm, sym%invp, sym%parent)
80 call mf_postorder(n, sym%parent, post)
81 call mf_relabel(n, post, sym%perm, sym%invp, sym%parent)
82 call mf_colcounts(graph, sym%perm, sym%invp, sym%parent, sym%colcnt)
83 call mf_supernodes(n, sym%parent, sym%colcnt, relax_nodes, sym%nsuper, sym%sptr, sym%sparent, post, sym%nmerge)
84 call mf_relabel(n, post, sym%perm, sym%invp, sym%parent, sym%colcnt)
86 sym%ndof(k) = graph%ndof(sym%perm(k))
88 call mf_rowstruct(graph, sym)
95 type(hecmwst_mf_symbolic),
intent(inout) :: sym
99 if (
allocated(sym%perm))
deallocate(sym%perm)
100 if (
allocated(sym%invp))
deallocate(sym%invp)
101 if (
allocated(sym%ndof))
deallocate(sym%ndof)
102 if (
allocated(sym%parent))
deallocate(sym%parent)
103 if (
allocated(sym%colcnt))
deallocate(sym%colcnt)
104 if (
allocated(sym%sptr))
deallocate(sym%sptr)
105 if (
allocated(sym%sparent))
deallocate(sym%sparent)
106 if (
allocated(sym%rptr))
deallocate(sym%rptr)
107 if (
allocated(sym%rlist))
deallocate(sym%rlist)
108 if (
allocated(sym%cmap_ptr))
deallocate(sym%cmap_ptr)
109 if (
allocated(sym%cmap))
deallocate(sym%cmap)
116 subroutine mf_etree(graph, perm, invp, parent)
118 type(hecmwst_mf_graph),
intent(in) :: graph
119 integer(kind=kint),
intent(in) :: perm(:)
120 integer(kind=kint),
intent(in) :: invp(:)
121 integer(kind=kint),
intent(out) :: parent(:)
122 integer(kind=kint),
allocatable :: setp(:)
123 integer(kind=kint) :: n, k, u, r, p
132 do p = graph%xadj(perm(k)), graph%xadj(perm(k)+1)-1
133 u = invp(graph%adjncy(p))
136 do while (setp(r) /= r)
137 setp(r) = setp(setp(r))
147 end subroutine mf_etree
150 subroutine mf_postorder(n, parent, post)
152 integer(kind=kint),
intent(in) :: n
153 integer(kind=kint),
intent(in) :: parent(:)
154 integer(kind=kint),
intent(out) :: post(:)
155 integer(kind=kint),
allocatable :: cptr(:), clist(:), cur(:), stk(:)
156 integer(kind=kint) :: j, k, p, v, c, top
160 allocate(cptr(0:n), clist(n), cur(n), stk(n))
164 if (p /= 0) cptr(p) = cptr(p) + 1
167 cptr(j) = cptr(j-1) + cptr(j)
174 clist(cptr(p-1) + cur(p)) = j
178 if (parent(j) /= 0) cycle
184 if (cur(v) < cptr(v))
then
197 deallocate(cptr, clist, cur, stk)
198 end subroutine mf_postorder
201 subroutine mf_relabel(n, post, perm, invp, parent, colcnt)
203 integer(kind=kint),
intent(in) :: n
204 integer(kind=kint),
intent(in) :: post(:)
205 integer(kind=kint),
intent(inout) :: perm(:)
206 integer(kind=kint),
intent(inout) :: invp(:)
207 integer(kind=kint),
intent(inout) :: parent(:)
208 integer(kind=kint),
intent(inout),
optional :: colcnt(:)
209 integer(kind=kint),
allocatable :: newpos(:), work(:)
210 integer(kind=kint) :: k
212 allocate(newpos(n), work(n))
217 work(k) = perm(post(k))
219 perm(1:n) = work(1:n)
224 if (parent(post(k)) == 0)
then
227 work(k) = newpos(parent(post(k)))
230 parent(1:n) = work(1:n)
231 if (
present(colcnt))
then
233 work(k) = colcnt(post(k))
235 colcnt(1:n) = work(1:n)
237 deallocate(newpos, work)
238 end subroutine mf_relabel
246 subroutine mf_colcounts(graph, perm, invp, parent, colcnt)
248 type(hecmwst_mf_graph),
intent(in) :: graph
249 integer(kind=kint),
intent(in) :: perm(:)
250 integer(kind=kint),
intent(in) :: invp(:)
251 integer(kind=kint),
intent(in) :: parent(:)
252 integer(kind=kint),
intent(out) :: colcnt(:)
253 integer(kind=kint),
allocatable :: fdesc(:), maxfd(:), lastleaf(:), setp(:)
254 integer(kind=kint) :: n, j, i, p, q, w
257 allocate(fdesc(n), maxfd(n), lastleaf(n), setp(n))
265 if (p /= 0) fdesc(p) = min(fdesc(p), fdesc(j))
268 if (fdesc(j) == j)
then
280 if (p /= 0) colcnt(p) = colcnt(p) - 1
281 do i = graph%xadj(perm(j)), graph%xadj(perm(j)+1)-1
282 q = invp(graph%adjncy(i))
285 if (fdesc(j) <= maxfd(q)) cycle
287 colcnt(j) = colcnt(j) + 1
288 if (lastleaf(q) /= 0)
then
290 colcnt(w) = colcnt(w) - 1
296 if (p /= 0) setp(j) = p
299 if (parent(j) /= 0) colcnt(parent(j)) = colcnt(parent(j)) + colcnt(j)
301 deallocate(fdesc, maxfd, lastleaf, setp)
306 integer(kind=kint) function lca(v)
307 integer(kind=kint),
intent(in) :: v
308 integer(kind=kint) :: r
310 do while (setp(r) /= r)
311 setp(r) = setp(setp(r))
317 end subroutine mf_colcounts
321 subroutine mf_supernodes(n, parent, colcnt, relax_nodes, nsuper, sptr, sparent, post, nmerge)
323 integer(kind=kint),
intent(in) :: n
324 integer(kind=kint),
intent(in) :: parent(:)
325 integer(kind=kint),
intent(in) :: colcnt(:)
326 integer(kind=kint),
intent(in) :: relax_nodes
327 integer(kind=kint),
intent(out) :: nsuper
328 integer(kind=kint),
allocatable,
intent(out) :: sptr(:)
329 integer(kind=kint),
allocatable,
intent(out) :: sparent(:)
330 integer(kind=kint),
intent(out) :: post(:)
331 integer(kind=kint),
intent(out) :: nmerge
332 integer(kind=kint),
allocatable :: nchild(:), superof(:), fptr(:), fparent(:), rep(:), size(:)
333 integer(kind=kint),
allocatable :: mid(:), mcols_ptr(:), mcols(:), mparent(:), morder(:), newid(:)
334 integer(kind=kint) :: nfund, k, s, p, m, nm, l, c
336 allocate(nchild(n), superof(n))
339 if (parent(k) /= 0) nchild(parent(k)) = nchild(parent(k)) + 1
344 if (parent(k-1) == k .and. colcnt(k-1) == colcnt(k) + 1 .and. nchild(k) == 1)
then
352 allocate(fptr(nfund+1), fparent(nfund), rep(nfund),
size(nfund))
355 fptr(superof(k)+1) = k + 1
358 p = parent(fptr(s+1)-1)
362 fparent(s) = superof(p)
365 size(s) = fptr(s+1) - fptr(s)
373 if (
size(s) +
size(p) <= relax_nodes)
then
375 size(p) =
size(p) +
size(s)
384 if (rep(s) == s)
then
393 do while (rep(p) /= p)
398 allocate(mparent(nm), mcols_ptr(nm+1), mcols(n), morder(nm))
399 mcols_ptr(1:nm+1) = 0
402 mcols_ptr(m+1) = mcols_ptr(m+1) + 1
406 mcols_ptr(m+1) = mcols_ptr(m) + mcols_ptr(m+1)
410 mcols(mcols_ptr(m)) = k
411 mcols_ptr(m) = mcols_ptr(m) + 1
414 mcols_ptr(m) = mcols_ptr(m-1)
418 if (rep(s) /= s) cycle
419 if (fparent(s) == 0)
then
422 mparent(mid(s)) = mid(fparent(s))
425 call mf_postorder(nm, mparent, morder)
428 allocate(sptr(nsuper+1), sparent(nsuper), newid(nm))
436 do k = mcols_ptr(c), mcols_ptr(c+1)-1
441 if (mparent(c) == 0)
then
444 sparent(m) = newid(mparent(c))
447 deallocate(nchild, superof, fptr, fparent, rep,
size, mid, mcols_ptr, mcols, mparent, morder, newid)
448 end subroutine mf_supernodes
452 subroutine mf_rowstruct(graph, sym)
454 type(hecmwst_mf_graph),
intent(in) :: graph
455 type(hecmwst_mf_symbolic),
intent(inout) :: sym
456 integer(kind=kint),
allocatable :: mark(:), head(:), next(:), buf(:), pos(:)
457 integer(kind=kint) :: n, ns, s, c, k, fc, lc, p, i, cnt, cap, l, ncol
461 allocate(mark(n), head(ns), next(ns), buf(n), pos(n))
462 allocate(sym%rptr(ns+1), sym%cmap_ptr(ns+1))
473 cap = cap + sym%colcnt(k)
475 allocate(sym%rlist(cap))
479 lc = sym%sptr(s+1) - 1
487 do p = graph%xadj(sym%perm(k)), graph%xadj(sym%perm(k)+1)-1
488 i = sym%invp(graph%adjncy(p))
490 if (mark(i) == s) cycle
498 ncol = sym%sptr(c+1) - sym%sptr(c)
499 do l = sym%rptr(c) + ncol, sym%rptr(c+1) - 1
502 if (mark(i) == s) cycle
509 call mf_sort(buf(lc-fc+2:cnt), cnt-(lc-fc+1))
510 if (sym%rptr(s) + cnt - 1 > cap)
then
511 cap = max(2*cap, sym%rptr(s) + cnt - 1)
512 call mf_grow(sym%rlist, cap)
514 sym%rlist(sym%rptr(s):sym%rptr(s)+cnt-1) = buf(1:cnt)
515 sym%rptr(s+1) = sym%rptr(s) + cnt
520 ncol = sym%sptr(c+1) - sym%sptr(c)
521 sym%cmap_ptr(c+1) = sym%cmap_ptr(c) + (sym%rptr(c+1) - sym%rptr(c) - ncol)
523 allocate(sym%cmap(sym%cmap_ptr(ns+1)-1))
525 if (head(s) == 0) cycle
526 do l = sym%rptr(s), sym%rptr(s+1) - 1
527 pos(sym%rlist(l)) = l - sym%rptr(s) + 1
531 ncol = sym%sptr(c+1) - sym%sptr(c)
533 do l = sym%rptr(c) + ncol, sym%rptr(c+1) - 1
534 sym%cmap(k) = pos(sym%rlist(l))
540 deallocate(mark, head, next, buf, pos)
541 end subroutine mf_rowstruct
543 subroutine mf_grow(a, cap)
545 integer(kind=kint),
allocatable,
intent(inout) :: a(:)
546 integer(kind=kint),
intent(in) :: cap
547 integer(kind=kint),
allocatable :: tmp(:)
550 tmp(1:
size(a)) = a(1:
size(a))
551 call move_alloc(tmp, a)
552 end subroutine mf_grow
555 subroutine mf_sort(a, m)
557 integer(kind=kint),
intent(inout) :: a(:)
558 integer(kind=kint),
intent(in) :: m
559 integer(kind=kint) :: i, j, c, t
568 if (a(c+1) > a(c)) c = c + 1
584 if (a(c+1) > a(c)) c = c + 1
592 end subroutine mf_sort
597 subroutine mf_estimate(sym)
599 type(hecmwst_mf_symbolic),
intent(inout) :: sym
600 integer(kind=kint) :: s, l, k
601 integer(kind=8) :: nrow, ncol, a, b
608 do k = sym%sptr(s), sym%sptr(s+1) - 1
609 ncol = ncol + sym%ndof(k)
612 do l = sym%rptr(s), sym%rptr(s+1) - 1
613 nrow = nrow + sym%ndof(sym%rlist(l))
615 sym%max_front = max(sym%max_front, int(nrow, kind=
kint))
616 sym%factor_nnz = sym%factor_nnz + ncol*nrow - ncol*(ncol-1)/2
619 sym%flops = sym%flops + (a*(a+1)*(2*a+1) - b*(b+1)*(2*b+1))/6
621 end subroutine mf_estimate
627 type(hecmwst_mf_graph),
intent(in) :: graph
628 type(hecmwst_mf_symbolic),
intent(in) :: sym
629 integer(kind=kint),
intent(out) :: nerr
630 integer(kind=kint),
allocatable :: fdesc(:), dsize(:), superof(:), mark(:)
631 integer(kind=kint) :: n, ns, k, s, p, c, l, i, fc, lc, ncol, nbad
632 integer(kind=8) :: nnz_node, nnz_cnt
633 type(hecmwst_mf_symbolic) :: tmp
638 allocate(fdesc(n), dsize(n), superof(n), mark(n))
642 if (sym%perm(k) < 1 .or. sym%perm(k) > n)
then
644 else if (sym%invp(sym%perm(k)) /= k)
then
650 write(*,
'(a,i0)')
'[DIRECTmf] check: perm/invp are not inverse, violations = ', nbad
661 if (p <= k .or. p > n)
then
665 fdesc(p) = min(fdesc(p), fdesc(k))
666 dsize(p) = dsize(p) + (k - fdesc(k) + 1)
668 if (sym%nmerge == 0)
then
670 if (dsize(k) /= k - fdesc(k)) nbad = nbad + 1
675 write(*,
'(a,i0)')
'[DIRECTmf] check: parent is not a topologically ordered tree, violations = ', nbad
679 if (sym%sptr(1) /= 1 .or. sym%sptr(ns+1) /= n+1) nbad = nbad + 1
681 if (sym%sptr(s+1) <= sym%sptr(s)) nbad = nbad + 1
685 write(*,
'(a)')
'[DIRECTmf] check: sptr does not partition the columns'
686 deallocate(fdesc, dsize, superof, mark)
690 superof(sym%sptr(s):sym%sptr(s+1)-1) = s
693 lc = sym%sptr(s+1) - 1
694 do k = sym%sptr(s), lc - 1
695 if (sym%parent(k) == 0)
then
697 else if (superof(sym%parent(k)) /= s)
then
701 if (sym%parent(lc) == 0)
then
702 if (sym%sparent(s) /= 0) nbad = nbad + 1
704 if (sym%sparent(s) /= superof(sym%parent(lc))) nbad = nbad + 1
705 if (sym%sparent(s) <= s) nbad = nbad + 1
710 write(*,
'(a,i0)')
'[DIRECTmf] check: supernodes inconsistent with the elimination tree, violations = ', nbad
716 lc = sym%sptr(s+1) - 1
718 if (sym%rptr(s+1) - sym%rptr(s) < ncol)
then
722 do l = sym%rptr(s), sym%rptr(s+1) - 1
724 if (l - sym%rptr(s) < ncol)
then
725 if (i /= fc + (l - sym%rptr(s))) nbad = nbad + 1
727 if (i <= lc .or. i > n) nbad = nbad + 1
728 if (l > sym%rptr(s))
then
729 if (i <= sym%rlist(l-1)) nbad = nbad + 1
736 write(*,
'(a,i0)')
'[DIRECTmf] check: rlist not ascending or not led by the own columns, violations = ', nbad
743 do l = sym%rptr(s), sym%rptr(s+1) - 1
744 mark(sym%rlist(l)) = s
746 do k = sym%sptr(s), sym%sptr(s+1) - 1
747 do p = graph%xadj(sym%perm(k)), graph%xadj(sym%perm(k)+1)-1
748 i = sym%invp(graph%adjncy(p))
749 if (i > k .and. mark(i) /= s) nbad = nbad + 1
755 write(*,
'(a,i0)')
'[DIRECTmf] check: graph edges missing from rlist, violations = ', nbad
764 lc = sym%sptr(s+1) - 1
766 c = (sym%rptr(s+1) - sym%rptr(s)) - (k - fc)
767 nnz_node = nnz_node + c
768 nnz_cnt = nnz_cnt + sym%colcnt(k)
769 if (sym%colcnt(k) > c) nbad = nbad + 1
770 if (sym%nmerge == 0 .and. sym%colcnt(k) /= c) nbad = nbad + 1
775 write(*,
'(a,i0)')
'[DIRECTmf] check: colcnt inconsistent with rlist, violations = ', nbad
777 if (nnz_cnt > nnz_node .or. (sym%nmerge == 0 .and. nnz_cnt /= nnz_node))
then
779 write(*,
'(a,i0,a,i0)')
'[DIRECTmf] check: sum(colcnt) = ', nnz_cnt,
' vs rlist node entries = ', nnz_node
785 ncol = sym%sptr(c+1) - sym%sptr(c)
786 if (sym%cmap_ptr(c+1) - sym%cmap_ptr(c) /= sym%rptr(c+1) - sym%rptr(c) - ncol)
then
792 do l = sym%rptr(c) + ncol, sym%rptr(c+1) - 1
794 if (i < 1 .or. i > sym%rptr(p+1) - sym%rptr(p))
then
796 else if (sym%rlist(sym%rptr(p) + i - 1) /= sym%rlist(l))
then
804 write(*,
'(a,i0)')
'[DIRECTmf] check: cmap does not map onto the parent rlist, violations = ', nbad
809 allocate(tmp%ndof(n), tmp%sptr(ns+1), tmp%rptr(ns+1), tmp%rlist(sym%rptr(ns+1)-1))
810 tmp%ndof(1:n) = sym%ndof(1:n)
811 tmp%sptr(1:ns+1) = sym%sptr(1:ns+1)
812 tmp%rptr(1:ns+1) = sym%rptr(1:ns+1)
813 tmp%rlist(1:sym%rptr(ns+1)-1) = sym%rlist(1:sym%rptr(ns+1)-1)
814 call mf_estimate(tmp)
815 if (tmp%factor_nnz /= sym%factor_nnz .or. tmp%flops /= sym%flops .or. tmp%max_front /= sym%max_front)
then
817 write(*,
'(a)')
'[DIRECTmf] check: stored estimates differ from recomputation'
820 deallocate(fdesc, dsize, superof, mark)
825 type(hecmwst_mf_symbolic),
intent(in) :: sym
826 integer(kind=kint) :: k, ndof_min, ndof_max
827 integer(kind=8) :: ndof_tot
830 ndof_min = huge(1_kint)
833 ndof_tot = ndof_tot + sym%ndof(k)
834 ndof_min = min(ndof_min, sym%ndof(k))
835 ndof_max = max(ndof_max, sym%ndof(k))
837 write(*,
'(a,i0,a,i0,a,i0,a,i0,a)')
'[DIRECTmf]: nodes = ', sym%nnode,
', dofs = ', ndof_tot, &
838 ' (ndof ', ndof_min,
'..', ndof_max,
')'
839 write(*,
'(a,i0,a,i0,a,i0)')
'[DIRECTmf]: supernodes = ', sym%nsuper,
', relaxed merges = ', sym%nmerge, &
840 ', max front (dof) = ', sym%max_front
841 write(*,
'(a,i0,a,f10.3,a)')
'[DIRECTmf]: factor nnz (dof) = ', sym%factor_nnz, &
842 ' (', real(sym%factor_nnz, kind=
kreal)*8.0d0/1024.0d0**3,
' GB)'
843 write(*,
'(a,i0,a,f12.3,a)')
'[DIRECTmf]: factorization flops = ', sym%flops, &
844 ' (', real(sym%flops, kind=
kreal)/1.0d9,
' GFLOP)'
855 type(hecmwst_mf_graph),
intent(in) :: graph
856 type(hecmwst_mf_symbolic),
intent(in) :: sym
857 integer(kind=kint),
intent(out) :: perm(:)
858 integer(kind=kint),
allocatable :: own(:), deg(:), queue(:)
859 integer(kind=kint) :: s, k, i, j, p, pos, head, tail, seed, mindeg
861 allocate(own(graph%nnode), deg(graph%nnode), queue(graph%nnode))
863 do k = sym%sptr(s), sym%sptr(s+1) - 1
869 do k = sym%sptr(s), sym%sptr(s+1) - 1
872 do p = graph%xadj(i), graph%xadj(i+1) - 1
873 if (own(graph%adjncy(p)) == s) deg(i) = deg(i) + 1
879 do k = sym%sptr(s), sym%sptr(s+1) - 1
881 if (own(i) == s .and. deg(i) < mindeg)
then
891 do while (head <= tail)
896 do p = graph%xadj(i), graph%xadj(i+1) - 1
898 if (own(j) == s)
then
907 deallocate(own, deg, queue)
Compressed (node level) graph of a block sparse matrix for the multifrontal solver.
Symbolic factorization (elimination tree, column counts, supernodes, row structure) for the multifron...
subroutine, public hecmw_mf_symbolic_cluster(graph, sym, perm)
Refined permutation for the BLR compression: the own nodes of every supernode are reordered by a BFS ...
subroutine, public hecmw_mf_symbolic_finalize(sym)
subroutine, public hecmw_mf_symbolic_print(sym)
subroutine, public hecmw_mf_symbolic_build(graph, perm, relax_nodes, sym)
perm(k) is the original node placed at position k by a fill reducing ordering; any topological reorde...
subroutine, public hecmw_mf_symbolic_check(graph, sym, nerr)
Consistency checks of a built structure against its graph; every violation is reported on unit 6 and ...
integer(kind=4), parameter kint
integer(kind=4), parameter kreal