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.
Files changed (68) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +12 -0
  3. data/Gemfile.lock +26 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +7 -0
  7. data/Rakefile +11 -0
  8. data/cudd-rb.gemspec +188 -0
  9. data/cudd-rb.noespec +30 -0
  10. data/lib/cudd-rb/bdd.rb +68 -0
  11. data/lib/cudd-rb/cube.rb +94 -0
  12. data/lib/cudd-rb/errors.rb +4 -0
  13. data/lib/cudd-rb/interfaces/bdd.rb +334 -0
  14. data/lib/cudd-rb/interfaces/root.rb +35 -0
  15. data/lib/cudd-rb/loader.rb +1 -0
  16. data/lib/cudd-rb/manager.rb +78 -0
  17. data/lib/cudd-rb/version.rb +14 -0
  18. data/lib/cudd-rb/wrapper.rb +58 -0
  19. data/lib/cudd-rb.rb +46 -0
  20. data/spec/cube/test_equality.rb +22 -0
  21. data/spec/cube/test_hash.rb +34 -0
  22. data/spec/cube/test_new.rb +49 -0
  23. data/spec/cube/test_to_a012.rb +34 -0
  24. data/spec/cube/test_to_bdd.rb +42 -0
  25. data/spec/cube/test_to_cube.rb +18 -0
  26. data/spec/cube/test_to_dnf.rb +55 -0
  27. data/spec/cube/test_to_hash.rb +34 -0
  28. data/spec/cube/test_to_truths.rb +34 -0
  29. data/spec/cudd/test_manager.rb +35 -0
  30. data/spec/interfaces/bdd/test_and.rb +14 -0
  31. data/spec/interfaces/bdd/test_bdd2cube.rb +32 -0
  32. data/spec/interfaces/bdd/test_bdd2dnf.rb +39 -0
  33. data/spec/interfaces/bdd/test_cofactor.rb +44 -0
  34. data/spec/interfaces/bdd/test_cube.rb +61 -0
  35. data/spec/interfaces/bdd/test_cube2bdd.rb +22 -0
  36. data/spec/interfaces/bdd/test_each_cube.rb +79 -0
  37. data/spec/interfaces/bdd/test_eval.rb +76 -0
  38. data/spec/interfaces/bdd/test_exist.rb +24 -0
  39. data/spec/interfaces/bdd/test_forall.rb +24 -0
  40. data/spec/interfaces/bdd/test_is_complement.rb +26 -0
  41. data/spec/interfaces/bdd/test_ite.rb +18 -0
  42. data/spec/interfaces/bdd/test_ith_var.rb +34 -0
  43. data/spec/interfaces/bdd/test_ith_vars.rb +40 -0
  44. data/spec/interfaces/bdd/test_new_var.rb +36 -0
  45. data/spec/interfaces/bdd/test_new_vars.rb +45 -0
  46. data/spec/interfaces/bdd/test_not.rb +18 -0
  47. data/spec/interfaces/bdd/test_one.rb +26 -0
  48. data/spec/interfaces/bdd/test_one_cube.rb +35 -0
  49. data/spec/interfaces/bdd/test_or.rb +14 -0
  50. data/spec/interfaces/bdd/test_restrict.rb +26 -0
  51. data/spec/interfaces/bdd/test_satisfiable.rb +33 -0
  52. data/spec/interfaces/bdd/test_satisfied.rb +40 -0
  53. data/spec/interfaces/bdd/test_size.rb +33 -0
  54. data/spec/interfaces/bdd/test_support.rb +66 -0
  55. data/spec/interfaces/bdd/test_var_index.rb +26 -0
  56. data/spec/interfaces/bdd/test_var_name.rb +32 -0
  57. data/spec/interfaces/bdd/test_var_names.rb +25 -0
  58. data/spec/interfaces/bdd/test_zero.rb +26 -0
  59. data/spec/manager/test_interface.rb +49 -0
  60. data/spec/shared/a_bdd.rb +15 -0
  61. data/spec/spec_helper.rb +45 -0
  62. data/spec/test_cudd-rb.rb +8 -0
  63. data/spec/wrapper/test_assumptions.rb +28 -0
  64. data/tasks/gem.rake +73 -0
  65. data/tasks/spec_test.rake +71 -0
  66. data/tasks/unit_test.rake +76 -0
  67. data/tasks/yard.rake +51 -0
  68. 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,14 @@
1
+ module Cudd
2
+ module Version
3
+
4
+ MAJOR = 0
5
+ MINOR = 0
6
+ TINY = 1
7
+
8
+ def self.to_s
9
+ [ MAJOR, MINOR, TINY ].join('.')
10
+ end
11
+
12
+ end
13
+ VERSION = Version.to_s
14
+ end
@@ -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