1 ! Copyright (C) 2007 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 ! Based on Slate's src/unfinished/interval.slate by Brian Rice.
4 USING: kernel sequences arrays math combinators math.order ;
7 TUPLE: interval from to ;
11 : open-point ( n -- endpoint ) f 2array ;
13 : closed-point ( n -- endpoint ) t 2array ;
15 : [a,b] ( a b -- interval )
16 >r closed-point r> closed-point <interval> ;
18 : (a,b) ( a b -- interval )
19 >r open-point r> open-point <interval> ;
21 : [a,b) ( a b -- interval )
22 >r closed-point r> open-point <interval> ;
24 : (a,b] ( a b -- interval )
25 >r open-point r> closed-point <interval> ;
27 : [a,a] ( a -- interval ) closed-point dup <interval> ;
29 : [-inf,a] ( a -- interval ) -1./0. swap [a,b] ;
31 : [-inf,a) ( a -- interval ) -1./0. swap [a,b) ;
33 : [a,inf] ( a -- interval ) 1./0. [a,b] ;
35 : (a,inf] ( a -- interval ) 1./0. (a,b] ;
37 : compare-endpoints ( p1 p2 quot -- ? )
38 >r over first over first r> call [
41 over first over first = [
42 swap second swap second not or
48 : endpoint< ( p1 p2 -- ? ) [ < ] compare-endpoints ;
50 : endpoint<= ( p1 p2 -- ? ) [ endpoint< ] 2keep = or ;
52 : endpoint> ( p1 p2 -- ? ) [ > ] compare-endpoints ;
54 : endpoint>= ( p1 p2 -- ? ) [ endpoint> ] 2keep = or ;
56 : endpoint-min ( p1 p2 -- p3 ) [ endpoint< ] most ;
58 : endpoint-max ( p1 p2 -- p3 ) [ endpoint> ] most ;
60 : interval>points ( int -- from to )
61 dup interval-from swap interval-to ;
63 : points>interval ( seq -- interval )
65 [ [ endpoint-min ] reduce ] 2keep
66 [ endpoint-max ] reduce <interval> ;
68 : (interval-op) ( p1 p2 quot -- p3 )
70 >r [ first ] bi@ r> call
71 r> r> [ second ] both? 2array ; inline
73 : interval-op ( i1 i2 quot -- i3 )
74 pick interval-from pick interval-from pick (interval-op) >r
75 pick interval-to pick interval-from pick (interval-op) >r
76 pick interval-to pick interval-to pick (interval-op) >r
77 pick interval-from pick interval-to pick (interval-op) >r
78 3drop r> r> r> r> 4array points>interval ; inline
80 : interval+ ( i1 i2 -- i3 ) [ + ] interval-op ;
82 : interval- ( i1 i2 -- i3 ) [ - ] interval-op ;
84 : interval* ( i1 i2 -- i3 ) [ * ] interval-op ;
86 : interval-integer-op ( i1 i2 quot -- i3 )
88 [ interval>points [ first integer? ] both? ] both?
89 r> [ 2drop f ] if ; inline
91 : interval-1+ ( i1 -- i2 ) 1 [a,a] interval+ ;
93 : interval-1- ( i1 -- i2 ) -1 [a,a] interval+ ;
95 : interval-neg ( i1 -- i2 ) -1 [a,a] interval* ;
97 : interval-bitnot ( i1 -- i2 ) interval-neg interval-1- ;
99 : interval-sq ( i1 -- i2 ) dup interval* ;
101 : make-interval ( from to -- int )
102 over first over first {
103 { [ 2dup > ] [ 2drop 2drop f ] }
105 2drop over second over second and
106 [ <interval> ] [ 2drop f ] if
111 : interval-intersect ( i1 i2 -- i3 )
113 [ interval>points ] bi@ swapd
114 [ swap endpoint> ] most
115 >r [ swap endpoint< ] most r>
121 : interval-union ( i1 i2 -- i3 )
123 [ interval>points 2array ] bi@ append points>interval
128 : interval-subset? ( i1 i2 -- ? )
129 dupd interval-intersect = ;
131 : interval-contains? ( x int -- ? )
132 >r [a,a] r> interval-subset? ;
134 : interval-singleton? ( int -- ? )
136 2dup [ second ] bi@ and
140 : interval-length ( int -- n )
142 [ interval>points [ first ] bi@ swap - ]
145 : interval-closure ( i1 -- i2 )
146 dup [ interval>points [ first ] bi@ [a,b] ] when ;
148 : interval-shift ( i1 i2 -- i3 )
149 #! Inaccurate; could be tighter
150 [ [ shift ] interval-op ] interval-integer-op interval-closure ;
152 : interval-shift-safe ( i1 i2 -- i3 )
153 dup interval-to first 100 > [
159 : interval-max ( i1 i2 -- i3 )
160 #! Inaccurate; could be tighter
161 [ max ] interval-op interval-closure ;
163 : interval-min ( i1 i2 -- i3 )
164 #! Inaccurate; could be tighter
165 [ min ] interval-op interval-closure ;
167 : interval-interior ( i1 -- i2 )
168 interval>points [ first ] bi@ (a,b) ;
170 : interval-division-op ( i1 i2 quot -- i3 )
171 >r 0 over interval-closure interval-contains?
172 [ 2drop f ] r> if ; inline
174 : interval/ ( i1 i2 -- i3 )
175 [ [ / ] interval-op ] interval-division-op ;
177 : interval/i ( i1 i2 -- i3 )
179 [ [ /i ] interval-op ] interval-integer-op
180 ] interval-division-op interval-closure ;
182 : interval-recip ( i1 -- i2 ) 1 [a,a] swap interval/ ;
184 : interval-2/ ( i1 -- i2 ) -1 [a,a] interval-shift ;
188 : left-endpoint-< ( i1 i2 -- ? )
189 [ swap interval-subset? ] 2keep
190 [ nip interval-singleton? ] 2keep
191 [ interval-from ] bi@ =
194 : right-endpoint-< ( i1 i2 -- ? )
195 [ interval-subset? ] 2keep
196 [ drop interval-singleton? ] 2keep
197 [ interval-to ] bi@ =
200 : (interval<) ( i1 i2 -- i1 i2 ? )
201 over interval-from over interval-from endpoint< ;
203 : interval< ( i1 i2 -- ? )
205 { [ 2dup interval-intersect not ] [ (interval<) ] }
206 { [ 2dup left-endpoint-< ] [ f ] }
207 { [ 2dup right-endpoint-< ] [ f ] }
211 : left-endpoint-<= ( i1 i2 -- ? )
212 >r interval-from r> interval-to = ;
214 : right-endpoint-<= ( i1 i2 -- ? )
215 >r interval-to r> interval-from = ;
217 : interval<= ( i1 i2 -- ? )
219 { [ 2dup interval-intersect not ] [ (interval<) ] }
220 { [ 2dup right-endpoint-<= ] [ t ] }
224 : interval> ( i1 i2 -- ? )
227 : interval>= ( i1 i2 -- ? )
230 : assume< ( i1 i2 -- i3 )
231 interval-to first [-inf,a) interval-intersect ;
233 : assume<= ( i1 i2 -- i3 )
234 interval-to first [-inf,a] interval-intersect ;
236 : assume> ( i1 i2 -- i3 )
237 interval-from first (a,inf] interval-intersect ;
239 : assume>= ( i1 i2 -- i3 )
240 interval-to first [a,inf] interval-intersect ;
242 : integral-closure ( i1 -- i2 )
243 dup interval-from first2 [ 1+ ] unless
244 swap interval-to first2 [ 1- ] unless