]> gitweb.factorcode.org Git - factor.git/blob - basis/interval-sets/interval-sets.factor
factor: Rename start -> subseq-start, start* -> subseq-start-from.
[factor.git] / basis / interval-sets / interval-sets.factor
1 ! Copyright (C) 2009 Daniel Ehrenberg.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types arrays assocs binary-search
4 combinators fry grouping kernel locals make math math.order
5 sequences sequences.private sorting specialized-arrays ;
6 SPECIALIZED-ARRAY: uint
7 IN: interval-sets
8 ! Sets of positive integers
9
10 ! Intervals are a pair of { start end }
11 TUPLE: interval-set { array uint-array read-only } ;
12
13 <PRIVATE
14
15 ERROR: not-an-interval-set obj ;
16
17 : check-interval-set ( map -- map )
18     dup interval-set? [ not-an-interval-set ] unless ; inline
19
20 PRIVATE>
21
22 : in? ( key set -- ? )
23     check-interval-set array>>
24     dupd [ <=> ] with search swap [
25         even? [ >= ] [ 1 - <= ] if
26     ] [ 2drop f ] if* ;
27
28 <PRIVATE
29
30 : spec>pairs ( sequence -- intervals )
31     [ dup number? [ dup 2array ] when ] map ;
32
33 : disjoint? ( node1 node2 -- ? )
34     [ second-unsafe ] [ first-unsafe ] bi* < ;
35
36 : (delete-redundancies) ( seq -- )
37     dup length {
38         { 0 [ drop ] }
39         { 1 [ % ] }
40         [
41             drop dup first2 <
42             [ unclip-slice , ]
43             [ 2 tail-slice ] if
44             (delete-redundancies)
45         ]
46     } case ;
47
48 : delete-redundancies ( seq -- seq' )
49     ! If the next element is >= current one, leave out both
50     [ (delete-redundancies) ] uint-array{ } make ;
51
52 : make-intervals ( seq -- interval-set )
53     uint-array{ } like
54     delete-redundancies
55     interval-set boa ;
56
57 : >intervals ( seq -- seq' )
58     [ 1 + ] assoc-map concat ;
59
60 PRIVATE>
61
62 : <interval-set> ( specification -- interval-set )
63     spec>pairs sort-keys
64     >intervals make-intervals ;
65
66 <PRIVATE
67
68 :: or-step ( set1 set2 -- set1' set2' )
69     set1 first ,
70     set1 second set2 first <=
71     [ set1 0 ] [ set2 2 ] if
72     [ second , ] [ set2 swap tail-slice ] bi*
73     set1 2 tail-slice ;
74
75 : combine-or ( set1 set2 -- )
76     {
77         { [ over empty? ] [ % drop ] }
78         { [ dup empty? ] [ drop % ] }
79         [
80             2dup [ first ] bi@ <=
81             [ swap ] unless
82             or-step combine-or
83         ]
84     } cond ;
85
86 PRIVATE>
87
88 : <interval-or> ( set1 set2 -- set )
89     [ array>> ] bi@
90     [ combine-or ] uint-array{ } make
91     make-intervals ;
92
93 <PRIVATE
94
95 : prefix-0 ( seq -- 0seq )
96     0 over ?nth zero? [ rest ] [ 0 prefix ] if ;
97
98 : interval-max ( interval-set1 interval-set2 -- n )
99     [ array>> [ 0 ] [ last ] if-empty ] bi@ max ;
100
101 PRIVATE>
102
103 : <interval-not> ( set maximum -- set' )
104     [ array>> prefix-0 ] dip suffix make-intervals ;
105
106 : <interval-and> ( set1 set2 -- set )
107     2dup interval-max
108     [ '[ _ <interval-not> ] bi@ <interval-or> ] keep
109     <interval-not> ;