11module MetisExt
22
3+ using Base: oneto
34using CliqueTrees
5+ using CliqueTrees: EliminationAlgorithm
6+ using CliqueTrees. Utilities
47using Graphs
58using Metis: Metis
69
7- const IDX = Metis. idx_t
10+ const INT = Metis. idx_t
11+
12+ function CliqueTrees. permutation (weights:: AbstractVector , graph, alg:: METIS )
13+ return permutation (weights, BipartiteGraph (graph), alg)
14+ end
815
916function CliqueTrees. permutation (graph, alg:: METIS )
1017 return permutation (BipartiteGraph (graph), alg)
1118end
1219
20+ function CliqueTrees. permutation (weights:: AbstractVector , graph:: AbstractGraph{V} , alg:: METIS ) where {V}
21+ m = ne (graph) * (2 - is_directed (graph))
22+ n = nv (graph)
23+
24+ # construct options
25+ options = Vector {INT} (undef, Metis. METIS_NOPTIONS)
26+ options .= - 1 # null
27+ options[Metis. METIS_OPTION_CTYPE + 1 ] = alg. ctype
28+ options[Metis. METIS_OPTION_RTYPE + 1 ] = alg. rtype
29+ options[Metis. METIS_OPTION_NSEPS + 1 ] = alg. nseps
30+ options[Metis. METIS_OPTION_NUMBERING + 1 ] = 1
31+ options[Metis. METIS_OPTION_NITER + 1 ] = alg. niter
32+ options[Metis. METIS_OPTION_SEED + 1 ] = alg. seed
33+ options[Metis. METIS_OPTION_COMPRESS + 1 ] = alg. compress
34+ options[Metis. METIS_OPTION_CCORDER + 1 ] = alg. ccorder
35+ options[Metis. METIS_OPTION_PFACTOR + 1 ] = alg. pfactor
36+ options[Metis. METIS_OPTION_UFACTOR + 1 ] = alg. ufactor
37+
38+ # construct METIS graph
39+ xadj = Vector {INT} (undef, n + 1 )
40+ adjncy = Vector {INT} (undef, m)
41+ vwght = Vector {INT} (undef, n)
42+ xadj[begin ] = p = one (INT)
43+
44+ @inbounds for j in vertices (graph)
45+ vwght[j] = trunc (INT, weights[j])
46+
47+ for i in neighbors (graph, j)
48+ if i != j
49+ adjncy[p] = i
50+ p += one (INT)
51+ end
52+ end
53+
54+ xadj[j + one (V)] = p
55+ end
56+
57+ resize! (adjncy, p - one (INT))
58+
59+ # construct permutation
60+ metisorder = Vector {INT} (undef, n)
61+ metisindex = Vector {INT} (undef, n)
62+
63+ Metis. @check Metis. METIS_NodeND (
64+ Ref {INT} (n),
65+ xadj,
66+ adjncy,
67+ vwght,
68+ options,
69+ metisorder,
70+ metisindex,
71+ )
72+
73+ # restore vertex type
74+ order:: Vector{V} = metisorder
75+ index:: Vector{V} = metisindex
76+ return order, index
77+ end
78+
1379function CliqueTrees. permutation (graph:: AbstractGraph{V} , alg:: METIS ) where {V}
80+ m = ne (graph) * (2 - is_directed (graph))
81+ n = nv (graph)
82+
1483 # construct options
15- options = Vector {IDX } (undef, Metis. METIS_NOPTIONS)
84+ options = Vector {INT } (undef, Metis. METIS_NOPTIONS)
1685 options .= - 1 # null
1786 options[Metis. METIS_OPTION_CTYPE + 1 ] = alg. ctype
1887 options[Metis. METIS_OPTION_RTYPE + 1 ] = alg. rtype
@@ -26,29 +95,29 @@ function CliqueTrees.permutation(graph::AbstractGraph{V}, alg::METIS) where {V}
2695 options[Metis. METIS_OPTION_UFACTOR + 1 ] = alg. ufactor
2796
2897 # construct METIS graph
29- xadj = Vector {IDX } (undef, nv (graph) + 1 )
30- adjncy = Vector {IDX } (undef, ne (graph) * ( 2 - is_directed (graph)) )
31- xadj[begin ] = p = one (IDX )
98+ xadj = Vector {INT } (undef, n + 1 )
99+ adjncy = Vector {INT } (undef, m )
100+ xadj[begin ] = p = one (INT )
32101
33102 @inbounds for j in vertices (graph)
34103 for i in neighbors (graph, j)
35104 if i != j
36105 adjncy[p] = i
37- p += one (IDX )
106+ p += one (INT )
38107 end
39108 end
40109
41110 xadj[j + one (V)] = p
42111 end
43112
44- resize! (adjncy, p - one (IDX ))
113+ resize! (adjncy, p - one (INT ))
45114
46115 # construct permutation
47- metisorder = Vector {IDX } (undef, nv (graph) )
48- metisindex = Vector {IDX } (undef, nv (graph) )
116+ metisorder = Vector {INT } (undef, n )
117+ metisindex = Vector {INT } (undef, n )
49118
50119 Metis. @check Metis. METIS_NodeND (
51- Ref {IDX} ( nv (graph) ),
120+ Ref {INT} (n ),
52121 xadj,
53122 adjncy,
54123 C_NULL ,
@@ -63,4 +132,205 @@ function CliqueTrees.permutation(graph::AbstractGraph{V}, alg::METIS) where {V}
63132 return order, index
64133end
65134
135+ function CliqueTrees. permutation (weights:: AbstractVector , graph, alg:: IND )
136+ return permutation (weights, BipartiteGraph (graph), alg)
137+ end
138+
139+ function CliqueTrees. permutation (graph, alg:: IND )
140+ return permutation (BipartiteGraph (graph), alg)
141+ end
142+
143+ function CliqueTrees. permutation (graph:: AbstractGraph{V} , alg:: IND ) where {V}
144+ weights = ones (V, nv (graph))
145+ return permutation (weights, graph, alg)
146+ end
147+
148+ function CliqueTrees. permutation (weights:: AbstractVector , graph:: AbstractGraph{V} , alg:: IND ) where {V}
149+ n = nv (graph)
150+ m = ne (graph) * (2 - is_directed (graph))
151+ new = BipartiteGraph {INT, INT} (n, n, m)
152+ pointers (new)[begin ] = p = one (INT)
153+
154+ @inbounds for v in vertices (graph)
155+ for w in neighbors (graph, v)
156+ if v != w
157+ targets (new)[p] = INT (w)
158+ p += one (INT)
159+ end
160+ end
161+
162+ pointers (new)[v + one (V)] = p
163+ end
164+
165+ resize! (targets (new), p - one (INT))
166+ order:: Vector{V} = indissect (vertices (new), oneto (zero (INT)), zero (INT), weights, new, INT (alg. limit), alg. alg)
167+ return order, invperm (order)
168+ end
169+
170+ function indissect (label:: AbstractVector{INT} , clique:: AbstractVector{INT} , delta:: INT , weights:: AbstractVector , graph:: AbstractGraph{INT} , limit:: INT , alg:: EliminationAlgorithm )
171+ n = nv (graph)
172+
173+ if n <= limit + delta
174+ order = first (permutation (weights, graph; alg = CompositeRotations (clique, alg)))
175+ else
176+ project = separator (weights, graph)
177+ project0 = Vector {INT} (undef, n)
178+ project1 = Vector {INT} (undef, n)
179+ n0 = n1 = n2 = zero (INT)
180+ m0 = m1 = zero (INT)
181+
182+ @inbounds for v in vertices (graph)
183+ vv = project[v]
184+
185+ if iszero (vv)
186+ project0[v] = n0 += one (INT)
187+ m0 += eltypedegree (graph, v)
188+ elseif isone (vv)
189+ project1[v] = n1 += one (INT)
190+ m1 += eltypedegree (graph, v)
191+ else
192+ project0[v] = n0 += one (INT)
193+ project1[v] = n1 += one (INT)
194+ n2 += one (INT)
195+
196+ for w in outneighbors (graph, v)
197+ ww = project[w]
198+
199+ if iszero (ww)
200+ m0 += one (INT)
201+ elseif isone (ww)
202+ m1 += one (INT)
203+ end
204+ end
205+ end
206+ end
207+
208+ m0 += n2 * n2 - n2
209+ m1 += n2 * n2 - n2
210+ label0 = Vector {INT} (undef, n0)
211+ label1 = Vector {INT} (undef, n1)
212+ label2 = Vector {INT} (undef, n2)
213+ t0 = t1 = t2 = zero (INT)
214+
215+ @inbounds for v in vertices (graph)
216+ vv = project[v]
217+
218+ if iszero (vv)
219+ t0 += one (INT)
220+ label0[t0] = v
221+ elseif isone (vv)
222+ t1 += one (INT)
223+ label1[t1] = v
224+ else
225+ t0 += one (INT)
226+ t1 += one (INT)
227+ t2 += one (INT)
228+ label0[t0] = label1[t1] = label2[t2] = v
229+ end
230+ end
231+
232+ t0 = t1 = one (INT)
233+ weights0 = Vector {INT} (undef, n0)
234+ weights1 = Vector {INT} (undef, n1)
235+ graph0 = BipartiteGraph {INT, INT} (n0, n0, m0)
236+ graph1 = BipartiteGraph {INT, INT} (n1, n1, m1)
237+ pointers (graph0)[t0] = u0 = one (INT)
238+ pointers (graph1)[t1] = u1 = one (INT)
239+
240+ @inbounds for v in vertices (graph)
241+ vv = project[v]
242+
243+ if iszero (vv)
244+ weights0[t0] = weights[v]
245+
246+ for w in neighbors (graph, v)
247+ targets (graph0)[u0] = project0[w]
248+ u0 += one (INT)
249+ end
250+
251+ t0 += one (INT)
252+ pointers (graph0)[t0] = u0
253+ elseif isone (vv)
254+ weights1[t1] = weights[v]
255+
256+ for w in neighbors (graph, v)
257+ targets (graph1)[u1] = project1[w]
258+ u1 += one (INT)
259+ end
260+
261+ t1 += one (INT)
262+ pointers (graph1)[t1] = u1
263+ else
264+ weights0[t0] = weights1[t1] = weights[v]
265+
266+ for w in neighbors (graph, v)
267+ ww = project[w]
268+
269+ if iszero (ww)
270+ targets (graph0)[u0] = project0[w]
271+ u0 += one (INT)
272+ elseif isone (ww)
273+ targets (graph1)[u1] = project1[w]
274+ u1 += one (INT)
275+ end
276+ end
277+
278+ for w in label2
279+ if v != w
280+ targets (graph0)[u0] = project0[w]
281+ targets (graph1)[u1] = project1[w]
282+ u0 += one (INT)
283+ u1 += one (INT)
284+ end
285+ end
286+
287+ t0 += one (INT)
288+ t1 += one (INT)
289+ pointers (graph0)[t0] = u0
290+ pointers (graph1)[t1] = u1
291+ end
292+ end
293+
294+ order0 = indissect (label0, view (project0, label2), n2, weights0, graph0, limit + delta, alg)
295+ order1 = indissect (label1, view (project1, label2), n2, weights1, graph1, limit + delta, alg)
296+ order = first (permutation (graph; alg = CompositeRotations (clique, [order0; order1; label2])))
297+ end
298+
299+ @inbounds for i in oneto (n - delta)
300+ order[i] = label[order[i]]
301+ end
302+
303+ return resize! (order, n - delta)
304+ end
305+
306+ function separator (weights:: AbstractVector , graph:: BipartiteGraph{INT, INT, Vector{INT}, Vector{INT}} )
307+ n = nv (graph)
308+
309+ # construct options
310+ options = Vector {INT} (undef, Metis. METIS_NOPTIONS)
311+ options .= - 1 # null
312+ options[Metis. METIS_OPTION_NUMBERING + 1 ] = 1
313+
314+ # construct METIS graph
315+ xadj = pointers (graph) .- one (INT)
316+ adjncy = targets (graph) .- one (INT)
317+ vwght = trunc .(INT, weights)
318+
319+ # construct separator
320+ part = Vector {INT} (undef, n)
321+ sepsize = fill (zero (INT), 1 )
322+
323+ Metis. @check Metis. METIS_ComputeVertexSeparator (
324+ Ref {INT} (n),
325+ xadj,
326+ adjncy,
327+ vwght,
328+ options,
329+ sepsize,
330+ part,
331+ )
332+
333+ return part
334+ end
335+
66336end
0 commit comments