cudd-rb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +26 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +15 -0
- data/README.md +7 -0
- data/Rakefile +11 -0
- data/cudd-rb.gemspec +188 -0
- data/cudd-rb.noespec +30 -0
- data/lib/cudd-rb/bdd.rb +68 -0
- data/lib/cudd-rb/cube.rb +94 -0
- data/lib/cudd-rb/errors.rb +4 -0
- data/lib/cudd-rb/interfaces/bdd.rb +334 -0
- data/lib/cudd-rb/interfaces/root.rb +35 -0
- data/lib/cudd-rb/loader.rb +1 -0
- data/lib/cudd-rb/manager.rb +78 -0
- data/lib/cudd-rb/version.rb +14 -0
- data/lib/cudd-rb/wrapper.rb +58 -0
- data/lib/cudd-rb.rb +46 -0
- data/spec/cube/test_equality.rb +22 -0
- data/spec/cube/test_hash.rb +34 -0
- data/spec/cube/test_new.rb +49 -0
- data/spec/cube/test_to_a012.rb +34 -0
- data/spec/cube/test_to_bdd.rb +42 -0
- data/spec/cube/test_to_cube.rb +18 -0
- data/spec/cube/test_to_dnf.rb +55 -0
- data/spec/cube/test_to_hash.rb +34 -0
- data/spec/cube/test_to_truths.rb +34 -0
- data/spec/cudd/test_manager.rb +35 -0
- data/spec/interfaces/bdd/test_and.rb +14 -0
- data/spec/interfaces/bdd/test_bdd2cube.rb +32 -0
- data/spec/interfaces/bdd/test_bdd2dnf.rb +39 -0
- data/spec/interfaces/bdd/test_cofactor.rb +44 -0
- data/spec/interfaces/bdd/test_cube.rb +61 -0
- data/spec/interfaces/bdd/test_cube2bdd.rb +22 -0
- data/spec/interfaces/bdd/test_each_cube.rb +79 -0
- data/spec/interfaces/bdd/test_eval.rb +76 -0
- data/spec/interfaces/bdd/test_exist.rb +24 -0
- data/spec/interfaces/bdd/test_forall.rb +24 -0
- data/spec/interfaces/bdd/test_is_complement.rb +26 -0
- data/spec/interfaces/bdd/test_ite.rb +18 -0
- data/spec/interfaces/bdd/test_ith_var.rb +34 -0
- data/spec/interfaces/bdd/test_ith_vars.rb +40 -0
- data/spec/interfaces/bdd/test_new_var.rb +36 -0
- data/spec/interfaces/bdd/test_new_vars.rb +45 -0
- data/spec/interfaces/bdd/test_not.rb +18 -0
- data/spec/interfaces/bdd/test_one.rb +26 -0
- data/spec/interfaces/bdd/test_one_cube.rb +35 -0
- data/spec/interfaces/bdd/test_or.rb +14 -0
- data/spec/interfaces/bdd/test_restrict.rb +26 -0
- data/spec/interfaces/bdd/test_satisfiable.rb +33 -0
- data/spec/interfaces/bdd/test_satisfied.rb +40 -0
- data/spec/interfaces/bdd/test_size.rb +33 -0
- data/spec/interfaces/bdd/test_support.rb +66 -0
- data/spec/interfaces/bdd/test_var_index.rb +26 -0
- data/spec/interfaces/bdd/test_var_name.rb +32 -0
- data/spec/interfaces/bdd/test_var_names.rb +25 -0
- data/spec/interfaces/bdd/test_zero.rb +26 -0
- data/spec/manager/test_interface.rb +49 -0
- data/spec/shared/a_bdd.rb +15 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/test_cudd-rb.rb +8 -0
- data/spec/wrapper/test_assumptions.rb +28 -0
- data/tasks/gem.rake +73 -0
- data/tasks/spec_test.rake +71 -0
- data/tasks/unit_test.rake +76 -0
- data/tasks/yard.rake +51 -0
- metadata +218 -0
@@ -0,0 +1,334 @@
|
|
1
|
+
module Cudd
|
2
|
+
module Interface
|
3
|
+
module BDD
|
4
|
+
|
5
|
+
### BDD CREATION ###################################################################
|
6
|
+
|
7
|
+
# Coerce `pointer` to a BDD
|
8
|
+
def bdd(pointer, &error_handler)
|
9
|
+
return pointer if Cudd::BDD===pointer
|
10
|
+
if FFI::Pointer::NULL==pointer
|
11
|
+
raise Cudd::Error, "NULL pointer for BDD" unless error_handler
|
12
|
+
error_handler.call
|
13
|
+
end
|
14
|
+
m = self
|
15
|
+
pointer.tap do |p|
|
16
|
+
p.instance_eval{ @manager = m }
|
17
|
+
p.extend(Cudd::BDD)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
### REFERENCE COUNT ################################################################
|
22
|
+
|
23
|
+
# @see Cudd_Ref
|
24
|
+
def ref(f)
|
25
|
+
Wrapper.Ref(f)
|
26
|
+
f
|
27
|
+
end
|
28
|
+
|
29
|
+
# @see Cudd_Deref, Cudd_RecursiveDeref
|
30
|
+
#
|
31
|
+
# Uses `Cudd_RecursiveDeref` if `recursive` is true (defauts), decreasing
|
32
|
+
# reference counts of all children of `f`. Uses `Cudd_Deref` otherwise
|
33
|
+
# (use only if your are sure).
|
34
|
+
def deref(f, recursive = true)
|
35
|
+
recursive ? Wrapper.RecursiveDeref(native_manager, f) : Wrapper.Deref(f)
|
36
|
+
f
|
37
|
+
end
|
38
|
+
|
39
|
+
### VARS ###########################################################################
|
40
|
+
|
41
|
+
# Returns the variable names
|
42
|
+
def var_names
|
43
|
+
@var_names ||= []
|
44
|
+
(@var_names.size...size).each do |i|
|
45
|
+
@var_names[i] = :"v#{i}"
|
46
|
+
end if @var_names.size < size
|
47
|
+
@var_names
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sets the variable names
|
51
|
+
def var_names=(names)
|
52
|
+
@var_names = names
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the variable name of a given bdd
|
56
|
+
def var_name(bdd)
|
57
|
+
return :zero if bdd==zero
|
58
|
+
return :one if bdd==one
|
59
|
+
var_names[var_index(bdd)]
|
60
|
+
end
|
61
|
+
|
62
|
+
# @see Cudd_ReadSize
|
63
|
+
def size
|
64
|
+
Wrapper.ReadSize(native_manager)
|
65
|
+
end
|
66
|
+
alias :bdd_count :size
|
67
|
+
|
68
|
+
# @see Cudd_NodeReadIndex
|
69
|
+
def var_index(bdd)
|
70
|
+
return nil if bdd==zero or bdd==one
|
71
|
+
Wrapper.NodeReadIndex(bdd)
|
72
|
+
end
|
73
|
+
|
74
|
+
# @see Cudd_bddIthVar
|
75
|
+
def ith_var(i)
|
76
|
+
bdd Wrapper.bddIthVar(native_manager, i)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the ith-vars denoted by `arg` as an Array of BDDs.
|
80
|
+
#
|
81
|
+
# Example:
|
82
|
+
# x, y, z = manager.ith_vars(0, 1, 2)
|
83
|
+
# x, y, z = manager.ith_vars(0..2)
|
84
|
+
# x, y, z = manager.ith_vars([0, 1, 2])
|
85
|
+
#
|
86
|
+
def ith_vars(*args)
|
87
|
+
args = args.first if args.size==1
|
88
|
+
Array(args).map(&:to_i).map{|i| ith_var(i)}
|
89
|
+
end
|
90
|
+
|
91
|
+
# @see Cudd_bddNewVar
|
92
|
+
def new_var(name = nil)
|
93
|
+
var = bdd Wrapper.bddNewVar(native_manager)
|
94
|
+
var_names[var_index(var)] = name if name
|
95
|
+
var
|
96
|
+
end
|
97
|
+
|
98
|
+
# Creates new variables and returns them as an Array.
|
99
|
+
#
|
100
|
+
# Example:
|
101
|
+
# x, y, z = manager.new_vars(3)
|
102
|
+
# x, y, z = manager.new_vars(:x, :y, :z)
|
103
|
+
#
|
104
|
+
def new_vars(first, *args)
|
105
|
+
_, first = args.unshift(first), args unless args.empty?
|
106
|
+
case first
|
107
|
+
when Integer then (0...first).map{ new_var }
|
108
|
+
when Enumerable then first.map{|x| new_var(x) }
|
109
|
+
else
|
110
|
+
[ new_var(first) ]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
### CONSTANTS ######################################################################
|
115
|
+
|
116
|
+
# @see Cudd_ReadOne
|
117
|
+
def one
|
118
|
+
@one ||= bdd Wrapper.ReadOne(native_manager)
|
119
|
+
end
|
120
|
+
|
121
|
+
# @see Cudd_ReadLogicZero
|
122
|
+
def zero
|
123
|
+
@zero ||= bdd Wrapper.ReadLogicZero(native_manager)
|
124
|
+
end
|
125
|
+
|
126
|
+
# @see Cudd_IsComplement
|
127
|
+
def is_complement?(bdd)
|
128
|
+
(bdd.address & 1)==1
|
129
|
+
end
|
130
|
+
|
131
|
+
### BOOLEAN ALGEBRA ################################################################
|
132
|
+
|
133
|
+
# @see Cudd_bddIte
|
134
|
+
def ite(f, g, h)
|
135
|
+
bdd Wrapper.bddIte(native_manager, f, g, h)
|
136
|
+
end
|
137
|
+
|
138
|
+
# @see Cudd_bddNot
|
139
|
+
def not(f)
|
140
|
+
bdd Wrapper.bddNot(native_manager, f)
|
141
|
+
end
|
142
|
+
|
143
|
+
# @see Cudd_bddAnd
|
144
|
+
def and(f, g)
|
145
|
+
bdd Wrapper.bddAnd(native_manager, f, g)
|
146
|
+
end
|
147
|
+
|
148
|
+
# @see Cudd_bddOr
|
149
|
+
def or(f, g)
|
150
|
+
bdd Wrapper.bddOr(native_manager, f, g)
|
151
|
+
end
|
152
|
+
|
153
|
+
# @see Cudd_bddNand
|
154
|
+
def nand(f, g)
|
155
|
+
bdd Wrapper.bddNand(native_manager, f, g)
|
156
|
+
end
|
157
|
+
|
158
|
+
# @see Cudd_bddNor
|
159
|
+
def nor(f, g)
|
160
|
+
bdd Wrapper.bddNor(native_manager, f, g)
|
161
|
+
end
|
162
|
+
|
163
|
+
# @see Cudd_bddXor
|
164
|
+
def xor(f, g)
|
165
|
+
bdd Wrapper.bddXor(native_manager, f, g)
|
166
|
+
end
|
167
|
+
|
168
|
+
# @see Cudd_bddXnor
|
169
|
+
def xnor(f, g)
|
170
|
+
bdd Wrapper.bddXnor(native_manager, f, g)
|
171
|
+
end
|
172
|
+
|
173
|
+
### SUPPORT ########################################################################
|
174
|
+
|
175
|
+
# @see Cudd_Support
|
176
|
+
def support(bdd)
|
177
|
+
Wrapper.Support(native_manager, bdd)
|
178
|
+
end
|
179
|
+
|
180
|
+
### COFACTOR & GENERALIZED COFACTOR ################################################
|
181
|
+
|
182
|
+
# @see Cudd_Cofactor
|
183
|
+
def cofactor(bdd, cube)
|
184
|
+
with_bdd_cube(cube) do |c|
|
185
|
+
bdd Wrapper.Cofactor(native_manager, bdd, c)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# @see Cudd_bddRestrict
|
190
|
+
def restrict(f, g)
|
191
|
+
with_bdd_cube(g) do |c|
|
192
|
+
bdd Wrapper.bddRestrict(native_manager, f, c)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
### ABSTRACTION ####################################################################
|
197
|
+
|
198
|
+
# @see Cudd_bddExistAbstract
|
199
|
+
def exist_abstract(bdd, cube)
|
200
|
+
with_bdd_cube(cube) do |c|
|
201
|
+
bdd Wrapper.bddExistAbstract(native_manager, bdd, c)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
alias :exist :exist_abstract
|
205
|
+
|
206
|
+
# @see Cudd_bddUnivAbstract
|
207
|
+
def univ_abstract(bdd, cube)
|
208
|
+
with_bdd_cube(cube) do |c|
|
209
|
+
bdd Wrapper.bddUnivAbstract(native_manager, bdd, c)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
alias :univ :univ_abstract
|
213
|
+
alias :forall :univ_abstract
|
214
|
+
|
215
|
+
### COERCIONS from & to Cubes ######################################################
|
216
|
+
|
217
|
+
# Coerces `arg` to a cube.
|
218
|
+
#
|
219
|
+
# Example (suppose three BDD variables: x, y and z):
|
220
|
+
#
|
221
|
+
# cube([1, 0, 2]) # => [1, 0, 2]
|
222
|
+
# cube([1, 0]) # same
|
223
|
+
# cube([true, false]) # same
|
224
|
+
# cube([x, !y]) # same
|
225
|
+
# cube(x => true, y => false) # same
|
226
|
+
#
|
227
|
+
def cube(arg, as = :cube)
|
228
|
+
cube = Cube.new(self, arg)
|
229
|
+
cube.send(:"to_#{as}")
|
230
|
+
rescue NoMethodError
|
231
|
+
raise ArgumentError, "Invalid 'as' option `#{as}`"
|
232
|
+
end
|
233
|
+
|
234
|
+
# @see Cudd_CubeArrayToBdd
|
235
|
+
def cube2bdd(cube_array)
|
236
|
+
with_ffi_pointer(:int, cube_array.size) do |ptr|
|
237
|
+
ptr.write_array_of_int(cube_array)
|
238
|
+
bdd Wrapper.CubeArrayToBdd(native_manager, ptr) do
|
239
|
+
raise Cudd::Error, "Cudd_CubeArrayToBdd failed on `#{cube_array.inspect}`"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# @see Cudd_BddToCubeArray
|
245
|
+
def bdd2cube(bdd)
|
246
|
+
s = size
|
247
|
+
with_ffi_pointer(:int, s) do |ptr|
|
248
|
+
if Wrapper.BddToCubeArray(native_manager, bdd, ptr)==1
|
249
|
+
ptr.read_array_of_int(s)
|
250
|
+
else
|
251
|
+
raise NotACubeError
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# Converts a bdd to a disjunctive normal form
|
257
|
+
def bdd2dnf(bdd)
|
258
|
+
return "true" if bdd==one
|
259
|
+
return "false" if bdd==zero
|
260
|
+
buf, size = "", 0
|
261
|
+
each_cube(bdd) do |cube|
|
262
|
+
size += 1
|
263
|
+
buf << " | " unless buf.empty?
|
264
|
+
buf << "(" << cube.to_dnf << ")"
|
265
|
+
end
|
266
|
+
size == 1 ? buf[1...-1] : buf
|
267
|
+
end
|
268
|
+
|
269
|
+
### EVALUATION & SATISFIABILITY ####################################################
|
270
|
+
|
271
|
+
# @see Cudd_Eval
|
272
|
+
def eval(f, cube)
|
273
|
+
with_ffi_pointer(:int, size) do |ptr|
|
274
|
+
ptr.write_array_of_int(cube(cube, :a012))
|
275
|
+
bdd Wrapper.Eval(native_manager, f, ptr)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Returns true if `bdd` is satisfiable, false otherwise.
|
280
|
+
def satisfiable?(bdd)
|
281
|
+
!(zero == bdd)
|
282
|
+
end
|
283
|
+
|
284
|
+
# Returns true if `bdd` is satisfied by a given assignment, false otherwise.
|
285
|
+
def satisfied?(bdd, cube)
|
286
|
+
one == eval(bdd, cube)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Returns the first cube satisfying `bdd`.
|
290
|
+
def one_cube(bdd)
|
291
|
+
each_cube(bdd).first
|
292
|
+
end
|
293
|
+
|
294
|
+
# @see Cudd_ForEachCube
|
295
|
+
def each_cube(bdd)
|
296
|
+
return self.enum_for(:each_cube, bdd) unless block_given?
|
297
|
+
return unless satisfiable?(bdd)
|
298
|
+
size, gen = self.size, nil
|
299
|
+
with_ffi_pointer(:pointer) do |cube_pointer|
|
300
|
+
with_ffi_pointer(:double) do |value_pointer|
|
301
|
+
gen = Wrapper.FirstCube(native_manager, bdd, cube_pointer, value_pointer)
|
302
|
+
begin
|
303
|
+
yield cube(cube_pointer.read_pointer.read_array_of_int(size))
|
304
|
+
end until Wrapper.NextCube(gen, cube_pointer, value_pointer)==0
|
305
|
+
end
|
306
|
+
end
|
307
|
+
ensure
|
308
|
+
Wrapper.GenFree(gen) if gen
|
309
|
+
end
|
310
|
+
|
311
|
+
# Returns an array with all cubes satisfying `bdd`.
|
312
|
+
def all_cubes(bdd)
|
313
|
+
each_cube(bdd).to_a
|
314
|
+
end
|
315
|
+
|
316
|
+
private
|
317
|
+
|
318
|
+
# Yields the block with a cube encoded by a BDD. If the latter must be
|
319
|
+
# built, it is automatically referenced then dereferenced after the block
|
320
|
+
# has been yield.
|
321
|
+
def with_bdd_cube(cube)
|
322
|
+
if cube.is_a?(Cudd::BDD)
|
323
|
+
yield(cube)
|
324
|
+
else
|
325
|
+
cube = cube(cube, :bdd).ref
|
326
|
+
res = yield(cube)
|
327
|
+
cube.deref
|
328
|
+
res
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
end # module BDD
|
333
|
+
end # module Interface
|
334
|
+
end # module Cudd
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Cudd
|
2
|
+
module Interface
|
3
|
+
module Root
|
4
|
+
|
5
|
+
def root_manager?
|
6
|
+
root_manager == self
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns an extension interface for a given name.
|
10
|
+
def interface(name)
|
11
|
+
return root_manager.interface(name) unless root_manager?
|
12
|
+
return self if name == :Root
|
13
|
+
interfaces[name] ||= begin
|
14
|
+
m = Manager.new(options, native_manager, root_manager)
|
15
|
+
m.extend Interface.const_get(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def with_ffi_pointer(type = :int, size = 1)
|
22
|
+
res = nil
|
23
|
+
FFI::MemoryPointer.new(type, size) do |ptr|
|
24
|
+
res = yield(ptr)
|
25
|
+
end
|
26
|
+
res
|
27
|
+
end
|
28
|
+
|
29
|
+
def interfaces
|
30
|
+
@interfaces ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
end # module Root
|
34
|
+
end # module Interface
|
35
|
+
end # module Cudd
|
@@ -0,0 +1 @@
|
|
1
|
+
require "ffi"
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative 'interfaces/root'
|
2
|
+
module Cudd
|
3
|
+
class Manager
|
4
|
+
include Interface::Root
|
5
|
+
|
6
|
+
# Options passed at construction.
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
# Creates a manager instance.
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
def initialize(*args)
|
13
|
+
args.each do |arg|
|
14
|
+
@options = arg if arg.is_a?(Hash)
|
15
|
+
@root_manager = arg if arg.is_a?(Manager)
|
16
|
+
@native_manager = arg if arg.is_a?(FFI::Pointer)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Creates a root manager by invoking `Cudd_Init`
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
def self.root(options)
|
24
|
+
options = options.dup
|
25
|
+
bdd_vars = (options[:numVars] ||= 0)
|
26
|
+
zdd_vars = (options[:numVarsZ] ||= 0)
|
27
|
+
num_slots = (options[:numSlots] ||= 256)
|
28
|
+
cache_size = (options[:cacheSize] ||= 262144)
|
29
|
+
max_mem = (options[:maxMemory] ||= 0)
|
30
|
+
native_manager = Wrapper.Init(bdd_vars, zdd_vars, num_slots, cache_size, max_mem)
|
31
|
+
raise Cudd::Error, "Unable to create a manager" unless native_manager
|
32
|
+
Manager.new(options, native_manager).tap do |m|
|
33
|
+
ObjectSpace.define_finalizer(m, lambda{|d| d.close})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Closes this manager by invoking `Cudd_Quit`.
|
38
|
+
def close
|
39
|
+
Wrapper.Quit(@native_manager) if @native_manager
|
40
|
+
ensure
|
41
|
+
@native_manager = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Is this manager alive?
|
45
|
+
#
|
46
|
+
# A manager is alive between its creation (via `Cudd.manager`) and an invocation to
|
47
|
+
# `close`, either explicitely of implicitely (garbage collected by ruby).
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def alive?
|
51
|
+
!@native_manager.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns true if this manager has already been closed, false otherwise.
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def closed?
|
58
|
+
@native_manager.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the native manager, that is, a FFI::Pointer to the CUDD's
|
62
|
+
# `DdManager`.
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
def native_manager
|
66
|
+
@native_manager
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# @api private
|
72
|
+
def root_manager
|
73
|
+
@root_manager || self
|
74
|
+
end
|
75
|
+
|
76
|
+
end # class Manager
|
77
|
+
end # module Cudd
|
78
|
+
require_relative 'interfaces/bdd'
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Cudd
|
2
|
+
module Wrapper
|
3
|
+
extend FFI::Library
|
4
|
+
ffi_lib ['cudd', 'libcudd'] + Dir[File.expand_path('../../../ext/*', __FILE__)]
|
5
|
+
|
6
|
+
ONE_POINTER = [ :pointer ]
|
7
|
+
TWO_POINTERS = [ :pointer, :pointer ]
|
8
|
+
THREE_POINTERS = [ :pointer, :pointer, :pointer ]
|
9
|
+
FOUR_POINTERS = [ :pointer, :pointer, :pointer, :pointer ]
|
10
|
+
FIVE_POINTERS = [ :pointer, :pointer, :pointer, :pointer, :pointer ]
|
11
|
+
|
12
|
+
def self.cudd_function(name, signature, return_type = :pointer)
|
13
|
+
attach_function name, :"Cudd_#{name}", signature, return_type
|
14
|
+
end
|
15
|
+
|
16
|
+
cudd_function :Init, Array.new(4, :uint) << :ulong
|
17
|
+
cudd_function :Quit, ONE_POINTER, :void
|
18
|
+
|
19
|
+
cudd_function :Ref, ONE_POINTER, :void
|
20
|
+
cudd_function :Deref, ONE_POINTER, :void
|
21
|
+
cudd_function :RecursiveDeref, TWO_POINTERS, :void
|
22
|
+
|
23
|
+
cudd_function :ReadSize, ONE_POINTER, :int
|
24
|
+
cudd_function :NodeReadIndex, ONE_POINTER, :int
|
25
|
+
|
26
|
+
cudd_function :ReadOne, ONE_POINTER
|
27
|
+
cudd_function :ReadZero, ONE_POINTER
|
28
|
+
cudd_function :ReadLogicZero, ONE_POINTER
|
29
|
+
|
30
|
+
cudd_function :bddIthVar, [ :pointer, :int ]
|
31
|
+
cudd_function :bddNewVar, ONE_POINTER
|
32
|
+
cudd_function :bddIte, FOUR_POINTERS
|
33
|
+
cudd_function :bddNot, TWO_POINTERS
|
34
|
+
cudd_function :bddAnd, THREE_POINTERS
|
35
|
+
cudd_function :bddOr, THREE_POINTERS
|
36
|
+
cudd_function :bddNand, THREE_POINTERS
|
37
|
+
cudd_function :bddNor, THREE_POINTERS
|
38
|
+
cudd_function :bddXor, THREE_POINTERS
|
39
|
+
cudd_function :bddXnor, THREE_POINTERS
|
40
|
+
|
41
|
+
cudd_function :Cofactor, THREE_POINTERS
|
42
|
+
cudd_function :bddRestrict, THREE_POINTERS
|
43
|
+
|
44
|
+
cudd_function :bddExistAbstract, THREE_POINTERS
|
45
|
+
cudd_function :bddUnivAbstract, THREE_POINTERS
|
46
|
+
|
47
|
+
cudd_function :Support, TWO_POINTERS
|
48
|
+
|
49
|
+
cudd_function :BddToCubeArray, THREE_POINTERS, :int
|
50
|
+
cudd_function :CubeArrayToBdd, TWO_POINTERS
|
51
|
+
|
52
|
+
cudd_function :Eval, THREE_POINTERS
|
53
|
+
cudd_function :FirstCube, FOUR_POINTERS
|
54
|
+
cudd_function :NextCube, THREE_POINTERS, :int
|
55
|
+
cudd_function :GenFree, ONE_POINTER, :int
|
56
|
+
|
57
|
+
end # module Wrapper
|
58
|
+
end # module Cudd
|
data/lib/cudd-rb.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# A ruby bridge to the CU Decision Diagram package (CUDD).
|
3
|
+
#
|
4
|
+
module Cudd
|
5
|
+
|
6
|
+
# initial size of subtables
|
7
|
+
UNIQUE_SLOTS = 256
|
8
|
+
|
9
|
+
# default size of the cache
|
10
|
+
CACHE_SLOTS = 262144
|
11
|
+
|
12
|
+
# Creates a manager instance.
|
13
|
+
#
|
14
|
+
# Recognized options match `Cudd_Init` arguments.
|
15
|
+
# - :numVars (defaults to 0) initial number of BDD variables (subtables)
|
16
|
+
# - :numVarsZ (defaults to 0) initial number of ZDD variables (subtables)
|
17
|
+
# - :numSlots (defaults to UNIQUE_SLOTS) initial size of the unique tables
|
18
|
+
# - :cacheSize (defaults to CACHE_SLOTS) initial size of the cache
|
19
|
+
# - :maxMemory (defaults to 0) target maximum memory occupation
|
20
|
+
#
|
21
|
+
# If a block is given, the manager is yield and automatically closed when the block
|
22
|
+
# terminates (its result is returned). Otherwise, the manager is returned and its is
|
23
|
+
# the responsibility of the caller to close it.
|
24
|
+
#
|
25
|
+
# @see Cudd_init
|
26
|
+
def self.manager(opts = {})
|
27
|
+
manager = Manager.root(opts.dup)
|
28
|
+
if block_given?
|
29
|
+
begin
|
30
|
+
yield(manager)
|
31
|
+
ensure
|
32
|
+
manager.close if manager.alive?
|
33
|
+
end
|
34
|
+
else
|
35
|
+
manager
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end # module Cudd
|
40
|
+
require_relative "cudd-rb/version"
|
41
|
+
require_relative "cudd-rb/loader"
|
42
|
+
require_relative "cudd-rb/errors"
|
43
|
+
require_relative "cudd-rb/wrapper"
|
44
|
+
require_relative "cudd-rb/manager"
|
45
|
+
require_relative "cudd-rb/bdd"
|
46
|
+
require_relative "cudd-rb/cube"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Cudd
|
3
|
+
describe Cube, '==' do
|
4
|
+
|
5
|
+
subject{ cube1 == cube2 }
|
6
|
+
|
7
|
+
before{ x; y; z }
|
8
|
+
|
9
|
+
context 'on equal cubes' do
|
10
|
+
let(:cube1){ cube(x => true, y => false) }
|
11
|
+
let(:cube2){ cube(x => true, y => false) }
|
12
|
+
it{ should be_true }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'on non equal cubes' do
|
16
|
+
let(:cube1){ cube(x => true, y => false) }
|
17
|
+
let(:cube2){ cube(x => false) }
|
18
|
+
it{ should be_false }
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Cudd
|
3
|
+
describe Cube, 'to_truths' do
|
4
|
+
|
5
|
+
subject{ c.to_truths }
|
6
|
+
|
7
|
+
before{ x; y; z }
|
8
|
+
|
9
|
+
context 'on x' do
|
10
|
+
let(:c){ cube(x => true) }
|
11
|
+
|
12
|
+
it 'returns the expected bdd' do
|
13
|
+
subject.should eq([true, nil, nil])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'on !x' do
|
18
|
+
let(:c){ cube(x => false) }
|
19
|
+
|
20
|
+
it 'returns the expected bdd' do
|
21
|
+
subject.should eq([false, nil, nil])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'on x & y' do
|
26
|
+
let(:c){ cube(x => true, y => true) }
|
27
|
+
|
28
|
+
it 'returns the expected bdd' do
|
29
|
+
subject.should eq([true, true, nil])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Cudd
|
3
|
+
describe Cube, 'new' do
|
4
|
+
|
5
|
+
subject{ Cube.new(bdd_interface, arg) }
|
6
|
+
|
7
|
+
before{
|
8
|
+
x; y; z
|
9
|
+
subject.should be_a(Cube)
|
10
|
+
}
|
11
|
+
|
12
|
+
shared_examples_for "A cube for x=1,y=0,z=2" do
|
13
|
+
it 'has [1,0,2] has to_a012' do
|
14
|
+
subject.to_a012.should eq([1, 0, 2])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when an array of 012' do
|
19
|
+
let(:arg){ [ 1, 0, 2 ] }
|
20
|
+
it_behaves_like "A cube for x=1,y=0,z=2"
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when an incomplete array of 012' do
|
24
|
+
let(:arg){ [ 1, 0 ] }
|
25
|
+
it_behaves_like "A cube for x=1,y=0,z=2"
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when truth values' do
|
29
|
+
let(:arg){ [ true, false, nil ] }
|
30
|
+
it_behaves_like "A cube for x=1,y=0,z=2"
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when an array of BDD variables' do
|
34
|
+
let(:arg){ [!y, x] }
|
35
|
+
it_behaves_like "A cube for x=1,y=0,z=2"
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when a Hash' do
|
39
|
+
let(:arg){ {x => 1, y => false} }
|
40
|
+
it_behaves_like "A cube for x=1,y=0,z=2"
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when a BDD' do
|
44
|
+
let(:arg){ x & !y }
|
45
|
+
it_behaves_like "A cube for x=1,y=0,z=2"
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|