1 ! Copyright (C) 2007, 2009 Slava Pestov, Doug Coleman.
2 ! See https://factorcode.org/license.txt for BSD license.
3 ! Based on Slate's src/unfinished/interval.slate by Brian Rice.
4 USING: accessors kernel sequences arrays math math.order
5 combinators combinators.short-circuit generic layouts memoize ;
8 SINGLETON: empty-interval
9 SINGLETON: full-interval
10 UNION: special-interval empty-interval full-interval ;
12 TUPLE: interval { from read-only } { to read-only } ;
14 M: empty-interval from>> drop { 1/0. f } ;
15 M: empty-interval to>> drop { -1/0. f } ;
16 M: full-interval from>> drop { -1/0. t } ;
17 M: full-interval to>> drop { 1/0. t } ;
19 : closed-point? ( from to -- ? )
20 2dup [ first ] bi@ number=
21 [ [ second ] both? ] [ 2drop f ] if ;
23 : <interval> ( from to -- interval )
25 { [ 2dup [ first ] bi@ > ] [ 2drop empty-interval ] }
26 { [ 2dup [ first ] bi@ number= ] [
28 [ interval boa ] [ 2drop empty-interval ] if
30 { [ 2dup [ { -1/0. t } = ] [ { 1/0. t } = ] bi* and ] [
36 : open-point ( n -- endpoint ) f 2array ;
38 : closed-point ( n -- endpoint ) t 2array ;
40 : [a,b] ( a b -- interval )
41 [ closed-point ] dip closed-point <interval> ; foldable
43 : (a,b) ( a b -- interval )
44 [ open-point ] dip open-point <interval> ; foldable
46 : [a,b) ( a b -- interval )
47 [ closed-point ] dip open-point <interval> ; foldable
49 : (a,b] ( a b -- interval )
50 [ open-point ] dip closed-point <interval> ; foldable
52 : [a,a] ( a -- interval )
53 closed-point dup <interval> ; foldable
55 : [-inf,b] ( b -- interval ) -1/0. swap [a,b] ; inline
57 : [-inf,b) ( b -- interval ) -1/0. swap [a,b) ; inline
59 : [a,inf] ( a -- interval ) 1/0. [a,b] ; inline
61 : (a,inf] ( a -- interval ) 1/0. (a,b] ; inline
63 : [0,b] ( b -- interval ) 0 swap [a,b] ; inline
65 : [0,b) ( b -- interval ) 0 swap [a,b) ; inline
67 MEMO: [0,inf] ( -- interval ) 0 [a,inf] ; foldable
69 MEMO: fixnum-interval ( -- interval )
70 most-negative-fixnum most-positive-fixnum [a,b] ; inline
72 MEMO: array-capacity-interval ( -- interval )
73 0 max-array-capacity [a,b] ; inline
75 : [-inf,inf] ( -- interval ) full-interval ; inline
77 : compare-endpoints ( p1 p2 quot -- ? )
78 [ 2dup [ first ] bi@ 2dup ] dip call [
81 number= [ [ second ] bi@ not or ] [ 2drop f ] if
84 : endpoint= ( p1 p2 -- ? )
85 { [ [ first ] bi@ number= ] [ [ second ] bi@ eq? ] } 2&& ;
87 : endpoint< ( p1 p2 -- ? )
88 [ < ] compare-endpoints ;
90 : endpoint<= ( p1 p2 -- ? )
91 { [ endpoint< ] [ endpoint= ] } 2|| ;
93 : endpoint> ( p1 p2 -- ? )
94 [ > ] compare-endpoints ;
96 : endpoint>= ( p1 p2 -- ? )
97 { [ endpoint> ] [ endpoint= ] } 2|| ;
99 : endpoint-min ( p1 p2 -- p3 ) [ endpoint< ] most ;
101 : endpoint-max ( p1 p2 -- p3 ) [ endpoint> ] most ;
103 : interval>points ( interval -- from to )
104 [ from>> ] [ to>> ] bi ;
106 : points>interval ( seq -- interval nan? )
107 [ first fp-nan? not ] partition
109 [ [ ] [ endpoint-min ] map-reduce ]
110 [ [ ] [ endpoint-max ] map-reduce ] bi
116 : nan-ok ( interval nan? -- interval ) drop ; inline
117 : nan-not-ok ( interval nan? -- interval ) [ drop full-interval ] when ; inline
119 : (interval-op) ( p1 p2 quot -- p3 )
120 [ [ first ] [ first ] [ call ] tri* ]
121 [ drop [ second ] both? ]
124 : interval-op ( i1 i2 quot -- i3 nan? )
126 [ [ from>> ] [ from>> ] [ ] tri* (interval-op) ]
127 [ [ to>> ] [ from>> ] [ ] tri* (interval-op) ]
128 [ [ to>> ] [ to>> ] [ ] tri* (interval-op) ]
129 [ [ from>> ] [ to>> ] [ ] tri* (interval-op) ]
130 } 3cleave 4array points>interval ; inline
132 : do-empty-interval ( i1 i2 quot -- i3 )
134 { [ pick empty-interval? ] [ 2drop ] }
135 { [ over empty-interval? ] [ drop nip ] }
136 { [ pick full-interval? ] [ 2drop ] }
137 { [ over full-interval? ] [ drop nip ] }
141 : interval+ ( i1 i2 -- i3 )
142 [ [ + ] interval-op nan-ok ] do-empty-interval ;
144 : interval- ( i1 i2 -- i3 )
145 [ [ - ] interval-op nan-ok ] do-empty-interval ;
147 : interval-intersect ( i1 i2 -- i3 )
149 { [ over empty-interval? ] [ drop ] }
150 { [ dup empty-interval? ] [ nip ] }
151 { [ over full-interval? ] [ nip ] }
152 { [ dup full-interval? ] [ drop ] }
154 [ interval>points ] bi@
155 [ [ swap endpoint< ] most ]
156 [ [ swap endpoint> ] most ] bi-curry* bi*
161 : intervals-intersect? ( i1 i2 -- ? )
162 interval-intersect empty-interval? not ;
164 : interval-union ( i1 i2 -- i3 )
166 { [ over empty-interval? ] [ nip ] }
167 { [ dup empty-interval? ] [ drop ] }
168 { [ over full-interval? ] [ drop ] }
169 { [ dup full-interval? ] [ nip ] }
170 [ [ interval>points 2array ] bi@ append points>interval nan-not-ok ]
173 : interval-subset? ( i1 i2 -- ? )
174 dupd interval-intersect = ;
176 GENERIC: interval-contains? ( x interval -- ? )
177 M: empty-interval interval-contains? 2drop f ;
178 M: full-interval interval-contains? 2drop t ;
179 M: interval interval-contains?
181 [ from>> first2 [ >= ] [ > ] if ]
182 [ to>> first2 [ <= ] [ < ] if ]
185 : interval-zero? ( interval -- ? )
186 0 swap interval-contains? ;
188 : interval* ( i1 i2 -- i3 )
189 [ [ [ * ] interval-op nan-ok ] do-empty-interval ]
190 [ [ interval-zero? ] either? ]
191 2bi [ 0 [a,a] interval-union ] when ;
193 : interval-1+ ( i1 -- i2 ) 1 [a,a] interval+ ;
195 : interval-1- ( i1 -- i2 ) -1 [a,a] interval+ ;
197 : interval-neg ( i1 -- i2 ) -1 [a,a] interval* ;
199 : interval-bitnot ( i1 -- i2 ) interval-neg interval-1- ;
201 : interval-sq ( i1 -- i2 ) dup interval* ;
203 GENERIC: interval-singleton? ( interval -- ? )
204 M: special-interval interval-singleton? drop f ;
205 M: interval interval-singleton?
207 2dup [ second ] both?
208 [ [ first ] bi@ number= ]
211 GENERIC: interval-length ( interval -- n )
212 M: empty-interval interval-length drop 0 ;
213 M: full-interval interval-length drop 1/0. ;
214 M: interval interval-length
215 interval>points [ first ] bi@ swap - ;
217 : interval-closure ( i1 -- i2 )
218 dup [ interval>points [ first ] bi@ [a,b] ] when ;
220 : interval-integer-op ( i1 i2 quot -- i3 )
222 2dup [ interval>points [ first integer? ] both? ] both?
223 ] dip [ 2drop [-inf,inf] ] if ; inline
225 : interval-shift ( i1 i2 -- i3 )
226 ! Inaccurate; could be tighter
229 [ interval-closure ] bi@
230 [ shift ] interval-op nan-not-ok
231 ] interval-integer-op
232 ] do-empty-interval ;
234 : interval-shift-safe ( i1 i2 -- i3 )
236 dup to>> first 100 > [
241 ] do-empty-interval ;
243 : interval-max ( i1 i2 -- i3 )
245 { [ over empty-interval? ] [ drop ] }
246 { [ dup empty-interval? ] [ nip ] }
247 { [ 2dup [ full-interval? ] both? ] [ drop ] }
248 { [ over full-interval? ] [ nip from>> first [a,inf] ] }
249 { [ dup full-interval? ] [ drop from>> first [a,inf] ] }
250 [ [ interval-closure ] bi@ [ max ] interval-op nan-not-ok ]
253 : interval-min ( i1 i2 -- i3 )
255 { [ over empty-interval? ] [ drop ] }
256 { [ dup empty-interval? ] [ nip ] }
257 { [ 2dup [ full-interval? ] both? ] [ drop ] }
258 { [ over full-interval? ] [ nip to>> first [-inf,b] ] }
259 { [ dup full-interval? ] [ drop to>> first [-inf,b] ] }
260 [ [ interval-closure ] bi@ [ min ] interval-op nan-not-ok ]
263 : interval-interior ( i1 -- i2 )
264 dup special-interval? [
265 interval>points [ first ] bi@ (a,b)
268 : interval-division-op ( i1 i2 quot -- i3 )
270 { [ 0 pick interval-closure interval-contains? ] [ 3drop [-inf,inf] ] }
271 { [ pick interval-zero? ] [ call 0 [a,a] interval-union ] }
275 : interval/ ( i1 i2 -- i3 )
276 [ [ [ / ] interval-op nan-not-ok ] interval-division-op ] do-empty-interval ;
278 : interval/-safe ( i1 i2 -- i3 )
279 ! Just a hack to make the compiler work if bootstrap.math
281 \ integer \ / ?lookup-method [ interval/ ] [ 2drop f ] if ;
283 : interval/i ( i1 i2 -- i3 )
287 [ interval-closure ] bi@
288 [ /i ] interval-op nan-not-ok
289 ] interval-integer-op
290 ] interval-division-op
291 ] do-empty-interval ;
293 : interval/f ( i1 i2 -- i3 )
294 [ [ [ /f ] interval-op nan-not-ok ] interval-division-op ] do-empty-interval ;
296 : (interval-abs) ( i1 -- i2 )
297 interval>points [ first2 [ abs ] dip 2array ] bi@ 2array ;
299 : interval-abs ( i1 -- i2 )
301 { [ dup empty-interval? ] [ ] }
302 { [ dup full-interval? ] [ drop [0,inf] ] }
303 { [ 0 over interval-contains? ] [ (interval-abs) { 0 t } suffix points>interval nan-not-ok ] }
304 [ (interval-abs) points>interval nan-not-ok ]
307 : interval-absq ( i1 -- i2 )
308 interval-abs interval-sq ;
310 : interval-recip ( i1 -- i2 ) 1 [a,a] swap interval/ ;
312 : interval-2/ ( i1 -- i2 ) -1 [a,a] interval-shift ;
316 : left-endpoint-< ( i1 i2 -- ? )
318 [ swap interval-subset? ]
319 [ nip interval-singleton? ]
320 [ [ from>> ] bi@ endpoint= ]
323 : right-endpoint-< ( i1 i2 -- ? )
326 [ drop interval-singleton? ]
327 [ [ to>> ] bi@ endpoint= ]
330 : (interval<) ( i1 i2 -- i1 i2 ? )
331 2dup [ from>> ] bi@ endpoint< ;
333 : interval< ( i1 i2 -- ? )
335 { [ 2dup [ special-interval? ] either? ] [ incomparable ] }
336 { [ 2dup interval-intersect empty-interval? ] [ (interval<) ] }
337 { [ 2dup left-endpoint-< ] [ f ] }
338 { [ 2dup right-endpoint-< ] [ f ] }
342 : left-endpoint-<= ( i1 i2 -- ? )
343 [ from>> ] [ to>> ] bi* endpoint= ;
345 : right-endpoint-<= ( i1 i2 -- ? )
346 [ to>> ] [ from>> ] bi* endpoint= ;
348 : interval<= ( i1 i2 -- ? )
350 { [ 2dup [ special-interval? ] either? ] [ incomparable ] }
351 { [ 2dup interval-intersect empty-interval? ] [ (interval<) ] }
352 { [ 2dup right-endpoint-<= ] [ t ] }
356 : interval> ( i1 i2 -- ? )
359 : interval>= ( i1 i2 -- ? )
362 : interval-mod ( i1 i2 -- i3 )
364 { [ over empty-interval? ] [ swap ] }
365 { [ dup empty-interval? ] [ ] }
366 { [ dup full-interval? ] [ ] }
367 [ interval-abs to>> first [ neg ] keep (a,b) ]
369 swap 0 [a,a] interval>= t eq? [ [0,inf] interval-intersect ] when ;
371 : (rem-range) ( interval -- interval' ) interval-abs to>> first [0,b) ;
373 : interval-rem ( i1 i2 -- i3 )
375 { [ over empty-interval? ] [ drop ] }
376 { [ dup empty-interval? ] [ nip ] }
377 { [ dup full-interval? ] [ 2drop [0,inf] ] }
381 : interval-nonnegative? ( interval -- ? )
384 : interval-negative? ( interval -- ? )
388 ! Return the weight of the MSB. For signed numbers, this does
389 ! not mean the sign bit.
390 : bit-weight ( n -- m )
391 dup [ -1/0. = ] [ 1/0. = ] bi or
393 [ dup 0 > [ 1 + ] [ neg ] if next-power-of-2 ] if ;
395 GENERIC: interval-bounds ( interval -- lower upper )
396 M: full-interval interval-bounds drop -1/0. 1/0. ;
397 M: interval interval-bounds interval>points [ first ] bi@ ;
399 : min-lower-bound ( i1 i2 -- n )
400 [ from>> first ] bi@ min ;
402 : max-lower-bound ( i1 i2 -- n )
403 [ from>> first ] bi@ max ;
405 : min-upper-bound ( i1 i2 -- n )
406 [ to>> first ] bi@ min ;
408 : max-upper-bound ( i1 i2 -- n )
409 [ to>> first ] bi@ max ;
411 : interval-bit-weight ( i1 -- n )
412 interval-bounds [ bit-weight ] bi@ max ;
415 : interval-bitand ( i1 i2 -- i3 )
419 [ 2dup [ interval-nonnegative? ] both? ]
420 [ min-upper-bound [0,b] ]
423 [ 2dup [ interval-nonnegative? ] either? ]
425 dup interval-nonnegative? [ nip ] [ drop ] if
430 [ min-lower-bound bit-weight neg ]
432 2dup [ interval-negative? ] both?
433 [ min-upper-bound ] [ max-upper-bound ] if
437 ] do-empty-interval ;
439 ! Basic Property of bitor: bits can never be taken away. For both signed and
440 ! unsigned integers this means that the number can only grow towards positive
441 ! infinity. Also, the significant bit range can never be larger than either of
443 ! In case both intervals are positive:
444 ! lower(i1 bitor i2) = max(lower(i1),lower(i2))
445 ! upper(i1 bitor i2) = 2 ^ max(bit-length(upper(i1)), bit-length(upper(i2))) - 1
446 ! In case both intervals are negative:
447 ! lower(i1 bitor i2) = max(lower(i1),lower(i2))
448 ! upper(i1 bitor i2) = -1
449 ! In case one is negative and the other positive, simply assume the whole
450 ! bit-range. This case is not accurate though.
451 : interval-bitor ( i1 i2 -- i3 )
453 { { [ 2dup [ interval-nonnegative? ] both? ]
454 [ [ max-lower-bound ] [ max-upper-bound ] 2bi bit-weight 1 - [a,b] ] }
455 { [ 2dup [ interval-negative? ] both? ]
456 [ max-lower-bound -1 [a,b] ] }
457 [ interval-union interval-bit-weight [ neg ] [ 1 - ] bi [a,b] ]
459 ] do-empty-interval ;
461 ! Basic Property of bitxor: can always produce 0, can never increase
463 ! If both operands are known to be negative, the sign bit(s) will be zero,
464 ! always resulting in a positive number
465 : interval-bitxor ( i1 i2 -- i3 )
467 { { [ 2dup [ interval-nonnegative? ] both? ]
468 [ max-upper-bound bit-weight 1 - [0,b] ] }
469 { [ 2dup [ interval-negative? ] both? ]
470 [ min-lower-bound bit-weight 1 - [0,b] ] }
471 [ interval-union interval-bit-weight [ neg ] [ 1 - ] bi [a,b] ]
473 ] do-empty-interval ;
475 GENERIC: interval-log2 ( i1 -- i2 )
476 M: empty-interval interval-log2 ;
477 M: full-interval interval-log2 drop [0,inf] ;
478 M: interval interval-log2
479 to>> first 1 max dup most-positive-fixnum >
480 [ drop full-interval interval-log2 ]
481 [ 1 + >integer log2 [0,b] ]
484 : assume< ( i1 i2 -- i3 )
485 dup special-interval? [ drop ] [
486 to>> first [-inf,b) interval-intersect
489 : assume<= ( i1 i2 -- i3 )
490 dup special-interval? [ drop ] [
491 to>> first [-inf,b] interval-intersect
494 : assume> ( i1 i2 -- i3 )
495 dup special-interval? [ drop ] [
496 from>> first (a,inf] interval-intersect
499 : assume>= ( i1 i2 -- i3 )
500 dup special-interval? [ drop ] [
501 from>> first [a,inf] interval-intersect
504 : integral-closure ( i1 -- i2 )
505 dup special-interval? [
506 [ from>> first2 [ 1 + ] unless ]
507 [ to>> first2 [ 1 - ] unless ]