rbmetis 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fbae1487ebf509c40e38f3f8faf4215cf990aeb2
4
+ data.tar.gz: c72a1b49ba3d6b7546fafbd0cf8c6d212056d316
5
+ SHA512:
6
+ metadata.gz: e580d9355397280750f1643e5d112ffd8d175bd1a6f2787bfa8d0767110d8144c4b077c201425a377ad9eed35cc0277b223b4ce2c212450ccd940180bda8d2f4
7
+ data.tar.gz: 17def092502f7ec8cd3a55dce354151b4bb7f4afea8e1b641fac5bb9f07283c0b093385ef4a6b94bcb160549419c4f06f710097bfe4c9dbd9f00b7517f5a9369
data/.gitignore ADDED
@@ -0,0 +1,32 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .config
19
+ *~
20
+ */*~
21
+ */*/*~
22
+ *.bak
23
+ */*.bak
24
+ */*/*.bak
25
+ .#*
26
+ */.#*
27
+ */*/.#*
28
+ rhosts
29
+ spec/*/*.dat
30
+ spec/*/*.csv
31
+ ext/Makefile
32
+ lib/rbmetis/config.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rbmetis.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2014 Masahiro TANAKA
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # RbMetis
2
+
3
+ FFI wrapper of [METIS graph partitioning library](http://glaros.dtc.umn.edu/gkhome/metis/metis/overview)
4
+
5
+ * [GitHub](https://github.com/masa16/rbmetis)
6
+ * [RubyGems](https://rubygems.org/gems/rbmetis)
7
+ * [Class Documentation](http://rubydoc.info/gems/rbmetis/frames/)
8
+
9
+ ## Requirement
10
+
11
+ * [METIS version 5.1.0](http://glaros.dtc.umn.edu/gkhome/metis/metis/overview)
12
+ * [Ruby-FFI](https://rubygems.org/gems/ffi)
13
+
14
+ ## Installation
15
+
16
+ Install from RubyGems:
17
+
18
+ $ gem install rbmetis
19
+
20
+ Or download source tree from [releases](https://github.com/masa16/rbmetis/releases),
21
+ cd to tree top and run:
22
+
23
+ $ ruby setup.rb
24
+
25
+ ### Installation Option
26
+
27
+ * Required METIS files:
28
+ * C header: metis.h
29
+ * Library: libmetis.so or libmetis.a
30
+
31
+ * option for extconf.rb
32
+
33
+ --with-metis-dir=path
34
+ --with-metis-include=path
35
+ --with-metis-lib=path
36
+
37
+ * How to pass option to extconf.rb
38
+
39
+ $ gem install rbmetis -- --with-metis-dir=/opt/metis
40
+ $ ruby setup.rb -- --with-metis-dir=/opt/metis
41
+
42
+ ## Usage
43
+
44
+ Loading RbMeits:
45
+
46
+ require 'rbmetis'
47
+
48
+ Currently implemented APIs:
49
+
50
+ RbMetis.part_graph_recursive(xadj, adjncy, npart, opts = {})
51
+ RbMetis.part_graph_kway(xadj, adjncy, npart, opts = {})
52
+ RbMetis.default_options
53
+
54
+ See also [RbMeits API document](http://rubydoc.info/gems/rbmetis/frames)
55
+ and [METIS manual](http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf)
56
+
57
+ ## Contributing
58
+
59
+ 1. Fork it ( https://github.com/[my-github-username]/rbmetis/fork )
60
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
61
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
62
+ 4. Push to the branch (`git push origin my-new-feature`)
63
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/ext/extconf.rb ADDED
@@ -0,0 +1,56 @@
1
+ require "mkmf"
2
+
3
+ # configure options:
4
+ # --with-metis-dir=path
5
+ # --with-metis-include=path
6
+ # --with-metis-lib=path
7
+
8
+ dir_config("metis")
9
+
10
+ libdirs = $LIBPATH.dup
11
+ libdirs |= %w[/usr/lib64 /usr/lib /usr/local/lib]
12
+ incdirs = $CPPFLAGS.scan(/(?<=^-I|\s-I)\S+/)
13
+ incdirs |= %w[/usr/include /usr/local/include]
14
+
15
+ libmetis = %w[libmetis.so libmetis.a]
16
+
17
+ libdirs.each do |dir|
18
+ libmetis.each do |name|
19
+ path = File.join(dir,name)
20
+ if File.exist?(path)
21
+ $libmetis = path
22
+ break
23
+ end
24
+ end
25
+ break if $libmetis
26
+ end
27
+
28
+ incdirs.each do |dir|
29
+ path = File.join(dir,'metis.h')
30
+ if File.exist?(path)
31
+ puts "reading #{path}"
32
+ open(path,'r').each do |line|
33
+ case line
34
+ when /^\s*#define\s+IDXTYPEWIDTH\s+(\d+)/
35
+ $idxtypewidth = $1.to_i
36
+ when /^\s*#define\s+REALTYPEWIDTH\s+(\d+)/
37
+ $realtypewidth = $1.to_i
38
+ end
39
+ end
40
+ break
41
+ end
42
+ end
43
+
44
+ conf_file = File.join("..","lib","rbmetis","config.rb")
45
+ print "creating #{conf_file}\n"
46
+ open(conf_file, "w") do |f|
47
+ f.puts <<EOL
48
+ module RbMetis
49
+ IDXTYPEWIDTH=#{$idxtypewidth}
50
+ REALTYPEWIDTH=#{$realtypewidth}
51
+ LIBMETIS='#{$libmetis}'
52
+ end
53
+ EOL
54
+ end
55
+
56
+ create_makefile("rbmetis")
data/lib/rbmetis.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'ffi'
2
+ require "rbmetis/version"
3
+ require "rbmetis/config"
4
+ require "rbmetis/lib"
5
+ require "rbmetis/main"
@@ -0,0 +1,135 @@
1
+ module RbMetis
2
+
3
+ # @visibility private
4
+ module Lib
5
+
6
+ extend FFI::Library
7
+ ffi_lib LIBMETIS
8
+ attach_function :METIS_PartGraphRecursive, [:pointer]*13, :int
9
+ attach_function :METIS_PartGraphKway, [:pointer]*13, :int
10
+ attach_function :METIS_SetDefaultOptions, [:pointer], :int
11
+
12
+ case IDXTYPEWIDTH
13
+ when 32
14
+ def alloc_idx_ary(ary)
15
+ a = FFI::MemoryPointer.new(:int32, ary.size)
16
+ a.write_array_of_int32(ary)
17
+ a
18
+ end
19
+ def alloc_idx(num)
20
+ a = FFI::MemoryPointer.new(:int32)
21
+ a.write_int32(num)
22
+ a
23
+ end
24
+ def read_idx_ary(a,n)
25
+ a.read_array_of_int32(n)
26
+ end
27
+ def read_idx(a)
28
+ a.read_int32
29
+ end
30
+ when 64
31
+ def alloc_idx_ary(ary)
32
+ a = FFI::MemoryPointer.new(:int64, ary.size)
33
+ a.write_array_of_int64(ary)
34
+ a
35
+ end
36
+ def alloc_idx(num)
37
+ a = FFI::MemoryPointer.new(:int64)
38
+ a.write_int64(num)
39
+ a
40
+ end
41
+ def read_idx_ary(a,n)
42
+ a.read_array_of_int64(n)
43
+ end
44
+ def read_idx(a)
45
+ a.read_int64
46
+ end
47
+ end
48
+ module_function :alloc_idx
49
+ module_function :alloc_idx_ary
50
+ module_function :read_idx
51
+ module_function :read_idx_ary
52
+
53
+ case REALTYPEWIDTH
54
+ when 32
55
+ def alloc_real_ary(ary)
56
+ a = FFI::MemoryPointer.new(4, ary.size)
57
+ a.put_array_of_float32(0, ary)
58
+ a
59
+ end
60
+ when 64
61
+ def alloc_real_ary(ary)
62
+ a = FFI::MemoryPointer.new(8, ary.size)
63
+ a.put_array_of_float64(0, ary)
64
+ a
65
+ end
66
+ end
67
+ module_function :alloc_real_ary
68
+
69
+ def check_idx_array(args,name,size=nil,sizename=nil)
70
+ arg = args[name]
71
+ if arg
72
+ if !(Array===arg)
73
+ raise ArgumentError, "#{name} must be an array"
74
+ end
75
+ if size && arg.size != size
76
+ raise ArgumentError, "the size of #{name} must be #{sizename||size}"
77
+ end
78
+ alloc_idx_ary(arg)
79
+ else
80
+ nil
81
+ end
82
+ end
83
+ module_function :check_idx_array
84
+
85
+ def check_real_array(args,name,size=nil,sizename=nil)
86
+ arg = args[name]
87
+ if arg
88
+ if !(Array===arg)
89
+ raise ArgumentError, "#{name} must be an array"
90
+ end
91
+ if size && arg.size != size
92
+ raise ArgumentError, "the size of #{name} must be #{sizename||size}"
93
+ end
94
+ alloc_real_ary(arg)
95
+ else
96
+ nil
97
+ end
98
+ end
99
+ module_function :check_real_array
100
+
101
+ def check_idx(args,name,default_value=nil)
102
+ arg = args[name]
103
+ if arg
104
+ if !(Integer===arg)
105
+ raise ArgumentError, "#{name} must be an integer"
106
+ end
107
+ alloc_idx(arg)
108
+ else
109
+ if default_value
110
+ alloc_idx(default_value)
111
+ else
112
+ nil
113
+ end
114
+ end
115
+ end
116
+ module_function :check_idx
117
+
118
+ def postprocess(retval)
119
+ case retval
120
+ when METIS_OK
121
+ "that the function returned normally."
122
+ when METIS_ERROR_INPUT
123
+ raise MetisError, "input error"
124
+ when METIS_ERROR_MEMORY
125
+ raise MetisError, "memory allocation error"
126
+ when METIS_ERROR
127
+ raise MetisError, "other type of error"
128
+ else
129
+ raise MetisError, "unknown return code"
130
+ end
131
+ end
132
+ module_function :postprocess
133
+
134
+ end
135
+ end
@@ -0,0 +1,259 @@
1
+ module RbMetis
2
+ class MetisError < StandardError
3
+ end
4
+
5
+ # Returned normally
6
+ METIS_OK = 1
7
+ # Returned due to erroneous inputs and/or options
8
+ METIS_ERROR_INPUT = -2
9
+ # Returned due to insufficient memory
10
+ METIS_ERROR_MEMORY = -3
11
+ # Some other errors
12
+ METIS_ERROR = -4
13
+
14
+ NOPTIONS = 40
15
+
16
+ #/*! Operation type codes */
17
+ OP_PMETIS,
18
+ OP_KMETIS,
19
+ OP_OMETIS = 0..2
20
+
21
+ #/*! Options codes (i.e., options[]) */
22
+ OPTION_PTYPE,
23
+ OPTION_OBJTYPE,
24
+ OPTION_CTYPE,
25
+ OPTION_IPTYPE,
26
+ OPTION_RTYPE,
27
+ OPTION_DBGLVL,
28
+ OPTION_NITER,
29
+ OPTION_NCUTS,
30
+ OPTION_SEED,
31
+ OPTION_NO2HOP,
32
+ OPTION_MINCONN,
33
+ OPTION_CONTIG,
34
+ OPTION_COMPRESS,
35
+ OPTION_CCORDER,
36
+ OPTION_PFACTOR,
37
+ OPTION_NSEPS,
38
+ OPTION_UFACTOR,
39
+ OPTION_NUMBERING,
40
+ #/* Used for command-line parameter purposes */
41
+ OPTION_HELP,
42
+ OPTION_TPWGTS,
43
+ OPTION_NCOMMON,
44
+ OPTION_NOOUTPUT,
45
+ OPTION_BALANCE,
46
+ OPTION_GTYPE,
47
+ OPTION_UBVEC = 0..25
48
+
49
+ # /*! Partitioning Schemes */
50
+ PTYPE_RB,
51
+ PTYPE_KWAY = 0..1
52
+
53
+ # /*! Graph types for meshes */
54
+ GTYPE_DUAL,
55
+ GTYPE_NODAL = 0..1
56
+
57
+ # /*! Coarsening Schemes */
58
+ CTYPE_RM,
59
+ CTYPE_SHEM = 0..1
60
+
61
+ # /*! Initial partitioning schemes */
62
+ IPTYPE_GROW,
63
+ IPTYPE_RANDOM,
64
+ IPTYPE_EDGE,
65
+ IPTYPE_NODE,
66
+ IPTYPE_METISRB = 0..4
67
+
68
+ # /*! Refinement schemes */
69
+ RTYPE_FM,
70
+ RTYPE_GREEDY,
71
+ RTYPE_SEP2SIDED,
72
+ RTYPE_SEP1SIDED = 0..3
73
+
74
+ # /*! Debug Levels */
75
+ DBG_INFO = 1
76
+ DBG_TIME = 2
77
+ DBG_COARSEN = 4
78
+ DBG_REFINE = 8
79
+ DBG_IPART = 16
80
+ DBG_MOVEINFO = 32
81
+ DBG_SEPINFO = 64
82
+ DBG_CONNINFO = 128
83
+ DBG_CONTIGINFO = 256
84
+ DBG_MEMORY = 2048
85
+
86
+ # /* Types of objectives */
87
+ OBJTYPE_CUT,
88
+ OBJTYPE_VOL,
89
+ OBJTYPE_NODE = 0..2
90
+
91
+ # @visibility private
92
+ module Lib
93
+ def part_graph_preprocess(xadj_arg, adjncy_arg, np, args={})
94
+ nv = xadj_arg.size - 1
95
+
96
+ # The number of vertices in the graph.
97
+ nvtxs = alloc_idx(nv)
98
+ # The adjacency structure of the graph as described in Section 5.5.
99
+ xadj = alloc_idx_ary(xadj_arg)
100
+ adjncy = alloc_idx_ary(adjncy_arg)
101
+ # The number of parts to partition the graph.
102
+ nparts = alloc_idx(np)
103
+
104
+ ncon = check_idx(args, :ncon, 1)
105
+ nc = read_idx(ncon)
106
+
107
+ # The weights of the vertices as described in Section 5.5.
108
+ vwgt = check_idx_array(args, :vwgt, nv*nc, "nvtxs*ncon")
109
+
110
+ # The number of balancing constraints. It should be at least 1.
111
+ ncon = alloc_idx(nc)
112
+
113
+ # The size of the vertices for computing the total communication
114
+ # volume as described in Section 5.7.
115
+ vsize = check_idx(args, :vsize, 1)
116
+
117
+ # The weights of the edges as described in Section 5.5.
118
+ adjwgt = check_idx_array(args, :adjwgt, adjncy_arg.size, "size of adjncy")
119
+
120
+ # This is an array of size nparts*ncon that specifies the desired
121
+ # weight for each partition and constraint.
122
+ # The target partition weight for the ith partition and jth
123
+ # constraint is specified at tpwgts[i*ncon+j]
124
+ # For each constraint, the sum of the tpwgts[] entries must be 1.0.
125
+ tpwgts = check_real_array(args, :tpwgts, np*nc, "nparts*ncon")
126
+
127
+ # This is an array of size ncon that specifies the allowed load
128
+ # imbalance tolerance for each constraint.
129
+ # For the ith partition and jth constraint the allowed weight is
130
+ # the ubvec[j]*tpwgts[i*ncon+j] fraction of the jth’s constraint
131
+ # total weight. The load imbalances must be greater than 1.0.
132
+ # A NULL value can be passed indicating that the load imbalance
133
+ # tolerance for each constraint should be 1.001 (for ncon=1) or
134
+ # 1.01 (for ncon>1).
135
+ ubvec = check_real_array(args, :ubvec, nc, "ncon")
136
+
137
+ # This is the array of options as described in Section 5.4.
138
+ options = check_idx_array(args, :options, 40)
139
+
140
+ # Upon successful completion, this variable stores the edge-cut or
141
+ # the total communication volume of the partitioning solution. The
142
+ # value returned depends on the partitioning’s objective
143
+ # function.
144
+ objval = alloc_idx(0)
145
+
146
+ # This is a vector of size nvtxs that upon successful completion
147
+ # stores the partition vector of the graph. The numbering of this
148
+ # vector starts from either 0 or 1, depending on the value of
149
+ # options[METIS OPTION NUMBERING].
150
+ part = alloc_idx_ary([0]*nv)
151
+
152
+ return [nvtxs, ncon, xadj, adjncy, vwgt, vsize, adjwgt, nparts,
153
+ tpwgts, ubvec, options, objval, part]
154
+ end
155
+ module_function :part_graph_preprocess
156
+ end
157
+
158
+ # partition a graph into k parts using multilevel recursive bisection.
159
+ # @overload part_graph_recursive(xadj, adjncy, npart, opts={})
160
+ # @param [Array] xadj adjacency structure of the graph
161
+ # @param [Array] adjncy adjacency structure of the graph
162
+ # @param [Integer] npart the number of partitions
163
+ # @option opts [Array] :vwgt (nil) The weights of the vertices.
164
+ # @option opts [Array] :ncon (1) The number of balancing
165
+ # constraints. It should be at least 1.
166
+ # @option opts [Array] :vsize (nil) The size of the vertices for
167
+ # computing the total communication volume.
168
+ # @option opts [Array] :adjwgt (nil) The weights of the edges.
169
+ # @option opts [Array] :tpwgts (nil) an array of size nparts*ncon
170
+ # that specifies the desired weight for each partition and
171
+ # constraint. The target partition weight for the ith partition
172
+ # and jth constraint is specified at tpwgts[i*ncon+j] For each
173
+ # constraint, the sum of the tpwgts[] entries must be 1.0.
174
+ # @option opts [Array] :ubvec (nil) an array of size ncon that
175
+ # specifies the allowed load imbalance tolerance for each
176
+ # constraint. For the ith partition and jth constraint the allowed
177
+ # weight is the ubvec[j]*tpwgts[i*ncon+j] fraction of the jth’s
178
+ # constraint total weight. The load imbalances must be greater than
179
+ # 1.0. A NULL value can be passed indicating that the load
180
+ # imbalance tolerance for each constraint should be 1.001 (for
181
+ # ncon=1) or 1.01 (for ncon>1).
182
+ # @option opts [Array] :options (nil) the array of options.
183
+ # The following options are valid for METIS PartGraphRecursive:
184
+ # METIS_OPTION_CTYPE, METIS_OPTION_IPTYPE, METIS_OPTION_RTYPE,
185
+ # METIS_OPTION_NO2HOP, METIS_OPTION_NCUTS, METIS_OPTION_NITER,
186
+ # METIS_OPTION_SEED, METIS_OPTION_UFACTOR, METIS_OPTION_NUMBERING,
187
+ # METIS_OPTION_DBGLVL
188
+ # @return [Array] an array that stores the partition of the graph.
189
+ # @raise [RbMetis::MetisError]
190
+ def part_graph_recursive(xadj, adjncy, npart, opts={})
191
+ # args = [ nvtxs, ncon, xadj, adjncy, vwgt, vsize, adjwgt, nparts,
192
+ # tpwgts, ubvec, options, objval, part ]
193
+ args = Lib.part_graph_preprocess(xadj, adjncy, npart, opts)
194
+ retval = Lib.METIS_PartGraphRecursive(*args)
195
+ Lib.postprocess(retval)
196
+ part = args.last
197
+ nv = xadj.size - 1
198
+ #p read_idx(objval)
199
+ return Lib.read_idx_ary(part,nv)
200
+ end
201
+ module_function :part_graph_recursive
202
+
203
+
204
+ # partition a graph into k parts using multilevel k-way partitioning.
205
+ # @overload part_graph_kway(xadj, adjncy, npart, opts={})
206
+ # @param [Array] xadj adjacency structure of the graph
207
+ # @param [Array] adjncy adjacency structure of the graph
208
+ # @param [Integer] npart the number of partitions
209
+ # @option opts [Array] :vwgt (nil) The weights of the vertices.
210
+ # @option opts [Array] :ncon (1) The number of balancing
211
+ # constraints. It should be at least 1.
212
+ # @option opts [Array] :vsize (nil) The size of the vertices for
213
+ # computing the total communication volume.
214
+ # @option opts [Array] :adjwgt (nil) The weights of the edges.
215
+ # @option opts [Array] :tpwgts (nil) an array of size nparts*ncon
216
+ # that specifies the desired weight for each partition and
217
+ # constraint. The target partition weight for the ith partition
218
+ # and jth constraint is specified at tpwgts[i*ncon+j] For each
219
+ # constraint, the sum of the tpwgts[] entries must be 1.0.
220
+ # @option opts [Array] :ubvec (nil) an array of size ncon that
221
+ # specifies the allowed load imbalance tolerance for each
222
+ # constraint. For the ith partition and jth constraint the allowed
223
+ # weight is the ubvec[j]*tpwgts[i*ncon+j] fraction of the jth’s
224
+ # constraint total weight. The load imbalances must be greater than
225
+ # 1.0. A NULL value can be passed indicating that the load
226
+ # imbalance tolerance for each constraint should be 1.001 (for
227
+ # ncon=1) or 1.01 (for ncon>1).
228
+ # @option opts [Array] :options (nil) the array of options.
229
+ # The following options are valid for METIS PartGraphKway:
230
+ # METIS_OPTION_OBJTYPE, METIS_OPTION_CTYPE, METIS_OPTION_IPTYPE,
231
+ # METIS_OPTION_RTYPE, METIS_OPTION_NO2HOP, METIS_OPTION_NCUTS,
232
+ # METIS_OPTION_NITER, METIS_OPTION_UFACTOR, METIS_OPTION_MINCONN,
233
+ # METIS_OPTION_CONTIG, METIS_OPTION_SEED, METIS_OPTION_NUMBERING,
234
+ # METIS_OPTION_DBGLVL
235
+ # @return [Array] an array that stores the partition of the graph.
236
+ # @raise [RbMetis::MetisError]
237
+ def part_graph_kway(xadj, adjncy, npart, opts={})
238
+ # args = [ nvtxs, ncon, xadj, adjncy, vwgt, vsize, adjwgt, nparts,
239
+ # tpwgts, ubvec, options, objval, part ]
240
+ args = Lib.part_graph_preprocess(xadj, adjncy, npart, opts)
241
+ retval = Lib.METIS_PartGraphKway(*args)
242
+ Lib.postprocess(retval)
243
+ part = args.last
244
+ nv = xadj.size - 1
245
+ #p read_idx(objval)
246
+ return Lib.read_idx_ary(part,nv)
247
+ end
248
+ module_function :part_graph_kway
249
+
250
+ # Initializes the options array into its default values.
251
+ # @return [Array] The array of options that will be initialized.
252
+ # It’s size is METIS_NOPTIONS.
253
+ def default_options
254
+ options = Lib.alloc_idx_ary([0]*40)
255
+ Lib.METIS_SetDefaultOptions(options)
256
+ Lib.read_idx_ary(options,40)
257
+ end
258
+ module_function :default_options
259
+ end