cantor 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ module Cantor
2
+
3
+ # @private
4
+ UniversalSet = Class.new(RelativeComplement) do
5
+
6
+ def initialize
7
+ end
8
+
9
+ # @return [UniversalSet]
10
+ def build
11
+ self
12
+ end
13
+
14
+ # @return true
15
+ def include?(object)
16
+ true
17
+ end
18
+
19
+ # @return false
20
+ def finite?
21
+ false
22
+ end
23
+
24
+ # @return Infinity
25
+ def size
26
+ 1.0 / 0.0
27
+ end
28
+
29
+ # @return false
30
+ def empty?
31
+ false
32
+ end
33
+
34
+ # @return [AbstractSet]
35
+ def replace(other)
36
+ Cantor.build(other)
37
+ end
38
+
39
+ # @group Set Operations
40
+ #########################################################################
41
+
42
+ # @return NullSet
43
+ def complement
44
+ # ¬U = ∅
45
+ NullSet.build
46
+ end
47
+
48
+ # @return [AbstractSet]
49
+ def intersection(other)
50
+ # U & A = A
51
+ Cantor.build(other)
52
+ end
53
+
54
+ # @return [AbstractSet]
55
+ def union(other)
56
+ # U ∪ A = U
57
+ self
58
+ end
59
+
60
+ # @return [AbstractSet]
61
+ def symmetric_difference(other)
62
+ # U ⊖ A = (U ∖ A) ∪ (A ∖ U) = (¬A) ∪ (∅) = ¬A
63
+ Cantor.complement(other)
64
+ end
65
+
66
+ # @return [AbstractSet]
67
+ def difference(other)
68
+ # U ∖ A = ¬A
69
+ Cantor.complement(other)
70
+ end
71
+
72
+ # @group Set Ordering
73
+ #########################################################################
74
+
75
+ # @return [Boolean]
76
+ def proper_subset?(other)
77
+ false
78
+ end
79
+
80
+ # @return [Boolean]
81
+ def proper_superset?(other)
82
+ not other.eql?(self)
83
+ end
84
+
85
+ # @return [Boolean]
86
+ def ==(other)
87
+ eql?(other)
88
+ end
89
+
90
+ # @group Pretty Printing
91
+ #########################################################################
92
+
93
+ # @return [String]
94
+ def inspect
95
+ "UniversalSet"
96
+ end
97
+
98
+ # @endgroup
99
+ #########################################################################
100
+ end.new
101
+
102
+ end
@@ -0,0 +1,1513 @@
1
+ # encoding: UTF-8
2
+ require "spec_helper"
3
+
4
+ describe Cantor::AbsoluteSet do
5
+
6
+ def mksubset(universe)
7
+ universe.copy(:mask => rand(2**universe.size))
8
+ end
9
+
10
+ def mksingleton(universe)
11
+ universe.copy(:mask => (2**(rand(universe.size) + 1) >> 1))
12
+ end
13
+
14
+ def self.items; %w(a b c d e f g h i j k l m n o p q r s t u v w x y z) end
15
+ def self.universe; Cantor.absolute(items) end
16
+ def self.single; universe.copy(:mask => 0b00000000000000000000000001) end
17
+ def self.subset; universe.copy(:mask => 0b10101010101010101010101010) end
18
+ def self.null; universe.copy(:mask => 0b00000000000000000000000000) end
19
+
20
+ let(:items) { %w(a b c d e f g h i j k l m n o p q r s t u v w x y z) }
21
+ let(:universe) { Cantor.absolute(items) }
22
+ let(:single) { universe.copy(:mask => 0b00000000000000000000000001) }
23
+ let(:subset) { universe.copy(:mask => 0b10101010101010101010101010) }
24
+ let(:null) { universe.copy(:mask => 0b00000000000000000000000000) }
25
+
26
+ def self.property(*args)
27
+ # TODO: Use Propr
28
+ @p ||= Class.new do
29
+ def check(*args)
30
+ self
31
+ end
32
+ end.new
33
+ end
34
+
35
+ describe "#to_a" do
36
+ property("|A| == |A.to_a|"){|xs| xs.size == xs.to_a.size }.
37
+ check(null).
38
+ check(single).
39
+ check(subset).
40
+ check(universe)
41
+
42
+ property("x ∉ A => x ∉ A.to_a") do |a, to_a|
43
+ universe.all? do |x|
44
+ a.include?(x) or not to_a.include?(x)
45
+ end
46
+ end.check { bind(mksubset(universe)) { unit([a, a.to_a]) }}
47
+
48
+ property("x ∈ A => x ∈ A.to_a") do |a, to_a|
49
+ universe.all? do |x|
50
+ not a.include?(x) or to_a.include?(x)
51
+ end
52
+ end.check { bind(mksubset(universe)) { unit([a, a.to_a]) }}
53
+ end
54
+
55
+ describe "#first" do
56
+ property("{x}.first = x"){|a,x| a.first == x }.
57
+ check{ bind(mkelement(universe)){|x| unit([universe & [x], x]) }}
58
+
59
+ property("A.first ∈ A"){|a| guard(!a.empty?); a.include?(a.first) }.
60
+ check{|a| mksubset(universe) }
61
+ end
62
+
63
+ describe "#map(&block)" do
64
+ property("A.map{|a| a } = A"){|s| s.map{|a| a }.should == a }.
65
+ check(null).
66
+ check(single).
67
+ check(subset).
68
+ check(universe).
69
+ check{ mksubset(universe) }
70
+
71
+ specify "A.map{|a| b } raises an error, given b ∉ U and A ≠ ∅" do
72
+ expect { single.map{|a| "A" }}.to \
73
+ raise_error(/universe does not contain element/)
74
+
75
+ expect { subset.map{|a| "A" }}.to \
76
+ raise_error(/universe does not contain element/)
77
+
78
+ expect { universe.map{|a| "A" }}.to \
79
+ raise_error(/universe does not contain element/)
80
+ end
81
+
82
+ property("A.map{|a| b } = {b}, given b ∈ U, A ≠ ∅") do |xs, x|
83
+ xs.map{|a| x } == [x]
84
+ end.
85
+ check(single, "a").
86
+ check(subset, subset.first).
87
+ check(universe, "z").
88
+ check{ bind(mksubset(universe)){|xs| bind(mkelement(xs)) {|x| unit [xs, x] }}}
89
+ end
90
+
91
+ describe "#select(&block)" do
92
+ property("A.select{|a| true } = A"){|xs| xs.select{|a| true } == xs }.
93
+ check(null).
94
+ check(single).
95
+ check(subset).
96
+ check(universe).
97
+ check{ mksubset(universe) }
98
+
99
+ property("A.select{|a| false } = ∅"){|xs| xs.select{|a| false } == null }.
100
+ check(null).
101
+ check(single).
102
+ check(subset).
103
+ check(universe).
104
+ check{ mksubset(universe) }
105
+
106
+ property("A.select{|a| a == b } = {b}, given b ∈ U, A ≠ ∅") do |xs, x|
107
+ guard(!xs.empty?)
108
+ xs.select{|a| a == x } == [x]
109
+ end.
110
+ check(single).
111
+ check(subset).
112
+ check(universe).
113
+ check{ bind(mksubset(universe)){|xs| bind(mkelement(xs)){|x| unit [xs, x] }}}
114
+ end
115
+
116
+ describe "#reject(&block)" do
117
+ property("A.reject{|a| false } = A") do |xs|
118
+ xs.reject{|a| false } == xs
119
+ end.
120
+ check(null).
121
+ check(single).
122
+ check(subset).
123
+ check(universe).
124
+ check{ mksubset(universe) }
125
+
126
+ property("A.reject{|a| true } = ∅") do
127
+ subset.reject{|a| true }.should == null
128
+ end.
129
+ check(null).
130
+ check(single).
131
+ check(subset).
132
+ check(universe).
133
+ check{ mksubset(universe) }
134
+
135
+ specify "A.reject{|a| a != b } = {b}, given b ∈ U, A ≠ ∅" do
136
+ end
137
+
138
+ property("A.reject{|a| a != b } = {b}, given b ∈ U, A ≠ ∅") do |xs, x|
139
+ guard(!xs.empty?)
140
+ xs.reject{|a| a != e } == [e]
141
+ end.
142
+ check(single).
143
+ check(subset).
144
+ check(universe).
145
+ check{ bind(mksubset(universe)){|xs| bind(mkelement(xs)){|x| unit [xs, x] }}}
146
+ end
147
+
148
+ describe "#include?(element)" do
149
+ specify "x ∉ ∅, for all x" do
150
+ null.should_not include("a")
151
+ null.should_not include("A")
152
+ end
153
+
154
+ specify "x ∉ A, for all x ∉ U" do
155
+ single.should_not include("A")
156
+ subset.should_not include("A")
157
+ universe.should_not include("A")
158
+ end
159
+
160
+ specify "x ∈ {x}, for all x" do
161
+ single.should include("a")
162
+ end
163
+
164
+ property("x ∈ {x}, for all x") do
165
+ mksingleton(universe)
166
+ end.check do |singleton|
167
+ singleton.should include(singleton.first)
168
+ end
169
+
170
+ property("x ∉ A, for all x ∈ ¬A") do
171
+ mksubset(universe)
172
+ end.check do |a|
173
+ (~a).each{|e| a.should_not include(e) }
174
+ end
175
+ end
176
+
177
+ describe "#finite?" do
178
+ it "is true" do
179
+ null.should be_finite
180
+ single.should be_finite
181
+ subset.should be_finite
182
+ universe.should be_finite
183
+ end
184
+ end
185
+
186
+ describe "#empty?" do
187
+ specify "∅.empty? is true" do
188
+ null.should be_empty
189
+ end
190
+
191
+ specify "{x}.empty? is false" do
192
+ single.should_not be_empty
193
+ end
194
+ end
195
+
196
+ describe "#size" do
197
+ specify "∅.size == 0" do
198
+ null.size == 0
199
+ end
200
+
201
+ specify "{x}.size == 1" do
202
+ single.size.should == 1
203
+ end
204
+ end
205
+
206
+ describe "#complement" do
207
+ specify "A ∩ ¬A = ∅" do
208
+ (null & ~null).should == null
209
+ (single & ~single).should == null
210
+ (subset & ~subset).should == null
211
+ (universe & ~universe).should == null
212
+ end
213
+
214
+ property("A ∩ ¬A = ∅") do
215
+ mksubset(universe)
216
+ end.check do |a|
217
+ (a & ~a).should == null
218
+ end
219
+
220
+ specify "A ∪ ¬A = U" do
221
+ (null | ~null).should == universe
222
+ (single | ~single).should == universe
223
+ (subset | ~subset).should == universe
224
+ (universe | ~universe).should == universe
225
+ end
226
+
227
+ property("A ∪ ¬A = U") do
228
+ mksubset(universe)
229
+ end.check do |a|
230
+ (a | ~a).should == universe
231
+ end
232
+
233
+ specify "A ⊖ ¬A = U" do
234
+ (null ^ ~null).should == universe
235
+ (single ^ ~single).should == universe
236
+ (subset ^ ~subset).should == universe
237
+ (universe ^ ~universe).should == universe
238
+ end
239
+
240
+ property("A ⊖ ¬A = U") do
241
+ mksubset(universe)
242
+ end.check do |a|
243
+ (a ^ ~a).should == universe
244
+ end
245
+
246
+ specify "A ∖ ¬A = A" do
247
+ (null - ~null).should == null
248
+ (single - ~single).should == single
249
+ (subset - ~subset).should == subset
250
+ (universe - ~universe).should == universe
251
+ end
252
+
253
+ property("A ∖ ¬A = A") do
254
+ mksubset(universe)
255
+ end.check do |a|
256
+ (a - ~a).should == a
257
+ end
258
+
259
+ specify "x ∉ ¬A, for all x ∉ U" do
260
+ (~null).should_not include("A")
261
+ (~single).should_not include("A")
262
+ (~subset).should_not include("A")
263
+ (~universe).should_not include("A")
264
+ end
265
+
266
+ property("x ∈ ¬A, for all x ∈ U and x ∉ A") do
267
+ mksubset(universe)
268
+ end.check do |a|
269
+ (~a).each{|e| a.should_not include(e) }
270
+ end
271
+
272
+ property("x ∉ ¬A, for all x ∈ U and x ∈ A") do
273
+ mksubset(universe)
274
+ end.check do |a|
275
+ a.each{|e| (~a).should_not include(e) }
276
+ end
277
+
278
+ specify "¬U = ∅" do
279
+ (~universe).should == null
280
+ end
281
+
282
+ specify "¬∅ = U" do
283
+ (~null).should == universe
284
+ end
285
+
286
+ # Identity
287
+ specify "¬(¬A) = A" do
288
+ (~(~null)).should == null
289
+ (~(~single)).should == single
290
+ (~(~subset)).should == subset
291
+ (~(~universe)).should == universe
292
+ end
293
+
294
+ property("¬(¬A) = A") do
295
+ mksubset(universe)
296
+ end.check do |a|
297
+ (~(~a)).should == a
298
+ end
299
+
300
+ # De Morgan's Laws
301
+ property("¬(A ∪ B) = ¬A ∩ ¬B") do
302
+ [mksubset(universe), mksubset(universe)]
303
+ end.check do |a, b|
304
+ (~(a | b)).should == (~a & ~b)
305
+ end
306
+
307
+ property("¬(A ∩ B) = ¬A ∪ ¬B") do
308
+ [mksubset(universe), mksubset(universe)]
309
+ end.check do |a, b|
310
+ (~(a & b)).should == (~a | ~b)
311
+ end
312
+
313
+ # Uniqueness of Complements
314
+ property("B = ¬A, given A ∪ B = U and A ∩ B = ∅") do
315
+ # Create a smaller universe, because the chances of choosing
316
+ # two random subsets from 2**26 possible, that happen to be
317
+ # disjoint is very small.
318
+ universe = Cantor.absolute(%w(a b c d e f))
319
+
320
+ a = mksubset(universe)
321
+ b = mksubset(universe)
322
+
323
+ guard(a | b == universe)
324
+ guard(a & b == null)
325
+
326
+ [a, b]
327
+ end.check(2, 500) do |a, b|
328
+ b.should == ~a
329
+ end
330
+ end
331
+
332
+ describe "#union(other)" do
333
+ property("x ∈ A ∪ B, for all x ∈ A") do
334
+ a = mksubset(universe)
335
+ b = mksubset(universe)
336
+ [a, b, (a | b)]
337
+ end.check do |a, b, union|
338
+ a.each{|x| union.should include(x) }
339
+ end
340
+
341
+ property("x ∈ A ∪ B, for all x ∈ B") do
342
+ a = mksubset(universe)
343
+ b = mksubset(universe)
344
+ [a, b, (a | b)]
345
+ end.check do |a, b, union|
346
+ b.each{|x| union.should include(x) }
347
+ end
348
+
349
+ property("x ∉ A ∪ B, for all x ∉ A and x ∉ B") do
350
+ a = mksubset(universe)
351
+ b = mksubset(universe)
352
+ [a, b, (a | b)]
353
+ end.check do |a, b, union|
354
+ universe.each do |x|
355
+ unless a.include?(x) or b.include?(x)
356
+ union.should_not include(x)
357
+ end
358
+ end
359
+ end
360
+
361
+ property("A ∪ B = A, given B ⊂ A") do
362
+ # Create a smaller universe, because the chances of choosing
363
+ # two random subsets from 2**26 possible, that happen to be
364
+ # subsets of each other is very small.
365
+ universe = Cantor.absolute(%w(a b c d e f))
366
+
367
+ a = mksubset(universe)
368
+ b = mksubset(universe)
369
+ guard(b < a)
370
+
371
+ [a, b]
372
+ end.check do |a, b|
373
+ (a | b).should == a
374
+ end
375
+
376
+ property("A ∪ B = B, given B ⊃ A") do
377
+ # Create a smaller universe, because the chances of choosing
378
+ # two random subsets from 2**26 possible, that happen to be
379
+ # subsets of each other is very small.
380
+ universe = Cantor.absolute(%w(a b c d e f))
381
+
382
+ a = mksubset(universe)
383
+ b = mksubset(universe)
384
+ guard(b > a)
385
+
386
+ [a, b]
387
+ end.check do |a, b|
388
+ (a | b).should == b
389
+ end
390
+
391
+ property("A ∪ B ⊇ A") do
392
+ [mksubset(universe), mksubset(universe)]
393
+ end.check do |a, b|
394
+ (a | b).should >= a
395
+ end
396
+
397
+ property("A ∪ B ⊇ B") do
398
+ [mksubset(universe), mksubset(universe)]
399
+ end.check do |a, b|
400
+ (a | b).should >= b
401
+ end
402
+
403
+ property("A ∪ B ⊃ A, given A ∩ B = ∅") do
404
+ # Create a smaller universe, because the chances of choosing
405
+ # two random subsets from 2**26 possible, that happen to be
406
+ # disjoint is very small.
407
+ universe = Cantor.absolute(%w(a b c d e f))
408
+
409
+ a = mksubset(universe)
410
+ b = mksubset(universe)
411
+ guard(b & a == null)
412
+
413
+ [a, b]
414
+ end.check do |a, b|
415
+ (a | b) > a
416
+ end
417
+
418
+ # Absorption
419
+ property("A ∪ (A ∩ B) = A") do
420
+ [mksubset(universe), mksubset(universe)]
421
+ end.check do |a, b|
422
+ (a | (a & b)).should == a
423
+ end
424
+
425
+ # Idempotent
426
+ specify "A ∪ A = A" do
427
+ (null + null).should == null
428
+ (single + single).should == single
429
+ (subset + subset).should == subset
430
+ (universe + universe).should == universe
431
+ end
432
+
433
+ # Domination
434
+ specify "A ∪ U = U" do
435
+ (null + universe).should == universe
436
+ (single + universe).should == universe
437
+ (subset + universe).should == universe
438
+ (universe + universe).should == universe
439
+ end
440
+
441
+ # Complement
442
+ specify "A ∪ ¬A = U" do
443
+ (null | ~null).should == universe
444
+ (single | ~single).should == universe
445
+ (subset | ~subset).should == universe
446
+ (universe | ~universe).should == universe
447
+ end
448
+
449
+ # Identity
450
+ specify "A ∪ ∅ = A" do
451
+ (null + null).should == null
452
+ (single + null).should == single
453
+ (subset + null).should == subset
454
+ (universe + null).should == universe
455
+ end
456
+
457
+ # Distributive
458
+ property("A ∪ (B ∩ C) = (A ∪ B) ∩ (A ∪ C)") do
459
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
460
+ end.check do |a, b, c|
461
+ (a | (b & c)).should == ((a | b) & (a | c))
462
+ end
463
+
464
+ # Commutative
465
+ property("A ∪ B = B ∪ A") do
466
+ [mksubset(universe), mksubset(universe)]
467
+ end.check do |a, b|
468
+ (a | b).should == (b | a)
469
+ end
470
+
471
+ # Associative
472
+ property("(A ∪ B) ∪ C = A ∪ (B ∪ C)") do
473
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
474
+ end.check do |a, b, c|
475
+ ((a | b) | c).should == (a | (b | c))
476
+ end
477
+
478
+ context "if B is a RelativeSet" do
479
+ context "and B ⊆ U" do
480
+ property("then A ∪ B = A ∪ Cantor.absolute(B, U)") do
481
+ [mksubset(universe), mksubset(universe)]
482
+ end.check do |a, b|
483
+ r = Cantor.build(b.to_a)
484
+
485
+ (a | b).should == (a | r)
486
+ (a | r).should == (a | b)
487
+ (a | r).should be_a(Cantor::AbsoluteSet)
488
+ end
489
+ end
490
+
491
+ context "and B ⊈ U" do
492
+ property("then A ∪ B raises an error") do
493
+ a = mksubset(universe)
494
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
495
+ [a, b]
496
+ end.check do |a, b|
497
+ r = Cantor.build(b.to_a)
498
+
499
+ lambda { a | r }.should \
500
+ raise_error(/universe does not contain/)
501
+ end
502
+ end
503
+ end
504
+
505
+ context "if B is a RelativeComplement" do
506
+ context "and ¬B ⊆ U" do
507
+ property("then A ∪ B = B ∪ A") do
508
+ a = mksubset(universe)
509
+ b = mksubset(universe)
510
+
511
+ [a, Cantor.complement(b.to_a)]
512
+ end.check do |a, b|
513
+ (a | b).should == b | a
514
+ (a | b).should be_a(Cantor::RelativeComplement)
515
+ end
516
+ end
517
+
518
+ context "and ¬B ⊈ U" do
519
+ property("then A ∪ B = B ∪ A") do
520
+ a = mksubset(universe)
521
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
522
+
523
+ [a, Cantor.complement(b.to_a)]
524
+ end.check do |a, b|
525
+ (a | b).should == b | a
526
+ (a | b).should be_a(Cantor::RelativeComplement)
527
+ end
528
+ end
529
+ end
530
+
531
+ context "if B is an Array" do
532
+ context "and B ⊆ U" do
533
+ property("then A ∪ B = A ∪ Cantor.absolute(B, U)") do
534
+ [mksubset(universe), mksubset(universe)]
535
+ end.check do |a, b|
536
+ r = b.to_a
537
+
538
+ (a | b).should == (a | r)
539
+ (a | r).should == (a | b)
540
+ (a | r).should be_a(Cantor::AbsoluteSet)
541
+ end
542
+ end
543
+
544
+ context "and B ⊈ U" do
545
+ property("then A ∪ B raises an error") do
546
+ a = mksubset(universe)
547
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
548
+ [a, b]
549
+ end.check do |a, b|
550
+ r = b.to_a
551
+
552
+ lambda { a | r }.should \
553
+ raise_error(/universe does not contain/)
554
+ end
555
+ end
556
+ end
557
+ end
558
+
559
+ describe "#intersection(other)" do
560
+ property("x ∈ A ∩ B, for all x ∈ A and x ∈ B") do
561
+ a = mksubset(universe)
562
+ b = mksubset(universe)
563
+ [a, b, (a & b)]
564
+ end.check do |a, b, intersection|
565
+ a.each do |x|
566
+ if b.include?(x)
567
+ intersection.should include(x)
568
+ end
569
+ end
570
+ end
571
+
572
+ property("x ∉ A ∩ B, for all x ∉ A") do
573
+ a = mksubset(universe)
574
+ b = mksubset(universe)
575
+ [a, b, (a & b)]
576
+ end.check do |a, b, intersection|
577
+ universe.each do |x|
578
+ unless a.include?(x)
579
+ intersection.should_not include(x)
580
+ end
581
+ end
582
+ end
583
+
584
+ property("x ∉ A ∩ B, for all x ∉ B") do
585
+ a = mksubset(universe)
586
+ b = mksubset(universe)
587
+ [a, b, (a & b)]
588
+ end.check do |a, b, intersection|
589
+ universe.each do |x|
590
+ unless b.include?(x)
591
+ intersection.should_not include(x)
592
+ end
593
+ end
594
+ end
595
+
596
+ specify "A ∩ U = A" do
597
+ (null & universe).should == null
598
+ (single & universe).should == single
599
+ (subset & universe).should == subset
600
+ (universe & universe).should == universe
601
+ end
602
+
603
+ property("A ∩ B = A, given B ⊇ A") do
604
+ # Create a smaller universe, because the chances of choosing
605
+ # two random subsets from 2**26 possible, that happen to be
606
+ # subsets of each other is very small.
607
+ universe = Cantor.absolute(%w(a b c d e f))
608
+
609
+ a = mksubset(universe)
610
+ b = mksubset(universe)
611
+ guard(b >= a)
612
+
613
+ [a, b]
614
+ end.check do |a, b|
615
+ (a & b).should == a
616
+ end
617
+
618
+ property("A ∩ B = B, given B ⊆ A") do
619
+ # Create a smaller universe, because the chances of choosing
620
+ # two random subsets from 2**26 possible, that happen to be
621
+ # subsets of each other is very small.
622
+ universe = Cantor.absolute(%w(a b c d e f))
623
+
624
+ a = mksubset(universe)
625
+ b = mksubset(universe)
626
+ guard(b <= a)
627
+
628
+ [a, b]
629
+ end.check do |a, b|
630
+ (a & b).should == b
631
+ end
632
+
633
+ # Absorption
634
+ property("A ∩ (A ∪ B) = A") do
635
+ [mksubset(universe), mksubset(universe)]
636
+ end.check do |a, b|
637
+ (a & (a | b)).should == a
638
+ end
639
+
640
+ # Idempotent
641
+ specify "A ∩ A = A" do
642
+ (null & null).should == null
643
+ (single & single).should == single
644
+ (subset & subset).should == subset
645
+ (universe & universe).should == universe
646
+ end
647
+
648
+ # Domination
649
+ specify "A ∩ ∅ = ∅" do
650
+ (null & null).should == null
651
+ (single & null).should == null
652
+ (subset & null).should == null
653
+ (universe & null).should == null
654
+ end
655
+
656
+ # Complement
657
+ specify "A ∩ ¬A = ∅" do
658
+ (null & ~null).should == null
659
+ (single & ~single).should == null
660
+ (subset & ~subset).should == null
661
+ (universe & ~universe).should == null
662
+ end
663
+
664
+ # Distributive
665
+ property("A ∩ (B ∪ C) = (A ∩ B) ∪ (A ∩ C)") do
666
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
667
+ end.check do |a, b, c|
668
+ (a & (b | c)).should == ((a & b) | (a & c))
669
+ end
670
+
671
+ # Commutative
672
+ property("A ∩ B = B ∩ A") do
673
+ [mksubset(universe), mksubset(universe)]
674
+ end.check do |a, b|
675
+ (a & b).should == (b & a)
676
+ end
677
+
678
+ # Associative
679
+ property("(A ∩ B) ∩ C = A ∩ (B ∩ C)") do
680
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
681
+ end.check do |a, b, c|
682
+ ((a & b) & c).should == (a & (b & c))
683
+ end
684
+
685
+ context "if B is a RelativeSet" do
686
+ context "and B ⊆ U" do
687
+ property("then A ∩ B = A ∩ Cantor.absolute(B, U)") do
688
+ [mksubset(universe), mksubset(universe)]
689
+ end.check do |a, b|
690
+ r = Cantor.build(b.to_a)
691
+
692
+ (a & b).should == (a & r)
693
+ (a & r).should == (a & b)
694
+ (a & r).should be_a(Cantor::AbsoluteSet)
695
+ end
696
+ end
697
+
698
+ context "and B ⊈ U" do
699
+ property("then A ∩ B = A ∩ Cantor.absolute(B ∩ U, U)") do
700
+ a = mksubset(universe)
701
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
702
+ [a, b]
703
+ end.check do |a, b|
704
+ r = Cantor.build(b.to_a) # B
705
+ b = universe.select{|x| b.include?(x) } # B ∩ U
706
+
707
+ (a & b).should == (a & r)
708
+ (a & r).should == (a & b)
709
+ (a & r).should be_a(Cantor::AbsoluteSet)
710
+ end
711
+ end
712
+ end
713
+
714
+ context "if B is a RelativeComplement" do
715
+ context "and ¬B ⊆ U" do
716
+ property("then A ∩ B = B ∩ A") do
717
+ a = mksubset(universe)
718
+ b = mksubset(universe)
719
+
720
+ [a, Cantor.complement(b.to_a)]
721
+ end.check do |a, b|
722
+ (a & b).should == b & a
723
+ (a & b).should be_a(Cantor::AbsoluteSet)
724
+ end
725
+ end
726
+
727
+ context "and ¬B ⊈ U" do
728
+ property("then A ∩ B = B ∩ A") do
729
+ a = mksubset(universe)
730
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
731
+
732
+ [a, Cantor.complement(b.to_a)]
733
+ end.check do |a, b|
734
+ (a & b).should == b & a
735
+ (a & b).should be_a(Cantor::AbsoluteSet)
736
+ end
737
+ end
738
+ end
739
+
740
+ context "if B is an Array" do
741
+ context "and B ⊆ U" do
742
+ property("then A ∩ B = A ∩ Cantor.absolute(B, U)") do
743
+ [mksubset(universe), mksubset(universe)]
744
+ end.check do |a, b|
745
+ r = b.to_a
746
+
747
+ (a & b).should == (a & r)
748
+ (a & r).should == (a & b)
749
+ (a & r).should be_a(Cantor::AbsoluteSet)
750
+ end
751
+ end
752
+
753
+ context "and B ⊈ U" do
754
+ property("then A ∩ B = A ∩ Cantor.absolute(B ∩ U, U)") do
755
+ a = mksubset(universe)
756
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
757
+ [a, b]
758
+ end.check do |a, b|
759
+ r = b.to_a # B
760
+ b = universe.select{|x| b.include?(x) } # B ∩ U
761
+
762
+ (a & b).should == (a & r)
763
+ (a & r).should == (a & b)
764
+ (a & r).should be_a(Cantor::AbsoluteSet)
765
+ end
766
+ end
767
+ end
768
+ end
769
+
770
+ describe "#difference(other)" do
771
+ property("x ∈ A ∖ B, for all x ∈ A and x ∉ B") do
772
+ a = mksubset(universe)
773
+ b = mksubset(universe)
774
+ [a, b, (a - b)]
775
+ end.check do |a, b, difference|
776
+ a.each do |x|
777
+ unless b.include?(x)
778
+ difference.should include(x)
779
+ end
780
+ end
781
+ end
782
+
783
+ property("x ∉ A ∖ B, for all x ∉ A") do
784
+ a = mksubset(universe)
785
+ b = mksubset(universe)
786
+ [a, b, (a - b)]
787
+ end.check do |a, b, difference|
788
+ universe.each do |x|
789
+ unless a.include?(x)
790
+ difference.should_not include(x)
791
+ end
792
+ end
793
+ end
794
+
795
+ property("x ∉ A ∖ B, for all x ∈ B") do
796
+ a = mksubset(universe)
797
+ b = mksubset(universe)
798
+ [a, b, (a - b)]
799
+ end.check do |a, b, difference|
800
+ b.each do |x|
801
+ difference.include?(x).should be_false
802
+ end
803
+ end
804
+
805
+ specify "U ∖ A = ¬A" do
806
+ (universe - null).should == ~null
807
+ (universe - single).should == ~single
808
+ (universe - subset).should == ~subset
809
+ (universe - universe).should == ~universe
810
+ end
811
+
812
+ specify "∅ ∖ A = ∅" do
813
+ (null - null).should == null
814
+ (null - single).should == null
815
+ (null - subset).should == null
816
+ (null - universe).should == null
817
+ end
818
+
819
+ specify "A ∖ A = ∅" do
820
+ (null - null).should == null
821
+ (single - single).should == null
822
+ (subset - subset).should == null
823
+ (universe - universe).should == null
824
+ end
825
+
826
+ specify "A ∖ ∅ = A" do
827
+ (null - null).should == null
828
+ (single - null).should == single
829
+ (subset - null).should == subset
830
+ (universe - null).should == universe
831
+ end
832
+
833
+ specify "A ∖ U = ∅" do
834
+ (null - universe).should == null
835
+ (single - universe).should == null
836
+ (subset - universe).should == null
837
+ (universe - universe).should == null
838
+ end
839
+
840
+ property("A ∖ B = A, given A ∩ B = ∅")
841
+
842
+ property("A ∖ B ⊂ A, given A ∩ B ≠ ∅") do
843
+ a = mksubset(universe)
844
+ b = mksubset(universe)
845
+ guard(a & b != null)
846
+
847
+ [a, b]
848
+ end.check do |a, b|
849
+ (a - b).should < a
850
+ end
851
+
852
+ property("A ∖ B ≠ B ∖ A, given A ≠ B") do
853
+ a = mksubset(universe)
854
+ b = mksubset(universe)
855
+ guard(a != b)
856
+
857
+ [a, b]
858
+ end.check do |a, b|
859
+ (a - b).should_not == (b - a)
860
+ end
861
+
862
+ property("C ∖ (A ∩ B) = (C ∖ A) ∪ (C ∖ B)") do
863
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
864
+ end.check do |a, b, c|
865
+ (c - (a & b)).should == ((c - a) | (c - b))
866
+ end
867
+
868
+ property("C ∖ (A ∪ B) = (C ∖ A) ∩ (C ∖ B)") do
869
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
870
+ end.check do |a, b, c|
871
+ (c - (a | b)).should == ((c - a) & (c - b))
872
+ end
873
+
874
+ property("C ∖ (B ∖ A) = (A ∩ C) ∪ (C ∖ B)") do
875
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
876
+ end.check do |a, b, c|
877
+ (c - (b - a)).should == ((a & c) | (c - b))
878
+ end
879
+
880
+ # property("(B ∖ A) ∩ C = (B ∩ C) ∖ A = B ∩ (C ∖ A)") do
881
+ # [mksubset(universe), mksubset(universe), mksubset(universe)]
882
+ # end.check do |a, b, c|
883
+ # end
884
+
885
+ property("(B ∖ A) ∪ C = (B ∪ C) ∖ (A ∖ C)") do
886
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
887
+ end.check do |a, b, c|
888
+ ((b - a) | c).should == ((b | c) - (a - c))
889
+ end
890
+
891
+ property("B ∖ A = ¬A ∩ B") do
892
+ [mksubset(universe), mksubset(universe)]
893
+ end.check do |a, b|
894
+ (b - a).should == (~a & b)
895
+ end
896
+
897
+ property("¬(B ∖ A) = A ∪ ¬B") do
898
+ [mksubset(universe), mksubset(universe)]
899
+ end.check do |a, b|
900
+ (~(b - a)).should == (a | ~b)
901
+ end
902
+
903
+ context "if B is a RelativeSet" do
904
+ context "and B ⊆ U" do
905
+ property("then A ∖ B = A ∖ Cantor.absolute(B, U)") do
906
+ [mksubset(universe), mksubset(universe)]
907
+ end.check do |a, b|
908
+ r = Cantor.build(b.to_a)
909
+
910
+ (a - b).should == (a - r)
911
+ (a - r).should == (a - b)
912
+ (a - r).should be_a(Cantor::AbsoluteSet)
913
+ end
914
+ end
915
+
916
+ context "and B ⊈ U" do
917
+ property("then A ∖ B = A ∖ Cantor.absolute(B ∩ U, U)") do
918
+ a = mksubset(universe)
919
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
920
+ [a, b]
921
+ end.check do |a, b|
922
+ r = Cantor.build(b.to_a) # B
923
+ b = universe.select{|x| b.include?(x) } # B ∩ U
924
+
925
+ (a - b).should == (a - r)
926
+ (a - r).should == (a - b)
927
+ (a - r).should be_a(Cantor::AbsoluteSet)
928
+ end
929
+ end
930
+ end
931
+
932
+ context "if B is a RelativeComplement" do
933
+ context "and ¬B ⊆ U" do
934
+ property("then A ∖ B = A ∩ ¬B") do
935
+ a = mksubset(universe)
936
+ b = mksubset(universe)
937
+
938
+ [a, Cantor.complement(b.to_a)]
939
+ end.check do |a, b|
940
+ (a - b).should == (a & ~b)
941
+ (a - b).should be_a(Cantor::AbsoluteSet)
942
+ end
943
+ end
944
+
945
+ context "and ¬B ⊈ U" do
946
+ property("then A ∖ B = A ∩ ¬B") do
947
+ a = mksubset(universe)
948
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
949
+
950
+ [a, Cantor.complement(b.to_a)]
951
+ end.check do |a, b|
952
+ (a - b).should == (a & ~b)
953
+ (a - b).should be_a(Cantor::AbsoluteSet)
954
+ end
955
+ end
956
+ end
957
+
958
+ context "if B is an Array" do
959
+ context "and B ⊆ U" do
960
+ property("then A ∖ B = A ∖ Cantor.absolute(B, U)") do
961
+ [mksubset(universe), mksubset(universe)]
962
+ end.check do |a, b|
963
+ r = b.to_a
964
+
965
+ (a - b).should == (a - r)
966
+ (a - r).should == (a - b)
967
+ (a - r).should be_a(Cantor::AbsoluteSet)
968
+ end
969
+ end
970
+
971
+ context "and B ⊈ U" do
972
+ property("then A ∖ B = A ∖ Cantor.absolute(B ∩ U, U)") do
973
+ a = mksubset(universe)
974
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
975
+ [a, b]
976
+ end.check do |a, b|
977
+ r = b.to_a # B
978
+ b = universe.select{|x| b.include?(x) } # B ∩ U
979
+
980
+ (a - b).should == (a - r)
981
+ (a - r).should == (a - b)
982
+ (a - r).should be_a(Cantor::AbsoluteSet)
983
+ end
984
+ end
985
+ end
986
+ end
987
+
988
+ describe "#symmetric_difference(other)" do
989
+ specify "A ⊖ A = ∅" do
990
+ (null ^ null).should == null
991
+ (single ^ single).should == null
992
+ (subset ^ subset).should == null
993
+ (universe ^ universe).should == null
994
+ end
995
+
996
+ specify "A ⊖ U = ¬A" do
997
+ (null ^ universe).should == ~null
998
+ (single ^ universe).should == ~single
999
+ (subset ^ universe).should == ~subset
1000
+ (universe ^ universe).should == ~universe
1001
+ end
1002
+
1003
+ specify "A ⊖ ∅ = A" do
1004
+ (null ^ null).should == null
1005
+ (single ^ null).should == single
1006
+ (subset ^ null).should == subset
1007
+ (universe ^ null).should == universe
1008
+ end
1009
+
1010
+ property("A ⊖ B = (A ∖ B) ∪ (B ∖ A)") do
1011
+ [mksubset(universe), mksubset(universe)]
1012
+ end.check do |a, b|
1013
+ (a ^ b).should == ((a - b) | (b - a))
1014
+ end
1015
+
1016
+ property("A ⊖ B = (A ∪ B) ∖ (A ∩ B)") do
1017
+ [mksubset(universe), mksubset(universe)]
1018
+ end.check do |a, b|
1019
+ (a ^ b).should == ((a | b) - (a & b))
1020
+ end
1021
+
1022
+ property("A ⊖ B = B ⊖ A") do
1023
+ [mksubset(universe), mksubset(universe)]
1024
+ end.check do |a, b|
1025
+ (a ^ b).should == (b ^ a)
1026
+ end
1027
+
1028
+ property("(A ⊖ B) ⊖ C = A ⊖ (B ⊖ C)") do
1029
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
1030
+ end.check do |a, b, c|
1031
+ ((a ^ b) ^ c).should == (a ^ (b ^ c))
1032
+ end
1033
+
1034
+ property("(A ⊖ B) ⊖ (B ⊖ C) = A ⊖ C") do
1035
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
1036
+ end.check do |a, b, c|
1037
+ ((a ^ b) ^ (b ^ c)).should == (a ^ c)
1038
+ end
1039
+
1040
+ property("A ∩ (B ⊖ C) = (A ∩ B) ⊖ (A ∩ C)") do
1041
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
1042
+ end.check do |a, b, c|
1043
+ (a & (b ^ c)).should == ((a & b) ^ (a & c))
1044
+ end
1045
+
1046
+ context "if B is a RelativeSet" do
1047
+ context "and B ⊆ U" do
1048
+ property("then A ⊖ B = A ⊖ Cantor.absolute(B, U)") do
1049
+ [mksubset(universe), mksubset(universe)]
1050
+ end.check do |a, b|
1051
+ r = Cantor.build(b.to_a)
1052
+
1053
+ (a ^ b).should == (a ^ r)
1054
+ (a ^ r).should == (a ^ b)
1055
+ (a ^ r).should be_a(Cantor::AbsoluteSet)
1056
+ end
1057
+ end
1058
+
1059
+ context "and B ⊈ U" do
1060
+ property("then A ⊖ B raises an error") do
1061
+ a = mksubset(universe)
1062
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1063
+ [a, b]
1064
+ end.check do |a, b|
1065
+ r = Cantor.build(b.to_a)
1066
+
1067
+ lambda { a ^ r }.should \
1068
+ raise_error(/universe does not contain/)
1069
+ end
1070
+ end
1071
+ end
1072
+
1073
+ context "if B is a RelativeComplement" do
1074
+ context "and ¬B ⊆ U" do
1075
+ property("then A ⊖ B = B ⊖ A") do
1076
+ a = mksubset(universe)
1077
+ b = mksubset(universe)
1078
+
1079
+ [a, Cantor.complement(b.to_a)]
1080
+ end.check do |a, b|
1081
+ (a ^ b).should == b ^ a
1082
+ (a ^ b).should be_a(Cantor::AbsoluteSet)
1083
+ end
1084
+ end
1085
+
1086
+ context "and ¬B ⊈ U" do
1087
+ property("then A ⊖ B = B ⊖ A") do
1088
+ a = mksubset(universe)
1089
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1090
+
1091
+ [a, Cantor.complement(b.to_a)]
1092
+ end.check do |a, b|
1093
+ (a ^ b).should == b ^ a
1094
+ (a ^ b).should be_a(Cantor::AbsoluteSet)
1095
+ end
1096
+ end
1097
+ end
1098
+
1099
+ context "if B is an Array" do
1100
+ context "and B ⊆ U" do
1101
+ property("then A ⊖ B = A ⊖ Cantor.absolute(B, U)") do
1102
+ [mksubset(universe), mksubset(universe)]
1103
+ end.check do |a, b|
1104
+ r = b.to_a
1105
+
1106
+ (a ^ b).should == (a ^ r)
1107
+ (a ^ r).should == (a ^ b)
1108
+ (a ^ r).should be_a(Cantor::AbsoluteSet)
1109
+ end
1110
+ end
1111
+
1112
+ context "and B ⊈ U" do
1113
+ property("then A ⊖ B raises an error") do
1114
+ a = mksubset(universe)
1115
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1116
+ [a, b]
1117
+ end.check do |a, b|
1118
+ r = b.to_a
1119
+
1120
+ lambda { a ^ r }.should \
1121
+ raise_error(/universe does not contain/)
1122
+ end
1123
+ end
1124
+ end
1125
+ end
1126
+
1127
+ describe "#subset?(other)" do
1128
+ # Reflexivity
1129
+ specify "A ⊆ A" do
1130
+ null.should <= null
1131
+ single.should <= single
1132
+ subset.should <= subset
1133
+ universe.should <= universe
1134
+ end
1135
+
1136
+ # Antisymmetry
1137
+ property("A ⊆ B and B ⊆ A, given A = B") do
1138
+ universe = Cantor.absolute(%w(a b c d e f))
1139
+
1140
+ a = mksubset(universe)
1141
+ b = mksubset(universe)
1142
+ guard(a == b)
1143
+
1144
+ [a, b]
1145
+ end.check(5, 200) do |a, b|
1146
+ a.should <= b
1147
+ b.should <= a
1148
+ end
1149
+
1150
+ property("A = B, given A ⊆ B and B ⊆ A") do
1151
+ universe = Cantor.absolute(%w(a b c d e f))
1152
+
1153
+ a = mksubset(universe)
1154
+ b = mksubset(universe)
1155
+ guard(a <= b)
1156
+ guard(b <= a)
1157
+
1158
+ [a, b]
1159
+ end.check(5, 200) do |a, b|
1160
+ a.should == b
1161
+ end
1162
+
1163
+ # Transitivity
1164
+ property("A ⊆ C, given A ⊆ B and B ⊆ C") do
1165
+ universe = Cantor.absolute(%w(a b c d e f))
1166
+
1167
+ a = mksubset(universe)
1168
+ b = mksubset(universe)
1169
+ c = mksubset(universe)
1170
+ guard(a <= b)
1171
+ guard(b <= c)
1172
+
1173
+ [a, b, c]
1174
+ end.check(5, 200) do |a, b, c|
1175
+ a.should <= c
1176
+ end
1177
+
1178
+ # Existence of a Least Element
1179
+ specify "∅ ⊆ A" do
1180
+ null.should <= null
1181
+ null.should <= single
1182
+ null.should <= subset
1183
+ null.should <= universe
1184
+ end
1185
+
1186
+ # Existence of a Greatest Element
1187
+ specify "A ⊆ U" do
1188
+ null.should <= universe
1189
+ single.should <= universe
1190
+ subset.should <= universe
1191
+ universe.should <= universe
1192
+ end
1193
+
1194
+ # Existence of Joins
1195
+ property("A ⊆ A ∪ B") do
1196
+ [mksubset(universe), mksubset(universe)]
1197
+ end.check do |a, b|
1198
+ a.should <= (a | b)
1199
+ end
1200
+
1201
+ # Existence of meets
1202
+ property("A ∪ B ⊇ C, given C ⊆ A and C ⊆ B") do
1203
+ universe = Cantor.absolute(%w(a b c d e f))
1204
+
1205
+ a = mksubset(universe)
1206
+ b = mksubset(universe)
1207
+ c = mksubset(universe)
1208
+ guard(c <= a)
1209
+ guard(c <= b)
1210
+
1211
+ [a, b, c]
1212
+ end.check(5, 200) do |a, b, c|
1213
+ (a | b).should >= c
1214
+ end
1215
+
1216
+ # Equivalent Statements
1217
+ property("A ⊆ B => ...") do
1218
+ [mksubset(universe), mksubset(universe)]
1219
+ end.check do |a, b|
1220
+ if a <= b
1221
+ (a & b).should == a
1222
+ (a | b).should == b
1223
+ (a - b).should == null
1224
+ (~b).should <= (~a)
1225
+ end
1226
+ end
1227
+
1228
+ # Equivalent Statements
1229
+ property("A ∩ B = A => ...") do
1230
+ [mksubset(universe), mksubset(universe)]
1231
+ end.check do |a, b|
1232
+ if (a & b) == a
1233
+ a.should <= b
1234
+ (a | b).should == b
1235
+ (a - b).should == null
1236
+ (~b).should <= (~a)
1237
+ end
1238
+ end
1239
+
1240
+ # Equivalent Statements
1241
+ property("A ∪ B = B => ...") do
1242
+ [mksubset(universe), mksubset(universe)]
1243
+ end.check do |a, b|
1244
+ if (a | b) == b
1245
+ a.should <= b
1246
+ (a & b).should == a
1247
+ (a - b).should == null
1248
+ (~b).should <= (~a)
1249
+ end
1250
+ end
1251
+
1252
+ # Equivalent Statements
1253
+ property("A ∖ B = ∅ => ...") do
1254
+ [mksubset(universe), mksubset(universe)]
1255
+ end.check do |a, b|
1256
+ if (a - b) == null
1257
+ a.should <= b
1258
+ (a & b).should == a
1259
+ (a | b).should == b
1260
+ (~b).should <= (~a)
1261
+ end
1262
+ end
1263
+
1264
+ # Equivalent Statements
1265
+ property("¬B ⊆ ¬A => ...") do
1266
+ [mksubset(universe), mksubset(universe)]
1267
+ end.check do |a, b|
1268
+ if (~b) <= (~a)
1269
+ a.should <= b
1270
+ (a & b).should == a
1271
+ (a | b).should == b
1272
+ (a - b).should == null
1273
+ end
1274
+ end
1275
+
1276
+ context "if B is a RelativeSet" do
1277
+ context "and B ⊆ U" do
1278
+ property("then A ⊆ B = A ⊆ Cantor.absolute(B, U)") do
1279
+ [mksubset(universe), mksubset(universe)]
1280
+ end.check do |a, b|
1281
+ r = Cantor.build(b.to_a)
1282
+ (a <= b).should == (a <= r)
1283
+ end
1284
+ end
1285
+
1286
+ context "and B ⊈ U" do
1287
+ property("then A ⊈ B = A ⊆ Cantor.absolute(B ∩ U, U)") do
1288
+ a = mksubset(universe)
1289
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1290
+ [a, b]
1291
+ end.check do |a, b|
1292
+ r = Cantor.build(b.to_a) # B
1293
+ b = universe.select{|x| b.include?(x) } # B ∩ U
1294
+ (a <= b).should == (a <= r)
1295
+ end
1296
+ end
1297
+ end
1298
+
1299
+ context "if B is a RelativeComplement(C)" do
1300
+ context "and C ⊆ U" do
1301
+ property("then A ⊆ ¬C ≡ A ∩ C = ∅") do
1302
+ [mksubset(universe), mksubset(universe)]
1303
+ end.check do |a, c|
1304
+ b = Cantor.complement(c.to_a)
1305
+ (a <= b).should == ((a & c) == null)
1306
+ end
1307
+ end
1308
+
1309
+ context "and C ⊈ U" do
1310
+ property("then A ⊆ ¬C ≡ A ∩ C = ∅") do
1311
+ a = mksubset(universe)
1312
+ c = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1313
+ [a, c]
1314
+ end.check do |a, c|
1315
+ b = Cantor.complement(c.to_a)
1316
+ (a <= b).should == ((a & c) == null)
1317
+ end
1318
+ end
1319
+ end
1320
+
1321
+ context "when B is an Array" do
1322
+ context "and B ⊆ U" do
1323
+ property("then A ⊆ B = A ⊆ Cantor.absolute(B, U)") do
1324
+ [mksubset(universe), mksubset(universe)]
1325
+ end.check do |a, b|
1326
+ r = b.to_a
1327
+ (a <= b).should == (a <= r)
1328
+ end
1329
+ end
1330
+
1331
+ context "and B ⊈ U" do
1332
+ property("then A ⊆ B = A ⊆ Cantor.absolute(B ∩ U, U)") do
1333
+ a = mksubset(universe)
1334
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1335
+ [a, b]
1336
+ end.check do |a, b|
1337
+ r = b.to_a # B
1338
+ b = universe.select{|x| b.include?(x) } # B ∩ U
1339
+
1340
+ (a <= b).should == (a <= r)
1341
+ end
1342
+ end
1343
+ end
1344
+ end
1345
+
1346
+ describe "#==(other)" do
1347
+ # Reflexive
1348
+ specify "A = A" do
1349
+ null.should == null
1350
+ single.should == single
1351
+ subset.should == subset
1352
+ universe.should == universe
1353
+ end
1354
+
1355
+ # Symmetric
1356
+ property("if A = B then B = A") do
1357
+ universe = Cantor.absolute(%w(a b c d e f))
1358
+ [mksubset(universe), mksubset(universe)]
1359
+ end.check do |a, b|
1360
+ if a == b
1361
+ b.should == a
1362
+ end
1363
+ end
1364
+
1365
+ # Transitive
1366
+ property("if A = B and B = C then A = C") do
1367
+ universe = Cantor.absolute(%w(a b c d e f))
1368
+ [mksubset(universe), mksubset(universe), mksubset(universe)]
1369
+ end.check do |a, b, c|
1370
+ if a == b and b == c
1371
+ a.should == c
1372
+ end
1373
+ end
1374
+
1375
+ context "if B is a RelativeSet" do
1376
+ context "and B ⊆ U" do
1377
+ property("then A = B ≡ A = Cantor.absolute(B, U)") do
1378
+ [mksubset(universe), mksubset(universe)]
1379
+ end.check do |a, b|
1380
+ r = Cantor.build(b.to_a)
1381
+ (a == b).should == (a == r)
1382
+ end
1383
+ end
1384
+
1385
+ context "and B ⊈ U" do
1386
+ property("then A = B ≡ A = Cantor.absolute(B ∩ U, U)") do
1387
+ a = mksubset(universe)
1388
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1389
+ [a, b]
1390
+ end.check do |a, b|
1391
+ r = Cantor.build(b.to_a) # B
1392
+ b = universe.select{|x| b.include?(x) } # B ∩ U
1393
+ (a == b).should == (a == r)
1394
+ end
1395
+ end
1396
+ end
1397
+
1398
+ context "if B is a RelativeComplement" do
1399
+ context "and ¬B ⊆ U" do
1400
+ property("then A = B ≡ B = A") do
1401
+ a = mksubset(universe)
1402
+ b = mksubset(universe)
1403
+
1404
+ [a, Cantor.complement(b.to_a)]
1405
+ end.check do |a, b|
1406
+ (a == b).should == (b == a)
1407
+ end
1408
+ end
1409
+
1410
+ context "and ¬B ⊈ U" do
1411
+ property("then A = B ≡ B = A") do
1412
+ a = mksubset(universe)
1413
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1414
+
1415
+ [a, Cantor.complement(b.to_a)]
1416
+ end.check do |a, b|
1417
+ (a == b).should == (b == a)
1418
+ end
1419
+ end
1420
+ end
1421
+
1422
+ context "if B is an Array" do
1423
+ context "and B ⊆ U" do
1424
+ property("then A = B ≡ A = Cantor.absolute(B, U)") do
1425
+ [mksubset(universe), mksubset(universe)]
1426
+ end.check do |a, b|
1427
+ r = b.to_a
1428
+ (a == b).should == (a == r)
1429
+ end
1430
+ end
1431
+
1432
+ context "and B ⊈ U" do
1433
+ property("then A = B ≡ A = Cantor.absolute(B ∩ U, U)") do
1434
+ a = mksubset(universe)
1435
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1436
+ [a, b]
1437
+ end.check do |a, b|
1438
+ r = b.to_a # B
1439
+ b = universe.select{|x| b.include?(x) } # B ∩ U
1440
+
1441
+ (a == b).should == (a == r)
1442
+ end
1443
+ end
1444
+ end
1445
+ end
1446
+
1447
+ describe "#replace(other)" do
1448
+ context "if B is an AbsoluteSet" do
1449
+ context "and B.universe = U" do
1450
+ property("then A.replace(B) = B") do
1451
+ [mksubset(universe), mksubset(universe)]
1452
+ end.check do |a, b|
1453
+ a.replace(b).should == b
1454
+ end
1455
+ end
1456
+
1457
+ context "and B.universe ≠ U" do
1458
+ property("then A.replace(B) = B") do
1459
+ a = mksubset(universe)
1460
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1461
+ [a, b]
1462
+ end.check do |a, b|
1463
+ a.replace(b).should == b
1464
+ end
1465
+ end
1466
+ end
1467
+
1468
+ context "if B is a RelativeSet" do
1469
+ property("then A.replace(B) = B") do
1470
+ a = mksubset(universe)
1471
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1472
+ [a, Cantor.build(b.to_a)]
1473
+ end.check do |a, b|
1474
+ a.replace(b).should == b
1475
+ end
1476
+ end
1477
+
1478
+ context "if B is a RelativeComplement" do
1479
+ property("then A.replace(B) = B") do
1480
+ a = mksubset(universe)
1481
+ b = mksubset(Cantor.absolute(universe.to_a + universe.to_a.map(&:upcase)))
1482
+ [a, Cantor.complement(b.to_a)]
1483
+ end.check do |a, b|
1484
+ a.replace(b).should == b
1485
+ end
1486
+ end
1487
+
1488
+ context "if B is an Array" do
1489
+ context "and B ⊆ U" do
1490
+ property("then A.replace(B) ≡ Cantor.absolute(B, U)") do
1491
+ [mksubset(universe), mksubset(universe)]
1492
+ end.check do |a, b|
1493
+ a.replace(b.to_a).should == b
1494
+ end
1495
+ end
1496
+
1497
+ context "and B ⊈ U" do
1498
+ property("then A.replace(B) raises an error") do
1499
+ a = mksubset(universe)
1500
+ b = mksubset(universe)
1501
+ c = mksubset(universe)
1502
+ guard(!c.empty?)
1503
+
1504
+ [a, (b.to_a | c.to_a.map(&:upcase))]
1505
+ end.check do |a, b|
1506
+ lambda { a.replace(b) }.should \
1507
+ raise_error(/universe does not contain/)
1508
+ end
1509
+ end
1510
+ end
1511
+ end
1512
+
1513
+ end