1 ! Copyright (C) 2007, 2009 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 memoize ;
10 SINGLETON: full-interval
12 TUPLE: interval { from read-only } { to read-only } ;
14 : closed-point? ( from to -- ? )
15 2dup [ first ] bi@ number=
16 [ [ second ] both? ] [ 2drop f ] if ;
18 : <interval> ( from to -- interval )
20 { [ 2dup [ first ] bi@ > ] [ 2drop empty-interval ] }
21 { [ 2dup [ first ] bi@ number= ] [
23 [ interval boa ] [ 2drop empty-interval ] if
25 { [ 2dup [ { -1/0. t } = ] [ { 1/0. t } = ] bi* and ] [
31 : open-point ( n -- endpoint ) f 2array ;
33 : closed-point ( n -- endpoint ) t 2array ;
35 : [a,b] ( a b -- interval )
36 [ closed-point ] dip closed-point <interval> ; foldable
38 : (a,b) ( a b -- interval )
39 [ open-point ] dip open-point <interval> ; foldable
41 : [a,b) ( a b -- interval )
42 [ closed-point ] dip open-point <interval> ; foldable
44 : (a,b] ( a b -- interval )
45 [ open-point ] dip closed-point <interval> ; foldable
47 : [a,a] ( a -- interval )
48 closed-point dup <interval> ; foldable
50 : [-inf,a] ( a -- interval ) -1/0. swap [a,b] ; inline
52 : [-inf,a) ( a -- interval ) -1/0. swap [a,b) ; inline
54 : [a,inf] ( a -- interval ) 1/0. [a,b] ; inline
56 : (a,inf] ( a -- interval ) 1/0. (a,b] ; inline
58 MEMO: [0,inf] ( -- interval ) 0 [a,inf] ; foldable
60 MEMO: fixnum-interval ( -- interval )
61 most-negative-fixnum most-positive-fixnum [a,b] ; inline
63 MEMO: array-capacity-interval ( -- interval )
64 0 max-array-capacity [a,b] ; inline
66 : [-inf,inf] ( -- interval ) full-interval ; inline
68 : compare-endpoints ( p1 p2 quot -- ? )
69 [ 2dup [ first ] bi@ ] dip call [
72 2dup [ first ] bi@ number= [
79 : endpoint= ( p1 p2 -- ? )
80 [ [ first ] bi@ number= ] [ [ second ] bi@ eq? ] 2bi and ;
82 : endpoint< ( p1 p2 -- ? ) [ < ] compare-endpoints ;
84 : endpoint<= ( p1 p2 -- ? ) [ endpoint< ] [ endpoint= ] 2bi or ;
86 : endpoint> ( p1 p2 -- ? ) [ > ] compare-endpoints ;
88 : endpoint>= ( p1 p2 -- ? ) [ endpoint> ] [ endpoint= ] 2bi or ;
90 : endpoint-min ( p1 p2 -- p3 ) [ endpoint< ] most ;
92 : endpoint-max ( p1 p2 -- p3 ) [ endpoint> ] most ;
94 : interval>points ( int -- from to )
95 [ from>> ] [ to>> ] bi ;
97 : points>interval ( seq -- interval nan? )
98 [ first fp-nan? not ] partition
100 [ [ ] [ endpoint-min ] map-reduce ]
101 [ [ ] [ endpoint-max ] map-reduce ] bi
107 : nan-ok ( interval nan? -- interval ) drop ; inline
108 : nan-not-ok ( interval nan? -- interval ) [ drop full-interval ] when ; inline
110 : (interval-op) ( p1 p2 quot -- p3 )
111 [ [ first ] [ first ] [ call ] tri* ]
112 [ drop [ second ] both? ]
115 : interval-op ( i1 i2 quot -- i3 nan? )
117 [ [ from>> ] [ from>> ] [ ] tri* (interval-op) ]
118 [ [ to>> ] [ from>> ] [ ] tri* (interval-op) ]
119 [ [ to>> ] [ to>> ] [ ] tri* (interval-op) ]
120 [ [ from>> ] [ to>> ] [ ] tri* (interval-op) ]
121 } 3cleave 4array points>interval ; inline
123 : do-empty-interval ( i1 i2 quot -- i3 )
125 { [ pick empty-interval eq? ] [ 2drop ] }
126 { [ over empty-interval eq? ] [ drop nip ] }
127 { [ pick full-interval eq? ] [ 2drop ] }
128 { [ over full-interval eq? ] [ drop nip ] }
132 : interval+ ( i1 i2 -- i3 )
133 [ [ + ] interval-op nan-ok ] do-empty-interval ;
135 : interval- ( i1 i2 -- i3 )
136 [ [ - ] interval-op nan-ok ] do-empty-interval ;
138 : interval-intersect ( i1 i2 -- i3 )
140 { [ over empty-interval eq? ] [ drop ] }
141 { [ dup empty-interval eq? ] [ nip ] }
142 { [ over full-interval eq? ] [ nip ] }
143 { [ dup full-interval eq? ] [ drop ] }
145 [ interval>points ] bi@
146 [ [ swap endpoint< ] most ]
147 [ [ swap endpoint> ] most ] bi-curry* bi*
152 : intervals-intersect? ( i1 i2 -- ? )
153 interval-intersect empty-interval eq? not ;
155 : interval-union ( i1 i2 -- i3 )
157 { [ over empty-interval eq? ] [ nip ] }
158 { [ dup empty-interval eq? ] [ drop ] }
159 { [ over full-interval eq? ] [ drop ] }
160 { [ dup full-interval eq? ] [ nip ] }
161 [ [ interval>points 2array ] bi@ append points>interval nan-not-ok ]
164 : interval-subset? ( i1 i2 -- ? )
165 dupd interval-intersect = ;
167 : interval-contains? ( x int -- ? )
168 dup empty-interval eq? [ 2drop f ] [
169 dup full-interval eq? [ 2drop t ] [
170 [ from>> first2 [ >= ] [ > ] if ]
171 [ to>> first2 [ <= ] [ < ] if ]
176 : interval-zero? ( int -- ? )
177 0 swap interval-contains? ;
179 : interval* ( i1 i2 -- i3 )
180 [ [ [ * ] interval-op nan-ok ] do-empty-interval ]
181 [ [ interval-zero? ] either? ]
182 2bi [ 0 [a,a] interval-union ] when ;
184 : interval-1+ ( i1 -- i2 ) 1 [a,a] interval+ ;
186 : interval-1- ( i1 -- i2 ) -1 [a,a] interval+ ;
188 : interval-neg ( i1 -- i2 ) -1 [a,a] interval* ;
190 : interval-bitnot ( i1 -- i2 ) interval-neg interval-1- ;
192 : interval-sq ( i1 -- i2 ) dup interval* ;
194 : special-interval? ( interval -- ? )
195 { empty-interval full-interval } member-eq? ;
197 : interval-singleton? ( int -- ? )
198 dup special-interval? [
202 2dup [ second ] both?
203 [ [ first ] bi@ number= ]
207 : interval-length ( int -- n )
209 { [ dup empty-interval eq? ] [ drop 0 ] }
210 { [ dup full-interval eq? ] [ drop 1/0. ] }
211 [ interval>points [ first ] bi@ swap - ]
214 : interval-closure ( i1 -- i2 )
215 dup [ interval>points [ first ] bi@ [a,b] ] when ;
217 : interval-integer-op ( i1 i2 quot -- i3 )
219 2dup [ interval>points [ first integer? ] both? ] both?
220 ] dip [ 2drop [-inf,inf] ] if ; inline
222 : interval-shift ( i1 i2 -- i3 )
223 #! Inaccurate; could be tighter
226 [ interval-closure ] bi@
227 [ shift ] interval-op nan-not-ok
228 ] interval-integer-op
229 ] do-empty-interval ;
231 : interval-shift-safe ( i1 i2 -- i3 )
233 dup to>> first 100 > [
238 ] do-empty-interval ;
240 : interval-max ( i1 i2 -- i3 )
242 { [ over empty-interval eq? ] [ drop ] }
243 { [ dup empty-interval eq? ] [ nip ] }
244 { [ 2dup [ full-interval eq? ] both? ] [ drop ] }
245 { [ over full-interval eq? ] [ nip from>> first [a,inf] ] }
246 { [ dup full-interval eq? ] [ drop from>> first [a,inf] ] }
247 [ [ interval-closure ] bi@ [ max ] interval-op nan-not-ok ]
250 : interval-min ( i1 i2 -- i3 )
252 { [ over empty-interval eq? ] [ drop ] }
253 { [ dup empty-interval eq? ] [ nip ] }
254 { [ 2dup [ full-interval eq? ] both? ] [ drop ] }
255 { [ over full-interval eq? ] [ nip to>> first [-inf,a] ] }
256 { [ dup full-interval eq? ] [ drop to>> first [-inf,a] ] }
257 [ [ interval-closure ] bi@ [ min ] interval-op nan-not-ok ]
260 : interval-interior ( i1 -- i2 )
261 dup special-interval? [
262 interval>points [ first ] bi@ (a,b)
265 : interval-division-op ( i1 i2 quot -- i3 )
267 { [ 0 pick interval-closure interval-contains? ] [ 3drop [-inf,inf] ] }
268 { [ pick interval-zero? ] [ call 0 [a,a] interval-union ] }
272 : interval/ ( i1 i2 -- i3 )
273 [ [ [ / ] interval-op nan-not-ok ] interval-division-op ] do-empty-interval ;
275 : interval/-safe ( i1 i2 -- i3 )
276 #! Just a hack to make the compiler work if bootstrap.math
278 \ integer \ / method [ interval/ ] [ 2drop f ] if ;
280 : interval/i ( i1 i2 -- i3 )
284 [ interval-closure ] bi@
285 [ /i ] interval-op nan-not-ok
286 ] interval-integer-op
287 ] interval-division-op
288 ] do-empty-interval ;
290 : interval/f ( i1 i2 -- i3 )
291 [ [ [ /f ] interval-op nan-not-ok ] interval-division-op ] do-empty-interval ;
293 : (interval-abs) ( i1 -- i2 )
294 interval>points [ first2 [ abs ] dip 2array ] bi@ 2array ;
296 : interval-abs ( i1 -- i2 )
298 { [ dup empty-interval eq? ] [ ] }
299 { [ dup full-interval eq? ] [ drop [0,inf] ] }
300 { [ 0 over interval-contains? ] [ (interval-abs) { 0 t } suffix points>interval nan-not-ok ] }
301 [ (interval-abs) points>interval nan-not-ok ]
304 : interval-absq ( i1 -- i2 )
305 interval-abs interval-sq ;
307 : interval-recip ( i1 -- i2 ) 1 [a,a] swap interval/ ;
309 : interval-2/ ( i1 -- i2 ) -1 [a,a] interval-shift ;
313 : left-endpoint-< ( i1 i2 -- ? )
314 [ swap interval-subset? ]
315 [ nip interval-singleton? ]
316 [ [ from>> ] bi@ endpoint= ]
319 : right-endpoint-< ( i1 i2 -- ? )
321 [ drop interval-singleton? ]
322 [ [ to>> ] bi@ endpoint= ]
325 : (interval<) ( i1 i2 -- i1 i2 ? )
326 2dup [ from>> ] bi@ endpoint< ;
328 : interval< ( i1 i2 -- ? )
330 { [ 2dup [ special-interval? ] either? ] [ incomparable ] }
331 { [ 2dup interval-intersect empty-interval eq? ] [ (interval<) ] }
332 { [ 2dup left-endpoint-< ] [ f ] }
333 { [ 2dup right-endpoint-< ] [ f ] }
337 : left-endpoint-<= ( i1 i2 -- ? )
338 [ from>> ] [ to>> ] bi* endpoint= ;
340 : right-endpoint-<= ( i1 i2 -- ? )
341 [ to>> ] [ from>> ] bi* endpoint= ;
343 : interval<= ( i1 i2 -- ? )
345 { [ 2dup [ special-interval? ] either? ] [ incomparable ] }
346 { [ 2dup interval-intersect empty-interval eq? ] [ (interval<) ] }
347 { [ 2dup right-endpoint-<= ] [ t ] }
351 : interval> ( i1 i2 -- ? )
354 : interval>= ( i1 i2 -- ? )
357 : interval-mod ( i1 i2 -- i3 )
359 { [ over empty-interval eq? ] [ swap ] }
360 { [ dup empty-interval eq? ] [ ] }
361 { [ dup full-interval eq? ] [ ] }
362 [ interval-abs to>> first [ neg ] keep (a,b) ]
364 swap 0 [a,a] interval>= t eq? [ [0,inf] interval-intersect ] when ;
366 : (rem-range) ( i -- i' ) interval-abs to>> first 0 swap [a,b) ;
368 : interval-rem ( i1 i2 -- i3 )
370 { [ over empty-interval eq? ] [ drop ] }
371 { [ dup empty-interval eq? ] [ nip ] }
372 { [ dup full-interval eq? ] [ 2drop [0,inf] ] }
376 : interval-bitand-pos ( i1 i2 -- ? )
377 [ to>> first ] bi@ min 0 swap [a,b] ;
379 : interval-bitand-neg ( i1 i2 -- ? )
380 dup from>> first 0 < [ drop ] [ nip ] if
381 0 swap to>> first [a,b] ;
383 : interval-nonnegative? ( i -- ? )
386 : interval-bitand ( i1 i2 -- i3 )
391 [ 2dup [ interval-nonnegative? ] both? ]
392 [ interval-bitand-pos ]
395 [ 2dup [ interval-nonnegative? ] either? ]
396 [ interval-bitand-neg ]
400 ] do-empty-interval ;
402 : interval-bitor ( i1 i2 -- i3 )
405 2dup [ interval-nonnegative? ] both?
407 [ interval>points [ first ] bi@ ] bi@
408 4array supremum 0 swap >integer next-power-of-2 [a,b]
409 ] [ 2drop [-inf,inf] ] if
410 ] do-empty-interval ;
412 : interval-bitxor ( i1 i2 -- i3 )
416 : interval-log2 ( i1 -- i2 )
418 { empty-interval [ empty-interval ] }
419 { full-interval [ [0,inf] ] }
421 to>> first 1 max dup most-positive-fixnum >
422 [ drop full-interval interval-log2 ]
423 [ 1 + >integer log2 0 swap [a,b] ]
428 : assume< ( i1 i2 -- i3 )
429 dup special-interval? [ drop ] [
430 to>> first [-inf,a) interval-intersect
433 : assume<= ( i1 i2 -- i3 )
434 dup special-interval? [ drop ] [
435 to>> first [-inf,a] interval-intersect
438 : assume> ( i1 i2 -- i3 )
439 dup special-interval? [ drop ] [
440 from>> first (a,inf] interval-intersect
443 : assume>= ( i1 i2 -- i3 )
444 dup special-interval? [ drop ] [
445 from>> first [a,inf] interval-intersect
448 : integral-closure ( i1 -- i2 )
449 dup special-interval? [
450 [ from>> first2 [ 1 + ] unless ]
451 [ to>> first2 [ 1 - ] unless ]