1 ! Copyright (C) 2007, 2008 Slava Pestov, Doug Coleman.
2 ! See http://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 generic layouts ;
12 TUPLE: interval { from read-only } { to read-only } ;
14 : <interval> ( from to -- interval )
16 { [ 2dup > ] [ 2drop 2drop empty-interval ] }
18 2drop 2dup [ second ] both?
19 [ interval boa ] [ 2drop empty-interval ] if
21 [ 2drop interval boa ]
24 : open-point ( n -- endpoint ) f 2array ;
26 : closed-point ( n -- endpoint ) t 2array ;
28 : [a,b] ( a b -- interval )
29 [ closed-point ] dip closed-point <interval> ; foldable
31 : (a,b) ( a b -- interval )
32 [ open-point ] dip open-point <interval> ; foldable
34 : [a,b) ( a b -- interval )
35 [ closed-point ] dip open-point <interval> ; foldable
37 : (a,b] ( a b -- interval )
38 [ open-point ] dip closed-point <interval> ; foldable
40 : [a,a] ( a -- interval )
41 closed-point dup <interval> ; foldable
43 : [-inf,a] ( a -- interval ) -1./0. swap [a,b] ; inline
45 : [-inf,a) ( a -- interval ) -1./0. swap [a,b) ; inline
47 : [a,inf] ( a -- interval ) 1./0. [a,b] ; inline
49 : (a,inf] ( a -- interval ) 1./0. (a,b] ; inline
51 : [-inf,inf] ( -- interval ) full-interval ; inline
53 : compare-endpoints ( p1 p2 quot -- ? )
54 [ 2dup [ first ] bi@ ] dip call [
57 2dup [ first ] bi@ = [
64 : endpoint< ( p1 p2 -- ? ) [ < ] compare-endpoints ;
66 : endpoint<= ( p1 p2 -- ? ) [ endpoint< ] 2keep = or ;
68 : endpoint> ( p1 p2 -- ? ) [ > ] compare-endpoints ;
70 : endpoint>= ( p1 p2 -- ? ) [ endpoint> ] 2keep = or ;
72 : endpoint-min ( p1 p2 -- p3 ) [ endpoint< ] most ;
74 : endpoint-max ( p1 p2 -- p3 ) [ endpoint> ] most ;
76 : interval>points ( int -- from to )
77 [ from>> ] [ to>> ] bi ;
79 : points>interval ( seq -- interval )
80 dup [ first fp-nan? ] any?
83 [ [ endpoint-min ] reduce ]
84 [ [ endpoint-max ] reduce ]
88 : (interval-op) ( p1 p2 quot -- p3 )
89 [ [ first ] [ first ] [ call ] tri* ]
90 [ drop [ second ] both? ]
93 : interval-op ( i1 i2 quot -- i3 )
95 [ [ from>> ] [ from>> ] [ ] tri* (interval-op) ]
96 [ [ to>> ] [ from>> ] [ ] tri* (interval-op) ]
97 [ [ to>> ] [ to>> ] [ ] tri* (interval-op) ]
98 [ [ from>> ] [ to>> ] [ ] tri* (interval-op) ]
99 } 3cleave 4array points>interval ; inline
101 : do-empty-interval ( i1 i2 quot -- i3 )
103 { [ pick empty-interval eq? ] [ 2drop ] }
104 { [ over empty-interval eq? ] [ drop nip ] }
105 { [ pick full-interval eq? ] [ 2drop ] }
106 { [ over full-interval eq? ] [ drop nip ] }
110 : interval+ ( i1 i2 -- i3 )
111 [ [ + ] interval-op ] do-empty-interval ;
113 : interval- ( i1 i2 -- i3 )
114 [ [ - ] interval-op ] do-empty-interval ;
116 : interval-intersect ( i1 i2 -- i3 )
118 { [ over empty-interval eq? ] [ drop ] }
119 { [ dup empty-interval eq? ] [ nip ] }
120 { [ over full-interval eq? ] [ nip ] }
121 { [ dup full-interval eq? ] [ drop ] }
123 [ interval>points ] bi@ swapd
124 [ [ swap endpoint< ] most ]
125 [ [ swap endpoint> ] most ] 2bi*
130 : intervals-intersect? ( i1 i2 -- ? )
131 interval-intersect empty-interval eq? not ;
133 : interval-union ( i1 i2 -- i3 )
135 { [ over empty-interval eq? ] [ nip ] }
136 { [ dup empty-interval eq? ] [ drop ] }
137 { [ over full-interval eq? ] [ drop ] }
138 { [ dup full-interval eq? ] [ nip ] }
139 [ [ interval>points 2array ] bi@ append points>interval ]
142 : interval-subset? ( i1 i2 -- ? )
143 dupd interval-intersect = ;
145 : interval-contains? ( x int -- ? )
146 dup empty-interval eq? [ 2drop f ] [
147 dup full-interval eq? [ 2drop t ] [
148 [ from>> first2 [ >= ] [ > ] if ]
149 [ to>> first2 [ <= ] [ < ] if ]
154 : interval-zero? ( int -- ? )
155 0 swap interval-contains? ;
157 : interval* ( i1 i2 -- i3 )
158 [ [ [ * ] interval-op ] do-empty-interval ]
159 [ [ interval-zero? ] either? ]
160 2bi [ 0 [a,a] interval-union ] when ;
162 : interval-1+ ( i1 -- i2 ) 1 [a,a] interval+ ;
164 : interval-1- ( i1 -- i2 ) -1 [a,a] interval+ ;
166 : interval-neg ( i1 -- i2 ) -1 [a,a] interval* ;
168 : interval-bitnot ( i1 -- i2 ) interval-neg interval-1- ;
170 : interval-sq ( i1 -- i2 ) dup interval* ;
172 : special-interval? ( interval -- ? )
173 { empty-interval full-interval } memq? ;
175 : interval-singleton? ( int -- ? )
176 dup special-interval? [
180 2dup [ second ] both?
185 : interval-length ( int -- n )
187 { [ dup empty-interval eq? ] [ drop 0 ] }
188 { [ dup full-interval eq? ] [ drop 1/0. ] }
189 [ interval>points [ first ] bi@ swap - ]
192 : interval-closure ( i1 -- i2 )
193 dup [ interval>points [ first ] bi@ [a,b] ] when ;
195 : interval-integer-op ( i1 i2 quot -- i3 )
197 2dup [ interval>points [ first integer? ] both? ] both?
198 ] dip [ 2drop [-inf,inf] ] if ; inline
200 : interval-shift ( i1 i2 -- i3 )
201 #! Inaccurate; could be tighter
204 [ interval-closure ] bi@
205 [ shift ] interval-op
206 ] interval-integer-op
207 ] do-empty-interval ;
209 : interval-shift-safe ( i1 i2 -- i3 )
211 dup to>> first 100 > [
216 ] do-empty-interval ;
218 : interval-max ( i1 i2 -- i3 )
219 #! Inaccurate; could be tighter
220 [ [ interval-closure ] bi@ [ max ] interval-op ] do-empty-interval ;
222 : interval-min ( i1 i2 -- i3 )
223 #! Inaccurate; could be tighter
224 [ [ interval-closure ] bi@ [ min ] interval-op ] do-empty-interval ;
226 : interval-interior ( i1 -- i2 )
227 dup special-interval? [
228 interval>points [ first ] bi@ (a,b)
231 : interval-division-op ( i1 i2 quot -- i3 )
233 { [ 0 pick interval-closure interval-contains? ] [ 3drop [-inf,inf] ] }
234 { [ pick interval-zero? ] [ call 0 [a,a] interval-union ] }
238 : interval/ ( i1 i2 -- i3 )
239 [ [ [ / ] interval-op ] interval-division-op ] do-empty-interval ;
241 : interval/-safe ( i1 i2 -- i3 )
242 #! Just a hack to make the compiler work if bootstrap.math
244 \ integer \ / method [ interval/ ] [ 2drop f ] if ;
246 : interval/i ( i1 i2 -- i3 )
250 [ interval-closure ] bi@
252 ] interval-integer-op
253 ] interval-division-op
254 ] do-empty-interval ;
256 : interval/f ( i1 i2 -- i3 )
257 [ [ [ /f ] interval-op ] interval-division-op ] do-empty-interval ;
259 : (interval-abs) ( i1 -- i2 )
260 interval>points [ first2 [ abs ] dip 2array ] bi@ 2array ;
262 : interval-abs ( i1 -- i2 )
264 { [ dup empty-interval eq? ] [ ] }
265 { [ dup full-interval eq? ] [ drop 0 [a,inf] ] }
266 { [ 0 over interval-contains? ] [ (interval-abs) { 0 t } suffix points>interval ] }
267 [ (interval-abs) points>interval ]
270 : interval-mod ( i1 i2 -- i3 )
274 nip interval-abs to>> first [ neg ] keep (a,b)
275 ] interval-division-op
276 ] do-empty-interval ;
278 : interval-rem ( i1 i2 -- i3 )
282 nip interval-abs to>> first 0 swap [a,b)
283 ] interval-division-op
284 ] do-empty-interval ;
286 : interval-recip ( i1 -- i2 ) 1 [a,a] swap interval/ ;
288 : interval-2/ ( i1 -- i2 ) -1 [a,a] interval-shift ;
292 : left-endpoint-< ( i1 i2 -- ? )
293 [ swap interval-subset? ]
294 [ nip interval-singleton? ]
298 : right-endpoint-< ( i1 i2 -- ? )
300 [ drop interval-singleton? ]
304 : (interval<) ( i1 i2 -- i1 i2 ? )
305 2dup [ from>> ] bi@ endpoint< ;
307 : interval< ( i1 i2 -- ? )
309 { [ 2dup [ special-interval? ] either? ] [ incomparable ] }
310 { [ 2dup interval-intersect empty-interval eq? ] [ (interval<) ] }
311 { [ 2dup left-endpoint-< ] [ f ] }
312 { [ 2dup right-endpoint-< ] [ f ] }
316 : left-endpoint-<= ( i1 i2 -- ? )
317 [ from>> ] dip to>> = ;
319 : right-endpoint-<= ( i1 i2 -- ? )
320 [ to>> ] dip from>> = ;
322 : interval<= ( i1 i2 -- ? )
324 { [ 2dup [ special-interval? ] either? ] [ incomparable ] }
325 { [ 2dup interval-intersect empty-interval eq? ] [ (interval<) ] }
326 { [ 2dup right-endpoint-<= ] [ t ] }
330 : interval> ( i1 i2 -- ? )
333 : interval>= ( i1 i2 -- ? )
336 : interval-bitand-pos ( i1 i2 -- ? )
337 [ to>> first ] bi@ min 0 swap [a,b] ;
339 : interval-bitand-neg ( i1 i2 -- ? )
340 dup from>> first 0 < [ drop ] [ nip ] if
341 0 swap to>> first [a,b] ;
343 : interval-nonnegative? ( i -- ? )
346 : interval-bitand ( i1 i2 -- i3 )
351 [ 2dup [ interval-nonnegative? ] both? ]
352 [ interval-bitand-pos ]
355 [ 2dup [ interval-nonnegative? ] either? ]
356 [ interval-bitand-neg ]
360 ] do-empty-interval ;
362 : interval-bitor ( i1 i2 -- i3 )
365 2dup [ interval-nonnegative? ] both?
367 [ interval>points [ first ] bi@ ] bi@
368 4array supremum 0 swap >integer next-power-of-2 [a,b]
369 ] [ 2drop [-inf,inf] ] if
370 ] do-empty-interval ;
372 : interval-bitxor ( i1 i2 -- i3 )
376 : interval-log2 ( i1 -- i2 )
378 { empty-interval [ empty-interval ] }
379 { full-interval [ 0 [a,inf] ] }
381 to>> first 1 max dup most-positive-fixnum >
382 [ drop full-interval interval-log2 ]
383 [ 1+ >integer log2 0 swap [a,b] ]
388 : assume< ( i1 i2 -- i3 )
389 dup special-interval? [ drop ] [
390 to>> first [-inf,a) interval-intersect
393 : assume<= ( i1 i2 -- i3 )
394 dup special-interval? [ drop ] [
395 to>> first [-inf,a] interval-intersect
398 : assume> ( i1 i2 -- i3 )
399 dup special-interval? [ drop ] [
400 from>> first (a,inf] interval-intersect
403 : assume>= ( i1 i2 -- i3 )
404 dup special-interval? [ drop ] [
405 from>> first [a,inf] interval-intersect
408 : integral-closure ( i1 -- i2 )
409 dup special-interval? [
410 [ from>> first2 [ 1+ ] unless ]
411 [ to>> first2 [ 1- ] unless ]