interval_notation 0.1.0

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.
@@ -0,0 +1,881 @@
1
+ require 'interval_notation'
2
+
3
+ include IntervalNotation
4
+ include IntervalNotation::BasicIntervals
5
+ include IntervalNotation::Syntax::Short
6
+
7
+ def each_combination_of_intervals(intervals)
8
+ basic_intervals = intervals.flat_map(&:intervals)
9
+ (1..basic_intervals.size / 2).each do |chunk_1_size|
10
+ indices = basic_intervals.size.times.to_a
11
+ indices.combination(chunk_1_size).each do |chunk_1_indices|
12
+ chunk_2_indices = indices - chunk_1_indices
13
+ chunk_1 = IntervalNotation::Operations.union(chunk_1_indices.map{|i| IntervalSet.new([basic_intervals[i]]) })
14
+ chunk_2 = IntervalNotation::Operations.union(chunk_2_indices.map{|i| IntervalSet.new([basic_intervals[i]]) })
15
+ yield chunk_1, chunk_2
16
+ end
17
+ end
18
+ end
19
+
20
+ describe IntervalNotation do
21
+ describe IntervalSet do
22
+ describe '.new' do
23
+ [ [OpenOpenInterval.new(1,3)],
24
+ [ClosedOpenInterval.new(1,3)],
25
+ [OpenClosedInterval.new(1,3)],
26
+ [ClosedClosedInterval.new(1,3)],
27
+ [Point.new(3)],
28
+ [OpenOpenInterval.new(-Float::INFINITY, 1)],
29
+ [OpenOpenInterval.new(-Float::INFINITY, 1), OpenOpenInterval.new(2,3)],
30
+ [OpenOpenInterval.new(10, Float::INFINITY)],
31
+ [OpenOpenInterval.new(2,3), OpenOpenInterval.new(10, Float::INFINITY)],
32
+ [OpenOpenInterval.new(1,3), Point.new(4)],
33
+ [OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,6)],
34
+ [OpenOpenInterval.new(1,3), OpenOpenInterval.new(4,6)],
35
+ [OpenOpenInterval.new(1,3), ClosedOpenInterval.new(4,6)],
36
+ [OpenClosedInterval.new(1,3), OpenOpenInterval.new(4,6)],
37
+ [OpenClosedInterval.new(1,3), ClosedOpenInterval.new(4,6)],
38
+ [ClosedClosedInterval.new(1,3), ClosedClosedInterval.new(4,6)],
39
+ [OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,6), ClosedClosedInterval.new(7,10), Point.new(11)]
40
+ ].each do |intervals|
41
+ it("IntervalSet.new(#{intervals.map(&:to_s).join(',')}) should not fail") do
42
+ expect{ IntervalSet.new(intervals) }.not_to raise_error
43
+ end
44
+ end
45
+
46
+ [ [OpenOpenInterval.new(3,6), OpenOpenInterval.new(1,3)],
47
+ [OpenOpenInterval.new(1,3), Point.new(1)],
48
+ [OpenOpenInterval.new(1,3), Point.new(0)],
49
+
50
+ [OpenOpenInterval.new(-Float::INFINITY, 1), OpenOpenInterval.new(0,3)],
51
+ [OpenOpenInterval.new(-Float::INFINITY, 1), OpenOpenInterval.new(-1,0)],
52
+ [OpenOpenInterval.new(-Float::INFINITY, 1), OpenOpenInterval.new(-1,1)],
53
+ [OpenOpenInterval.new(-Float::INFINITY, 1), Point.new(0)],
54
+ [OpenOpenInterval.new(-Float::INFINITY, 1), Point.new(1)],
55
+ [Point.new(2), OpenOpenInterval.new(-Float::INFINITY, 1)],
56
+
57
+ [Point.new(11), OpenOpenInterval.new(10, Float::INFINITY)],
58
+ [Point.new(10), OpenOpenInterval.new(10, Float::INFINITY)],
59
+ [OpenOpenInterval.new(10, Float::INFINITY), Point.new(11)],
60
+ [OpenOpenInterval.new(10, Float::INFINITY), Point.new(9)],
61
+ [OpenOpenInterval.new(10, Float::INFINITY), OpenOpenInterval.new(9,13)],
62
+ [OpenOpenInterval.new(10, Float::INFINITY), OpenOpenInterval.new(11,13)],
63
+
64
+ [OpenOpenInterval.new(1,3), Point.new(3)],
65
+ [OpenOpenInterval.new(1,3), ClosedOpenInterval.new(3,4)],
66
+ [OpenClosedInterval.new(1,3), ClosedOpenInterval.new(3,4)],
67
+ [OpenClosedInterval.new(1,3), OpenOpenInterval.new(3,4)],
68
+ [OpenOpenInterval.new(1,4), OpenOpenInterval.new(1,4)],
69
+ [OpenOpenInterval.new(1,4), OpenOpenInterval.new(2,3)],
70
+ [OpenOpenInterval.new(1,4), OpenOpenInterval.new(2,5)]
71
+ ].each do |intervals|
72
+ it("IntervalSet.new(#{intervals.map(&:to_s).join(',')}) should fail") do
73
+ expect{ IntervalSet.new(intervals) }.to raise_error(Error)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '.to_s' do
80
+ {
81
+ Empty => '∅',
82
+ R => '(-∞;+∞)',
83
+ oo(1,3) => '(1;3)',
84
+ oc(1,3) => '(1;3]',
85
+ co(1,3) => '[1;3)',
86
+ cc(1,3) => '[1;3]',
87
+ lt(3) => '(-∞;3)',
88
+ le(3) => '(-∞;3]',
89
+ gt(3) => '(3;+∞)',
90
+ ge(3) => '[3;+∞)',
91
+ pt(2) => '{2}',
92
+ oo(1,3) | cc(4,5) => '(1;3)∪[4;5]',
93
+ oo(1,3) | pt(4) => '(1;3)∪{4}',
94
+ pt(-1) | oo(1,3) | pt(4) => '{-1}∪(1;3)∪{4}',
95
+ pt(1) | pt(4) => '{1}∪{4}',
96
+ }.each do |interval, str|
97
+ it "String representation #{interval.to_s} should eq #{str}" do
98
+ expect(interval.to_s).to eq str
99
+ end
100
+ it "Interval created by string representation #{interval.to_s} is the same as a source interval" do
101
+ expect(IntervalNotation::IntervalSet.from_string(interval.to_s)).to eq interval
102
+ end
103
+ end
104
+ end
105
+
106
+ describe 'IntervalNotation::IntervalSet.from_string' do
107
+ {
108
+ '∅' => Empty,
109
+ 'Empty' => Empty,
110
+ 'empty' => Empty,
111
+ '' => Empty,
112
+ 'R' => R,
113
+ '3' => pt(3),
114
+ '-3' => pt(-3),
115
+ '{3}' => pt(3),
116
+ '{3,5}' => pt(3) | pt(5),
117
+ '{3;5}' => pt(3) | pt(5),
118
+ '{3}u{5}' => pt(3) | pt(5),
119
+ '{3}U{5}' => pt(3) | pt(5),
120
+ '{3}∪{5}' => pt(3) | pt(5),
121
+ '(0,1)' => oo(0,1),
122
+ '(0,1]' => oc(0,1),
123
+ '[0,1)' => co(0,1),
124
+ '[0,1]' => cc(0,1),
125
+ '(0,1)U(2,5.5)' => oo(0,1) | oo(2,5.5),
126
+ '(0;1)U(2;5.5)' => oo(0,1) | oo(2,5.5),
127
+ '(- 2; 5.5)' => oo(-2, 5.5),
128
+ '(-∞; ∞)' => R,
129
+ '(-∞; 1)' => lt(1),
130
+ '(-inf; 1)' => lt(1),
131
+ '(-infty; 1)' => lt(1),
132
+ '(-\infty; 1)' => lt(1),
133
+ '(-infinity; 1)' => lt(1),
134
+ '(1;∞)' => gt(1),
135
+ '(1;inf)' => gt(1),
136
+ '(1;infty)' => gt(1),
137
+ '(1;\infty)' => gt(1),
138
+ '(1;infinity)' => gt(1),
139
+ '(1;+∞)' => gt(1),
140
+ '[1;+∞)' => ge(1),
141
+ '[1;+inf)' => ge(1),
142
+ '[1;+infty)' => ge(1),
143
+ '[1;+\infty)' => ge(1),
144
+ '[1;+infinity)' => ge(1),
145
+ }.each do |str, interval|
146
+ it "IntervalNotation::IntervalSet.from_string from string #{str} should eq #{interval}" do
147
+ expect(IntervalNotation::IntervalSet.from_string(str)).to eq interval
148
+ end
149
+ end
150
+ end
151
+
152
+ describe '.union' do
153
+ [ [Empty],
154
+ [oo(1,3)],
155
+ [Empty, Empty],
156
+ [Empty, oo(1,3)],
157
+ [oo(1,3), Empty],
158
+ [oo(1,3), pt(3)],
159
+ [oo(1,3), pt(4)],
160
+ [oo(1,3), oo(5,6)],
161
+ [oo(1,3), oo(2,6)],
162
+ [oo(1,3), oo(3,6)],
163
+ [oo(1,3), co(3,6)],
164
+ [oc(1,3), oo(3,6)],
165
+ [oc(1,3), co(3,6)],
166
+ [oo(1,3), oo(3,6), oo(7,9)],
167
+ [oc(1,3), co(3,6), oo(7,9)],
168
+ [oo(1,3), pt(3), oo(3,5)],
169
+ [oo(1,3), oo(3,6), oo(7,9), oo(15,19), oc(123,190)],
170
+ [oo(1,3), oo(3,6), oo(7,9), oo(15,19), oc(123,190),cc(4,18)],
171
+ [lt(0),oo(1,3), oo(3,6), oo(7,9), oo(15,19), oc(123,190),cc(4,18),ge(180)],
172
+ ].each do |intervals|
173
+ it "IntervalNotation::Operations.union(#{intervals.map(&:to_s).join(',')}) should be equal to #{intervals.map(&:to_s).join('|')}" do
174
+ expect( IntervalNotation::Operations.union(intervals) ).to eq intervals.inject(&:|)
175
+ end
176
+ end
177
+ end
178
+
179
+ describe '#empty?' do
180
+ {
181
+ Empty => true,
182
+ pt(1) => false,
183
+ pt(1)|pt(3) => false,
184
+ oo(1,5) => false,
185
+ oo(1,5)|pt(7) => false,
186
+ oo(1,3)|oo(3,5) => false,
187
+ oo(1,3)|oo(3,5)|cc(6,7) => false
188
+ }.each do |interval, answer|
189
+ it "#{interval}.empty? should be #{answer}" do
190
+ expect( interval.empty? ).to eq answer
191
+ end
192
+ end
193
+ end
194
+
195
+ describe '#union' do
196
+ {
197
+ # Union of non-overlapping intervals
198
+ [pt(3), pt(5)] => IntervalSet.new([Point.new(3), Point.new(5)]),
199
+ [oo(1,3), pt(5)] => IntervalSet.new([OpenOpenInterval.new(1,3), Point.new(5)]),
200
+ [oo(1,3), oo(3,5)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5)]),
201
+ [oo(1,3), oo(4,5)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(4,5)]),
202
+ [oo(3,5), oo(1,3)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5)]),
203
+ [oo(4,5), oo(1,3)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(4,5)]),
204
+
205
+ [oo(1,3), oo(3,5), cc(7,9)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5), ClosedClosedInterval.new(7,9)]),
206
+ [oo(1,3), oo(3,5), oo(5,7)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5), OpenOpenInterval.new(5,7)]),
207
+ [oo(1,3), cc(7,9), oo(3,5)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5), ClosedClosedInterval.new(7,9)]),
208
+ [oo(1,3), oc(7,9), oo(3,5)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5), OpenClosedInterval.new(7,9)]),
209
+ [oo(1,3), co(7,9), oo(3,5)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5), ClosedOpenInterval.new(7,9)]),
210
+ [oo(1,3), ge(7), oo(3,5)] => IntervalSet.new([OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5), ClosedOpenInterval.new(7,Float::INFINITY)]),
211
+ [oo(1,3), gt(7), oo(3,5),le(0)] => IntervalSet.new([OpenClosedInterval.new(-Float::INFINITY,0), OpenOpenInterval.new(1,3), OpenOpenInterval.new(3,5), OpenOpenInterval.new(7,Float::INFINITY)]),
212
+
213
+ # union with empty interval
214
+ [oo(1,3), Empty] => oo(1,3),
215
+ [oo(1,3)|oo(3,5)|cc(7,9), Empty] => oo(1,3)|oo(3,5)|cc(7,9),
216
+
217
+ # interval united with point
218
+ [oo(1,3), pt(2)] => oo(1,3),
219
+ [oo(1,3), pt(1)] => co(1,3),
220
+ [co(1,3), pt(1)] => co(1,3),
221
+ [oo(1,3), pt(0)] => pt(0)|oo(1,3),
222
+
223
+ # union with almost the same interval
224
+ [pt(3), pt(3)] => pt(3),
225
+ [pt(3)|pt(5), pt(3)|pt(5)] => pt(3)|pt(5),
226
+ [oo(1,3), oo(1,3)] => oo(1,3),
227
+ [oo(1,3), oc(1,3)] => oc(1,3),
228
+ [oo(1,3), co(1,3)] => co(1,3),
229
+ [oo(1,3), cc(1,3)] => cc(1,3),
230
+
231
+ [oo(1,3)|oo(5,7), oo(1,3)|oo(5,7)] => oo(1,3)|oo(5,7),
232
+ [oo(1,3)|co(5,7), oo(1,3)|oo(5,7)] => oo(1,3)|co(5,7),
233
+ [oo(1,3)|oo(5,7), oo(1,3)|co(5,7)] => oo(1,3)|co(5,7),
234
+ [oo(1,3)|co(5,7), oo(1,3)|co(5,7)] => oo(1,3)|co(5,7),
235
+
236
+ [pt(3)|pt(5), pt(3)|pt(7)] => pt(3)|pt(5)|pt(7),
237
+ }.merge({ # too long hash to be one hash
238
+ # infinite intervals
239
+ # gt
240
+ [gt(3), oo(1,2)] => IntervalSet.new([OpenOpenInterval.new(1, 2), OpenOpenInterval.new(3, Float::INFINITY)]),
241
+ [gt(3), oo(1,3)] => IntervalSet.new([OpenOpenInterval.new(1, 3), OpenOpenInterval.new(3, Float::INFINITY)]),
242
+ [gt(3), co(1,3)] => IntervalSet.new([ClosedOpenInterval.new(1, 3), OpenOpenInterval.new(3, Float::INFINITY)]),
243
+ [gt(3), oc(1,3)] => gt(1),
244
+ [gt(3), cc(1,3)] => ge(1),
245
+
246
+ [gt(3), oo(2,5)] => gt(2),
247
+ [gt(3), co(2,5)] => ge(2),
248
+ [gt(3), co(4,5)] => gt(3),
249
+ [gt(3), oo(4,5)] => gt(3),
250
+ [gt(3), oo(3,5)] => gt(3),
251
+ [gt(3), co(3,5)] => ge(3),
252
+ [gt(3), pt(2)] => IntervalSet.new([Point.new(2), OpenOpenInterval.new(3, Float::INFINITY)]),
253
+ [gt(3), pt(3)] => ge(3),
254
+ [gt(3), pt(4)] => gt(3),
255
+
256
+ # ge
257
+ [ge(3), oo(1,2)] => IntervalSet.new([OpenOpenInterval.new(1, 2), ClosedOpenInterval.new(3, Float::INFINITY)]),
258
+ [ge(3), oo(1,3)] => gt(1),
259
+ [ge(3), co(1,3)] => ge(1),
260
+ [ge(3), oc(1,3)] => gt(1),
261
+ [ge(3), cc(1,3)] => ge(1),
262
+
263
+ [ge(3), oo(2,5)] => gt(2),
264
+ [ge(3), co(2,5)] => ge(2),
265
+ [ge(3), co(4,5)] => ge(3),
266
+ [ge(3), oo(4,5)] => ge(3),
267
+ [ge(3), oo(3,5)] => ge(3),
268
+ [ge(3), co(3,5)] => ge(3),
269
+ [ge(3), pt(2)] => IntervalSet.new([Point.new(2), ClosedOpenInterval.new(3, Float::INFINITY)]),
270
+ [ge(3), pt(3)] => ge(3),
271
+ [ge(3), pt(4)] => ge(3),
272
+
273
+ # lt
274
+ [lt(3), oo(4,5)] => IntervalSet.new([OpenOpenInterval.new(-Float::INFINITY, 3), OpenOpenInterval.new(4, 5)]),
275
+ [lt(3), oo(3,5)] => IntervalSet.new([OpenOpenInterval.new(-Float::INFINITY, 3), OpenOpenInterval.new(3, 5)]),
276
+ [lt(3), co(3,5)] => lt(5),
277
+ [lt(3), oc(3,5)] => IntervalSet.new([OpenOpenInterval.new(-Float::INFINITY, 3), OpenClosedInterval.new(3, 5)]),
278
+ [lt(3), cc(3,5)] => le(5),
279
+
280
+ [lt(3), oo(1,2)] => lt(3),
281
+ [lt(3), oo(1,3)] => lt(3),
282
+ [lt(3), oo(1,4)] => lt(4),
283
+ [lt(3), oc(1,2)] => lt(3),
284
+ [lt(3), oc(1,3)] => le(3),
285
+ [lt(3), oc(1,4)] => le(4),
286
+ [lt(3), pt(2)] => lt(3),
287
+ [lt(3), pt(3)] => le(3),
288
+ [lt(3), pt(4)] => IntervalSet.new([OpenOpenInterval.new(-Float::INFINITY, 3), Point.new(4)]),
289
+
290
+ # le
291
+ [le(3), oo(4,5)] => IntervalSet.new([OpenClosedInterval.new(-Float::INFINITY, 3), OpenOpenInterval.new(4, 5)]),
292
+ [le(3), oo(3,5)] => lt(5),
293
+ [le(3), co(3,5)] => lt(5),
294
+ [le(3), oc(3,5)] => le(5),
295
+ [le(3), cc(3,5)] => le(5),
296
+
297
+ [le(3), oo(1,2)] => le(3),
298
+ [le(3), oo(1,3)] => le(3),
299
+ [le(3), oo(1,4)] => lt(4),
300
+ [le(3), oc(1,2)] => le(3),
301
+ [le(3), oc(1,3)] => le(3),
302
+ [le(3), oc(1,4)] => le(4),
303
+ [le(3), pt(2)] => le(3),
304
+ [le(3), pt(3)] => le(3),
305
+ [le(3), pt(4)] => IntervalSet.new([OpenClosedInterval.new(-Float::INFINITY, 3), Point.new(4)]),
306
+
307
+ # both infinite
308
+ [lt(3), gt(4)] => IntervalSet.new([OpenOpenInterval.new(-Float::INFINITY, 3), OpenOpenInterval.new(4, Float::INFINITY)]),
309
+ [lt(3), gt(3)] => IntervalSet.new([OpenOpenInterval.new(-Float::INFINITY, 3), OpenOpenInterval.new(3, Float::INFINITY)]),
310
+ [lt(3), ge(3)] => R,
311
+ [le(3), gt(3)] => R,
312
+ [le(3), ge(3)] => R,
313
+ [lt(3), gt(2)] => R,
314
+ }).merge({ # too long hash to be one hash
315
+ # non-adjacent
316
+ [oo(1,3), oo(5,6)] => IntervalSet.new([OpenOpenInterval.new(1, 3), OpenOpenInterval.new(5, 6)]),
317
+
318
+ # adjacent
319
+ [oo(1,3), oo(3,6)] => IntervalSet.new([OpenOpenInterval.new(1, 3), OpenOpenInterval.new(3, 6)]),
320
+ [oo(1,3), co(3,6)] => oo(1,6),
321
+ [oc(1,3), oo(3,6)] => oo(1,6),
322
+ [oc(1,3), co(3,6)] => oo(1,6),
323
+ [oo(1,3), oo(0,1)] => IntervalSet.new([OpenOpenInterval.new(0, 1), OpenOpenInterval.new(1, 3)]),
324
+ [oo(1,3), oc(0,1)] => oo(0,3),
325
+ [co(1,3), oo(0,1)] => oo(0,3),
326
+ [co(1,3), oc(0,1)] => oo(0,3),
327
+
328
+ # overlapping
329
+ [oo(1,3), oo(2,6)] => oo(1,6),
330
+ [oo(1,3), co(2,6)] => oo(1,6),
331
+ [oc(1,3), oo(2,6)] => oo(1,6),
332
+ [oc(1,3), co(2,6)] => oo(1,6),
333
+ [oo(1,3), oo(0,2)] => oo(0,3),
334
+ [oo(1,3), oc(0,2)] => oo(0,3),
335
+ [co(1,3), oo(0,2)] => oo(0,3),
336
+ [co(1,3), oc(0,2)] => oo(0,3),
337
+
338
+ # inside
339
+ [oo(1,4), oo(1,4)] => oo(1,4),
340
+ [oo(1,4), oo(1,3)] => oo(1,4),
341
+ [oo(1,4), oo(2,4)] => oo(1,4),
342
+
343
+ [oo(1,4), oo(2,3)] => oo(1,4),
344
+ [oo(1,4), co(2,3)] => oo(1,4),
345
+ [oo(1,4), oc(2,3)] => oo(1,4),
346
+ [oo(1,4), cc(2,3)] => oo(1,4),
347
+
348
+
349
+ # almost inside
350
+ [oo(1,4), oc(1,4)] => oc(1,4),
351
+ [oo(1,4), co(1,4)] => co(1,4),
352
+ [oo(1,4), oc(1,4)] => oc(1,4),
353
+ [oo(1,4), cc(1,4)] => cc(1,4),
354
+ [oo(1,4), co(1,3)] => co(1,4),
355
+ [oo(1,4), oc(2,4)] => oc(1,4),
356
+
357
+ # outside and almost outside
358
+ [oo(1,4), oo(0,5)] => oo(0,5),
359
+ [oo(1,4), cc(0,5)] => cc(0,5),
360
+ [oo(1,4), oo(0,4)] => oo(0,4),
361
+ [oo(1,4), oo(1,5)] => oo(1,5),
362
+ [oo(1,4), co(1,5)] => co(1,5),
363
+ [oo(1,4), oc(0,4)] => oc(0,4),
364
+
365
+ # union of interval set with the deleted point with another interval
366
+ [oo(1,3)|oo(3,5), pt(2)] => oo(1,3)|oo(3,5),
367
+ [oo(1,3)|oo(3,5), pt(3)] => oo(1,5),
368
+ [oo(1,3)|oo(3,5), oo(1,3)] => oo(1,3)|oo(3,5),
369
+ [oo(1,3)|oo(3,5), oo(3,5)] => oo(1,3)|oo(3,5),
370
+ [oo(1,3)|oo(3,5), oo(1.5,2.5)] => oo(1,3)|oo(3,5),
371
+ [oo(1,3)|oo(3,5), oo(3,6)] => oo(1,3)|oo(3,6),
372
+ [oo(1,3)|oo(3,5), oo(4,6)] => oo(1,3)|oo(3,6),
373
+ [oo(1,3)|oo(3,5), oo(0,3)] => oo(0,3)|oo(3,5),
374
+ [oo(1,3)|oo(3,5), oo(0,2)] => oo(0,3)|oo(3,5),
375
+ [oo(1,3)|oo(3,5), oo(0,6)] => oo(0,6),
376
+ [oo(1,3)|oo(3,5), oo(1,5)] => oo(1,5),
377
+ [oo(1,3)|oo(3,5), oo(2,4)] => oo(1,5),
378
+ [oo(1,3)|oo(3,5), cc(2,4)] => oo(1,5),
379
+ [oo(1,3)|oo(3,5), oc(1,3)] => oo(1,5),
380
+ [oo(1,3)|oo(3,5), oc(2,3)] => oo(1,5),
381
+ [oo(1,3)|oo(3,5), co(3,4)] => oo(1,5),
382
+ }).merge({ # too long hash to be one hash
383
+ [oo(1,3)|oo(5,7), oo(3,5)] => oo(1,3) | oo(3,5) | oo(5,7),
384
+ [oo(1,3)|oo(5,7), co(3,5)] => oo(1,5) | oo(5,7),
385
+ [oo(1,3)|oo(5,7), oc(3,5)] => oo(1,3) | oo(3,7),
386
+ [oo(1,3)|oo(5,7), cc(3,5)] => oo(1,7),
387
+ [oo(1,3)|oo(5,7)|oo(11,13), oo(3,5)|oo(7,11)] => oo(1,3)|oo(3,5)|oo(5,7)|oo(7,11)|oo(11,13),
388
+ [oo(1,3)|cc(5,7)|oo(11,13), oo(3,5)|oo(7,11)] => oo(1,3)|oo(3,11)|oo(11,13),
389
+
390
+ # each interval is interval set
391
+ [oo(1,3)|oo(3,5), oo(2,3)|oo(3,7)] => oo(1,3)|oo(3,7),
392
+ [oo(1,5), oo(2,3)|oo(3,7)] => (oo(1,7)),
393
+ [oo(1,3)|oo(3,5), oo(2,7)] => (oo(1,7)),
394
+
395
+
396
+ [oo(1,3)|oo(5,7), oo(3,5)] => oo(1,3)|oo(3,5)|oo(5,7),
397
+ [oo(1,3)|oo(5,7), co(3,5)] => oo(1,5)|oo(5,7),
398
+ [oo(1,3)|oo(5,7), cc(3,5)] => oo(1,7),
399
+ }).each do |intervals, answer|
400
+ it "IntervalNotation::Operations.union(#{intervals.map(&:to_s).join(',')} should equal #{answer}" do
401
+ expect( IntervalNotation::Operations.union(intervals) ).to eq answer
402
+ end
403
+
404
+ it "IntervalNotation::Operations.union(#{intervals.map(&:to_s).join(',')} should equal consequent unite: #{intervals.map(&:to_s).join('|')}" do
405
+ expect( IntervalNotation::Operations.union(intervals) ).to eq intervals.inject(&:union)
406
+ end
407
+
408
+ if intervals.size == 2
409
+ interval_1, interval_2 = intervals
410
+ it "#{interval_1} | #{interval_2} should equal #{answer}" do
411
+ expect( interval_1.union(interval_2) ).to eq answer
412
+ end
413
+ end
414
+
415
+ each_combination_of_intervals(intervals) do |chunk_1, chunk_2|
416
+ it "#{chunk_1}.union(#{chunk_2}) should be equal to #{answer}" do
417
+ expect( chunk_1.union(chunk_2) ).to eq answer
418
+ end
419
+ end
420
+ end
421
+ end
422
+
423
+
424
+ describe '#intersection' do
425
+ {
426
+ [oo(1,3), oo(1,3)] => oo(1,3),
427
+ [oo(1,3), oc(1,3)] => oo(1,3),
428
+ [oo(1,3), co(1,3)] => oo(1,3),
429
+ [oo(1,3), cc(1,3)] => oo(1,3),
430
+
431
+ [pt(2), pt(3)] => Empty,
432
+ [pt(3), pt(3)] => pt(3),
433
+ [pt(3)|pt(5), pt(3)|pt(5)] => pt(3)|pt(5),
434
+ [pt(3)|pt(5), pt(3)|pt(7)] => pt(3),
435
+
436
+ [oo(1,3)|oo(5,7), oo(1,3)|oo(5,7)] => oo(1,3)|oo(5,7),
437
+ [oo(1,3)|co(5,7), oo(1,3)|oo(5,7)] => oo(1,3)|oo(5,7),
438
+ [oo(1,3)|oo(5,7), oo(1,3)|co(5,7)] => oo(1,3)|oo(5,7),
439
+ [oo(1,3)|co(5,7), oo(1,3)|co(5,7)] => oo(1,3)|co(5,7),
440
+
441
+ [oo(1,3)|oo(3,5), oo(1,3)] => oo(1,3),
442
+ [oo(1,3)|oo(3,5), oo(1,3)|oo(7,9)] => oo(1,3),
443
+ [oo(1,3)|oo(3,5), oo(3,5)] => oo(3,5),
444
+ [oo(1,3)|oo(3,5), oo(1,3)|oo(3,5)] => oo(1,3)|oo(3,5),
445
+
446
+ [oo(1,3), oo(4,5)] => Empty,
447
+ [oo(1,3), oo(3,5)] => Empty,
448
+ [oo(1,3), co(3,5)] => Empty,
449
+ [oc(1,3), oo(3,5)] => Empty,
450
+ [oc(1,3), co(3,5)] => pt(3),
451
+
452
+ [oo(1,3), oo(0,5)] => oo(1,3),
453
+ [oc(1,3), oo(0,5)] => oc(1,3),
454
+ [co(1,3), oo(0,5)] => co(1,3),
455
+ [cc(1,3), oo(0,5)] => cc(1,3),
456
+
457
+ [oo(1,3), oo(1,5)] => oo(1,3),
458
+ [co(1,3), oo(1,5)] => oo(1,3),
459
+ [oc(1,3), oo(1,5)] => oc(1,3),
460
+ [cc(1,3), oo(1,5)] => oc(1,3),
461
+ [co(3,5), oo(1,5)] => co(3,5),
462
+
463
+ [oo(1,3), oo(2,5)] => oo(2,3),
464
+ [oc(1,3), oo(2,5)] => oc(2,3),
465
+ [oo(1,3), co(2,5)] => co(2,3),
466
+ [oc(1,3), co(2,5)] => cc(2,3),
467
+
468
+ [oo(1,3), pt(2)] => pt(2),
469
+ [oo(1,3), pt(3)] => Empty,
470
+ [oc(1,3), pt(3)] => pt(3),
471
+ [oo(1,3), pt(4)] => Empty,
472
+ [oc(1,3), pt(4)] => Empty,
473
+
474
+ [oo(1,3)|oo(3,5), oo(2,3)|oo(3,7)] => oo(2,3)|oo(3,5),
475
+ [oo(1,3)|oo(3,5), oo(2,7)] => oo(2,3)|oo(3,5),
476
+
477
+ [oo(2,6), oo(1,3)|co(5,7)] => oo(2,3)|co(5,6),
478
+ [oo(1,6), oo(1,3)|co(5,7)] => oo(1,3)|co(5,6),
479
+ [oo(0,6), oo(1,3)|co(5,7)] => oo(1,3)|co(5,6),
480
+ [oo(0,6), oo(1,3)|co(5,6)] => oo(1,3)|co(5,6),
481
+
482
+
483
+ }.each do |intervals, answer|
484
+ it "IntervalNotation::Operations.intersection(#{intervals.map(&:to_s).join(',')} should equal #{answer}" do
485
+ expect( IntervalNotation::Operations.intersection(intervals) ).to eq answer
486
+ end
487
+
488
+ it "IntervalNotation::Operations.intersection(#{intervals.map(&:to_s).join(',')} should equal consequent unite: #{intervals.map(&:to_s).join('&')}" do
489
+ expect( IntervalNotation::Operations.intersection(intervals) ).to eq intervals.inject(&:intersection)
490
+ end
491
+
492
+ if intervals.size == 2
493
+ interval_1, interval_2 = intervals
494
+ it "#{interval_1} & #{interval_2} should equal #{answer}" do
495
+ expect( interval_1.intersection(interval_2) ).to eq answer
496
+ end
497
+ end
498
+ end
499
+
500
+ {
501
+ [oo(1,3), oo(1,3), oo(1,3)] => oo(1,3),
502
+ [oo(1,3), cc(1,3), oo(1,3)] => oo(1,3),
503
+ [oo(1,3), cc(0,5), cc(1,3)] => oo(1,3),
504
+ [cc(1,5), cc(3,7), cc(1,3)|cc(5,7)] => pt(3)|pt(5),
505
+ [oo(1,5), oo(3,7), oo(1,3)|oo(5,7)] => Empty,
506
+ [oo(1,5), oc(1,3), co(3,5)] => pt(3)
507
+ }.each do |intervals, answer|
508
+ it "#{intervals.map(&:to_s).join('&')} should equal #{answer}" do
509
+ expect( IntervalNotation::Operations.intersection(intervals) ).to eq answer
510
+ end
511
+ end
512
+ end
513
+
514
+ describe '#subtract' do
515
+ {
516
+ [oo(1,5)|oo(6,8),(oo(1,5))] => oo(6,8),
517
+ [oo(1,5)|oo(6,8),(oo(1,8))] => Empty,
518
+ [oo(1,5)|oo(6,8),(cc(1,5))] => oo(6,8),
519
+ [oo(1,5),cc(2,3)] => oo(1,2)|oo(3,5),
520
+ [oo(1,5),oo(2,3)] => oc(1,2)|co(3,5),
521
+ [oo(1,5),oo(1,3)] => co(3,5),
522
+ [oo(1,5),pt(0)] => oo(1,5),
523
+ [oo(1,5),pt(1)] => oo(1,5),
524
+ [co(1,5),pt(1)] => oo(1,5),
525
+ [oo(1,5),pt(3)] => oo(1,3)|oo(3,5),
526
+ [cc(1,5),oo(1,3)] => pt(1)|cc(3,5),
527
+ [cc(1,5),co(1,3)] => cc(3,5),
528
+ [oo(1,5),cc(1,3)] => oo(3,5),
529
+ [oo(1,5),oo(0,3)] => co(3,5),
530
+ [oo(1,5),oo(0,2)|oo(3,4)] => cc(2,3)|co(4,5),
531
+ [R,oo(1,5)] => le(1)|ge(5),
532
+ [R,oc(1,5)] => le(1)|gt(5),
533
+ [R,co(1,5)] => lt(1)|ge(5),
534
+ [R,pt(3)] => lt(3)|gt(3),
535
+ [R,Empty] => R,
536
+ [R,R] => Empty,
537
+ [oo(1,5),R] => Empty,
538
+ [pt(3),R] => Empty,
539
+ [oo(1,3)|pt(5)|cc(7,10),R] => Empty,
540
+ [Empty,R] => Empty,
541
+ [Empty,pt(3)] => Empty,
542
+ [Empty,oo(1,3)] => Empty,
543
+ }.each do |(interval_1, interval_2), answer|
544
+ it "#{interval_1} - #{interval_2} should equal #{answer}" do
545
+ expect( interval_1.subtract(interval_2) ).to eq answer
546
+ end
547
+ end
548
+ end
549
+
550
+ describe '#symmetric_difference' do
551
+ {
552
+ [oo(1,3),oo(1,3)] => Empty,
553
+ [cc(1,3),cc(1,3)] => Empty,
554
+ [cc(1,3),pt(2)] => co(1,2)|oc(2,3),
555
+ [cc(1,3),oo(1,3)] => pt(1)|pt(3),
556
+ [oo(1,4),oo(2,3)] => oc(1,2)|co(3,4),
557
+ [oo(1,4),cc(2,3)] => oo(1,2)|oo(3,4),
558
+ [oo(1,4),Empty] => oo(1,4),
559
+ [oo(1,4),R] => le(1)|ge(4),
560
+ }.each do |(interval_1, interval_2), answer|
561
+ it "#{interval_1} ^ #{interval_2} should equal #{answer}" do
562
+ expect( interval_1.symmetric_difference(interval_2) ).to eq answer
563
+ end
564
+ it "#{interval_2} ^ #{interval_1} should equal #{answer}" do
565
+ expect( interval_2.symmetric_difference(interval_1) ).to eq answer
566
+ end
567
+ it "#{interval_1} ^ #{answer} should equal #{interval_2}" do
568
+ expect( interval_1.symmetric_difference(answer) ).to eq interval_2
569
+ end
570
+ it "#{interval_2} ^ #{answer} should equal #{interval_1}" do
571
+ expect( interval_2.symmetric_difference(answer) ).to eq interval_1
572
+ end
573
+ end
574
+ end
575
+
576
+ describe '#complement' do
577
+ {
578
+ oo(1,3)|cc(5,6) => le(1)|co(3,5)|gt(6),
579
+ oo(1,5) => le(1)|ge(5),
580
+ oc(1,5) => le(1)|gt(5),
581
+ co(1,5) => lt(1)|ge(5),
582
+ pt(3) => lt(3)|gt(3),
583
+ Empty => R,
584
+ R => Empty,
585
+ }.each do |interval, answer|
586
+ it "#{interval}.complement should equal #{answer}" do
587
+ expect( interval.complement ).to eq answer
588
+ end
589
+ end
590
+ end
591
+
592
+ describe '#include_position?' do
593
+ {
594
+ [oo(1,3), -100] => false,
595
+ [oo(1,3), 0] => false,
596
+ [oo(1,3), 1] => false,
597
+ [oo(1,3), 2] => true,
598
+ [oo(1,3), 3] => false,
599
+ [oo(1,3), 4] => false,
600
+ [oo(1,3), 100] => false,
601
+
602
+ [co(1,3), -100] => false,
603
+ [co(1,3), 0] => false,
604
+ [co(1,3), 1] => true,
605
+ [co(1,3), 2] => true,
606
+ [co(1,3), 3] => false,
607
+ [co(1,3), 4] => false,
608
+ [co(1,3), 100] => false,
609
+
610
+ [oc(1,3), -100] => false,
611
+ [oc(1,3), 0] => false,
612
+ [oc(1,3), 1] => false,
613
+ [oc(1,3), 2] => true,
614
+ [oc(1,3), 3] => true,
615
+ [oc(1,3), 4] => false,
616
+ [oc(1,3), 100] => false,
617
+
618
+ [cc(1,3), -100] => false,
619
+ [cc(1,3), 0] => false,
620
+ [cc(1,3), 1] => true,
621
+ [cc(1,3), 2] => true,
622
+ [cc(1,3), 3] => true,
623
+ [cc(1,3), 4] => false,
624
+ [cc(1,3), 100] => false,
625
+
626
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), -1] => false,
627
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 0] => true,
628
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 1] => true,
629
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 2] => true,
630
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 3] => false,
631
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 4] => true,
632
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 5] => false,
633
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 6] => true,
634
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 7] => false,
635
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 8] => true,
636
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 9] => true,
637
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 10] => true,
638
+ [cc(0,2)|pt(4)|pt(6)|cc(8,10), 11] => false,
639
+
640
+ [lt(-10)|cc(1,3)|ge(10), -1000] => true,
641
+ [lt(-10)|cc(1,3)|ge(10), -11] => true,
642
+ [lt(-10)|cc(1,3)|ge(10), -10] => false,
643
+ [lt(-10)|cc(1,3)|ge(10), -9] => false,
644
+ [lt(-10)|cc(1,3)|ge(10), 0] => false,
645
+ [lt(-10)|cc(1,3)|ge(10), 1] => true,
646
+ [lt(-10)|cc(1,3)|ge(10), 2] => true,
647
+ [lt(-10)|cc(1,3)|ge(10), 3] => true,
648
+ [lt(-10)|cc(1,3)|ge(10), 4] => false,
649
+ [lt(-10)|cc(1,3)|ge(10), 9] => false,
650
+ [lt(-10)|cc(1,3)|ge(10), 10] => true,
651
+ [lt(-10)|cc(1,3)|ge(10), 11] => true,
652
+ [lt(-10)|cc(1,3)|ge(10), 1000] => true,
653
+ }.each do |(interval, point), answer|
654
+ if answer
655
+ it "#{interval}.include_position?(#{point}) should be truthy" do
656
+ expect( interval.include_position?(point) ).to be_truthy
657
+ end
658
+ else
659
+ it "#{interval}.include_position?(#{point}) should be falsy" do
660
+ expect( interval.include_position?(point) ).to be_falsy
661
+ end
662
+ end
663
+ end
664
+ end
665
+
666
+ describe '#contain? / contained_by?' do
667
+ {
668
+ [oo(1,3), oo(1,2)] => true,
669
+ [oo(1,3), oo(1.5,2.5)] => true,
670
+ [oo(1,3), cc(1.5,2.5)] => true,
671
+ [oo(1,3), oo(2,3)] => true,
672
+ [oo(1,3), oo(1,3)] => true,
673
+ [cc(1,3), oo(1,3)] => true,
674
+ [cc(1,3), cc(1,3)] => true,
675
+ [oo(1,3), cc(1,3)] => false,
676
+ [oo(1,3), co(1,3)] => false,
677
+ [oo(1,3)|pt(4)|cc(8,10), oo(1,3)|oc(9,10) ] => true,
678
+ [oo(1,3)|pt(4)|cc(8,10), oo(1,3)|pt(4) ] => true,
679
+ [oo(1,3)|pt(4)|cc(8,10), oo(1,3)|pt(5) ] => false,
680
+ [oo(1,3)|pt(4)|cc(8,10), oo(1,3)|pt(8) ] => true,
681
+ [lt(10), oo(1,3)] => true,
682
+ [lt(10), oo(10,11)] => false,
683
+ [le(10), oo(10,11)] => false,
684
+ }.each do |(interval_1, interval_2), answer|
685
+ if answer
686
+ it "#{interval_1}.contain?(#{interval_2}) should be truthy" do
687
+ expect( interval_1.contain?(interval_2) ).to be_truthy
688
+ end
689
+ it "#{interval_2}.contained_by?(#{interval_1}) should be truthy" do
690
+ expect( interval_2.contained_by?(interval_1) ).to be_truthy
691
+ end
692
+ else
693
+ it "#{interval_1}.contain?(#{interval_2}) should be falsy" do
694
+ expect( interval_1.contain?(interval_2) ).to be_falsy
695
+ end
696
+ it "#{interval_2}.contained_by?(#{interval_1}) should be falsy" do
697
+ expect( interval_2.contained_by?(interval_1) ).to be_falsy
698
+ end
699
+ end
700
+ end
701
+ end
702
+
703
+ describe '#intersect?' do
704
+ {
705
+ [oo(1,3), oo(1,2)] => true,
706
+ [oo(1,3), oo(1,3)] => true,
707
+ [oo(1,3), cc(1.5,2.5)] => true,
708
+
709
+ [oo(1,3), oo(3,4)] => false,
710
+ [oc(1,3), oo(3,4)] => false,
711
+ [oo(1,3), co(3,4)] => false,
712
+ [oc(1,3), co(3,4)] => true,
713
+
714
+ [oo(1,3), oo(4,5)] => false,
715
+ [cc(1,3), cc(4,5)] => false,
716
+ [cc(1,3), pt(2)|cc(4,5)] => true,
717
+ [co(1,3), pt(2)|cc(4,5)] => true,
718
+ [cc(1,3), pt(3)|cc(4,5)] => true,
719
+ [co(1,3), pt(3)|cc(4,5)] => false,
720
+ [cc(1,3), cc(4,5)|pt(6)] => false,
721
+
722
+ [lt(10), oo(1,3)] => true,
723
+ [lt(10), oo(11,12)] => false,
724
+ [lt(10), oo(10,11)] => false,
725
+ [le(10), co(10,11)] => true,
726
+ [le(10), le(9)] => true,
727
+ [le(10), le(11)] => true,
728
+ [le(10), ge(11)] => false,
729
+ [le(10), ge(10)] => true,
730
+ [le(10), gt(10)] => false,
731
+ [le(10), gt(11)] => false,
732
+ }.each do |(interval_1, interval_2), answer|
733
+ if answer
734
+ it "#{interval_1}.intersect?(#{interval_2}) should be truthy" do
735
+ expect( interval_1.intersect?(interval_2) ).to be_truthy
736
+ end
737
+ else
738
+ it "#{interval_1}.intersect?(#{interval_2}) should be falsy" do
739
+ expect( interval_1.intersect?(interval_2) ).to be_falsy
740
+ end
741
+ end
742
+ end
743
+ end
744
+
745
+ describe '#contiguous?' do
746
+ it 'Empty interval is treated as contiguous' do
747
+ expect(Empty).to be_contiguous
748
+ end
749
+
750
+ it 'Single component intervals are treated as contiguous' do
751
+ expect(R).to be_contiguous
752
+ expect(oo(1,3)).to be_contiguous
753
+ expect(cc(1,3)).to be_contiguous
754
+ expect(lt(3)).to be_contiguous
755
+ expect(ge(3)).to be_contiguous
756
+ expect(pt(3)).to be_contiguous
757
+ end
758
+
759
+ it 'Several components intervals are treated as contiguous' do
760
+ expect(oo(1,3)|oo(3,5)).not_to be_contiguous
761
+ expect(oo(1,3)|oo(3,5)|oo(10,15)).not_to be_contiguous
762
+ expect(oo(1,3)|pt(5)).not_to be_contiguous
763
+ expect(cc(1,3)|pt(5)).not_to be_contiguous
764
+ expect(cc(1,3)|ge(5)).not_to be_contiguous
765
+ expect(pt(3)|ge(5)).not_to be_contiguous
766
+ expect(lt(3)|ge(5)).not_to be_contiguous
767
+ expect(pt(3)|pt(5)).not_to be_contiguous
768
+ end
769
+ end
770
+
771
+ describe '#num_connected_components' do
772
+ {
773
+ oo(1,3) => 1,
774
+ oc(1,3) => 1,
775
+ co(1,3) => 1,
776
+ cc(1,3) => 1,
777
+ oo(1,3) | oo(3,6) => 2,
778
+ oo(1,3) | oo(5,8) => 2,
779
+ oo(1,3) | oo(3,6) | cc(10,15) => 3,
780
+ oo(1,3) | pt(4) | oo(5,8) => 3,
781
+ Empty => 0,
782
+ pt(3) => 1,
783
+ pt(3) | pt(5) => 2,
784
+ lt(3) => 1,
785
+ le(3) => 1,
786
+ gt(3) => 1,
787
+ ge(3) => 1,
788
+ R => 1,
789
+ }.each do |interval, answer|
790
+ it "#{interval}.num_connected_components should equal #{answer}" do
791
+ expect(interval.num_connected_components).to eq answer
792
+ end
793
+ end
794
+ end
795
+
796
+ describe '#total_length' do
797
+ {
798
+ oo(1,3) => 2,
799
+ oc(1,3) => 2,
800
+ co(1,3) => 2,
801
+ cc(1,3) => 2,
802
+ oo(1,3) | oo(3,6) => 5,
803
+ oo(1,3) | oo(5,8) => 5,
804
+ oo(1,3) | pt(4) | oo(5,8) => 5,
805
+ Empty => 0,
806
+ pt(3) => 0,
807
+ pt(3) | pt(5) => 0,
808
+ lt(3) => Float::INFINITY,
809
+ le(3) => Float::INFINITY,
810
+ gt(3) => Float::INFINITY,
811
+ ge(3) => Float::INFINITY,
812
+ R => Float::INFINITY,
813
+ }.each do |interval, answer|
814
+ it "#{interval}.total_length should equal #{answer}" do
815
+ expect(interval.total_length).to eq answer
816
+ end
817
+ end
818
+ end
819
+
820
+ describe '#covering_interval' do
821
+ {
822
+ Empty => Empty,
823
+ oo(1,3) => oo(1,3),
824
+ oc(1,3) => oc(1,3),
825
+ co(1,3) => co(1,3),
826
+ cc(1,3) => cc(1,3),
827
+ pt(3) => pt(3),
828
+ lt(3) => lt(3),
829
+ le(3) => le(3),
830
+ gt(3) => gt(3),
831
+ ge(3) => ge(3),
832
+ R => R,
833
+ pt(3) | pt(4) => cc(3,4),
834
+ oo(1,3) | pt(4) => oc(1,4),
835
+ pt(0) | oo(1,3) | pt(4) => cc(0,4),
836
+ pt(0) | oc(1,3) => cc(0,3),
837
+ oo(1,3) | oo(3,6) => oo(1,6),
838
+ oo(1,3) | oc(3,6) => oc(1,6),
839
+ oo(1,3) | oc(5,8) => oc(1,8),
840
+ co(1,3) | oc(5,8) => cc(1,8),
841
+ cc(1,3) | cc(5,8) => cc(1,8),
842
+ oo(1,3) | oo(3,6) | cc(10,15) => oc(1,15),
843
+ oo(1,3) | pt(4) | oo(5,8) => oo(1,8),
844
+ }.each do |interval, answer|
845
+ it "#{interval}.covering_interval should equal #{answer}" do
846
+ expect(interval.covering_interval).to eq answer
847
+ end
848
+ end
849
+ end
850
+
851
+ describe '#closure' do
852
+ {
853
+ Empty => Empty,
854
+ oo(1,3) => cc(1,3),
855
+ oc(1,3) => cc(1,3),
856
+ co(1,3) => cc(1,3),
857
+ cc(1,3) => cc(1,3),
858
+ pt(3) => pt(3),
859
+ lt(3) => le(3),
860
+ le(3) => le(3),
861
+ gt(3) => ge(3),
862
+ ge(3) => ge(3),
863
+ lt(3) | gt(3) => R,
864
+ lt(3) | gt(4) => le(3) | ge(4),
865
+ oo(1,3) | oo(4,5) => cc(1,3) | cc(4,5),
866
+ oc(1,3) | co(4,5) => cc(1,3) | cc(4,5),
867
+ R => R,
868
+ oo(1,3) | pt(4) => cc(1,3) | pt(4),
869
+ pt(3) | pt(4) => pt(3) | pt(4),
870
+ oo(1,3) | oo(3,4) => cc(1,4),
871
+ co(1,3) | oc(3,4) => cc(1,4),
872
+ oo(1,3) | oo(3,6) | cc(10,15) => cc(1,6) | cc(10,15),
873
+ oo(1,3) | oo(3,6) | gt(10) => cc(1,6) | ge(10),
874
+ oo(1,3) | pt(4) | oo(5,8) => cc(1,3) | pt(4) | cc(5,8),
875
+ }.each do |interval, answer|
876
+ it "#{interval}.covering_interval should equal #{answer}" do
877
+ expect(interval.closure).to eq answer
878
+ end
879
+ end
880
+ end
881
+ end