1 ! Copyright (C) 2007 Robbert van Dalen.
2 ! See http://factorcode.org/license.txt for BSD license.
6 USING: generic kernel math math.functions sequences
7 isequences.interface shuffle ;
10 "index out of bounds" throw ; foldable
12 : traversal-error ( -- * )
13 "traversal error" throw ; foldable
15 : to-sequence ( s -- s )
17 [ -- to-sequence reverse ]
18 [ dup [ swap i-at ] swap add* swap i-length swap map ]
21 : neg? ( s -- ? ) i-length 0 < ; foldable
23 : is-atom? ( seq -- ? )
29 : 2size ( s1 s2 -- s1 s2 size1 size2 )
30 2dup [ i-length ] 2apply ; inline
32 : rindex ( s n -- s n )
33 swap dup i-length rot - ; inline
35 : left-right ( s -- left right )
36 [ ileft ] keep iright ; inline
39 i-length swap dup ileft dup i-length roll 2dup <=
40 [ swap - rot iright swap ]
44 : (ihead2) ( s i -- h )
45 swap dup ileft dup i-length roll 2dup =
47 [ 2dup < [ swap - rot iright swap ihead ++ ] [ nip ihead nip ] if ]
50 : (ihead) ( s i -- h )
51 dup pick i-length = [ drop ] [ (ihead2) ] if ; inline
53 : (itail3) ( s i -- h )
54 swap left-right swap dup i-length roll 2dup =
56 [ 2dup < [ swap - nip itail ] [ nip itail swap ++ ] if ]
59 : (itail2) ( s sl i -- t )
60 tuck = [ 2drop 0 ] [ (itail3) ] if ; inline
62 : (itail) ( s i -- t )
63 over i-length dup >r 1 =
64 [ r> drop 1 = [ drop 0 ] when ] [ r> swap (itail2) ] if ;
67 : PRIME1 ( -- prime1 ) HEX: 58ea12c9 ; foldable
68 : PRIME2 ( -- prime2 ) HEX: 79af7bc3 ; foldable
70 : hh ( fixnum-h -- fixnum-h )
71 PRIME1 * PRIME2 + >fixnum ; inline
73 : quick-hash ( fixnum-h1 fixnum-h2 -- fixnum-h )
74 [ hh ] 2apply bitxor hh ; inline
77 left-right [ $$ ] 2apply quick-hash ; inline
79 : (ig1) ( s1 s2 -- s )
81 [ dup >r ileft ipair r> iright r> ++ ipair ]
82 [ r> ++ ipair ] if ; inline
84 : (ig2) ( s1 s2 -- s )
86 [ >r dup >r ileft ++ r> iright r> ipair ipair ]
87 [ >r ++ r> ipair ] if ; inline
89 : (ig3) ( s1 s2 size1 size2 -- s )
92 [ swap twice >= [ (ig2) ] [ ipair ] if ] if ; inline
94 : ++g++ ( s1 s2 -- s )
95 dup i-length dup zero?
97 [ pick i-length dup zero? [ 2drop nip ] [ swap (ig3) ] if ] if ; inline
99 : ++g+- ( s1 s2 -- s )
101 [ neg swap -- swap rindex itail -- nip ]
105 : ++g-+ ( s1 s2 -- s )
107 [ nip swap -- swap neg ihead -- ]
111 : ++g-- ( s1 s2 -- s )
112 -- swap -- swap ++ -- ; inline
116 [ [ ++g-- ] [ ++g+- ] if ] [ [ ++g-+ ] [ ++g++ ] if ] if ;
119 ! #### lazy negative isequence ####
121 TUPLE: ineg sequence ;
123 M: ineg -- ineg-sequence ;
124 M: ineg i-length ineg-sequence i-length neg ;
125 M: ineg i-at i-length dup 0 <= [ neg swap -- swap i-at ] [ index-error ] if ;
126 M: ineg ileft -- iright -- ;
127 M: ineg iright -- ileft -- ;
128 M: ineg ihead [ -- ] 2apply ihead -- ;
129 M: ineg itail [ -- ] 2apply itail -- ;
130 M: ineg $$ ineg-sequence $$ neg ;
132 TUPLE: irev sequence ;
135 dup i-length 1 > [ <irev> ] when ; inline
137 M: irev i-at swap irev-sequence swap i-length over i-length - 1+ neg i-at ;
138 M: irev i-length irev-sequence i-length ;
139 M: irev ileft irev-sequence iright `` ;
140 M: irev iright irev-sequence ileft `` ;
141 M: irev ihead >r irev-sequence r> rindex itail `` ;
142 M: irev itail >r irev-sequence r> rindex ihead `` ;
143 M: irev $$ irev-sequence neg hh ;
145 M: irev descending? irev-sequence ascending? ;
146 M: irev ascending? irev-sequence descending? ;
148 M: object `` <i-rev> ;
149 M: ineg `` -- `` -- ;
151 M: irev `` irev-sequence ;
153 ! #### composite isequence (size-balanced binary tree) ####
155 TUPLE: ibranch left right size ;
157 : <isequence> ( s1 s2 -- s )
158 2size + <ibranch> ; inline
160 M: ibranch i-length ibranch-size ;
161 M: ibranch i-at (i-at) ;
162 M: ibranch iright ibranch-right ;
163 M: ibranch ileft ibranch-left ;
164 M: ibranch ihead (ihead) ;
165 M: ibranch itail (itail) ;
169 ! #### object isequence ####
171 GENERIC: object/++ ( s1 s2 -- s )
172 GENERIC: object/ipair ( s1 s2 -- s )
174 M: object object/++ swap ++g ;
175 M: object object/ipair swap <isequence> ;
176 M: object ++ swap object/++ ;
177 M: object ipair swap object/ipair ;
179 M: object i-length drop 1 ;
180 M: object -- <ineg> ;
181 M: object i-at i-length zero? [ index-error ] unless ;
182 M: object ileft drop 0 ;
183 M: object iright drop 0 ;
184 M: object ihead dup zero? [ 2drop 0 ] [ 1 = [ index-error ] unless ] if ;
185 M: object itail dup zero? [ drop ] [ 1 = [ drop 0 ] [ index-error ] if ] if ;
188 ! #### single element isequence ####
192 : <i> ( v -- s ) <ileaf> ; inline
194 M: ileaf i-at i-length zero? [ ileaf-value ] [ index-error ] if ;
195 M: ileaf $$ 0 i-at $$ ;
198 ! #### integer isequence ####
201 GENERIC: integer/++ ( s1 s2 -- v )
202 M: object integer/++ object/++ ;
203 M: integer ++ swap integer/++ ;
205 GENERIC: integer/ipair ( s1 s2 -- s )
206 M: object integer/ipair swap <isequence> ;
207 M: integer ipair swap integer/ipair ;
209 M: integer integer/++ + ;
210 M: integer integer/ipair + ;
212 M: integer i-length ;
214 M: integer i-at i-length dup 0 >= [ > [ 0 ] [ index-error ] if ] [ index-error ] if ;
216 dup zero? [ traversal-error ] [ 2/ ] if ;
218 dup zero? [ traversal-error ] [ 1+ 2/ ] if ;
219 M: integer ihead swap drop ;
221 M: integer $$ >fixnum ;
224 ! #### negative integers ####
226 PREDICATE: integer ninteger 0 < ;
228 M: ninteger i-at i-length dup 0 <= [ < [ 0 ] [ index-error ] if ] [ index-error ] if ;
231 ! #### sequence -> isequence ####
234 : chk-index dup zero? [ traversal-error ] [ 2/ ] if ; inline
236 M: sequence i-length length ;
237 M: sequence i-at i-length swap nth ;
238 M: sequence ileft dup length chk-index head ;
239 M: sequence iright dup length chk-index tail ;
240 M: sequence ihead head ;
241 M: sequence itail tail ;
242 M: sequence $$ [ $$ ] map unclip [ quick-hash ] reduce ;
245 ! #### (natural) compare/ordering ####
249 : (i-eq4?) ( s1 s2 -- ? )
250 2dup [ is-atom? ] 2apply
251 [ [ = ] [ 2drop f ] if ]
252 [ [ 2drop f ] [ [ 0 i-at ] 2apply (i-eq?) ] if ] if ;
254 : (i-eq3?) ( s1 s2 -- ? )
255 dup ileft pick over i-length tuck ihead rot (i-eq?)
256 [ itail swap iright swap (i-eq?) ]
260 : (i-eq2?) ( s1 s2 sl -- ? )
261 dup zero? [ 3drop 0 ]
262 [ 1 = [ (i-eq4?) ] [ (i-eq3?) ] if ]
265 : (i-eq?) ( s1 s2 -- ? )
267 [ 2dup [ i-length ] 2apply tuck = [ (i-eq2?) ] [ 3drop f ] if ]
270 : (i-cmp5) ( s1 s2 -- i )
271 dup ileft pick over i-length tuck ihead rot i-cmp dup zero?
272 [ drop itail swap iright swap i-cmp ]
273 [ -roll 3drop ] if ; inline
275 : (i-cmp4) ( s1 s2 s -- i )
276 dup zero? [ 3drop 0 ]
277 [ 1 = [ [ 0 i-at ] 2apply i-cmp ] [ (i-cmp5) ] if ]
280 : (i-cmp3) ( s1 s2 ls1 ls2 -- i )
281 2dup = [ drop (i-cmp4) ]
282 [ min dup >r ihead r> (i-cmp4) dup zero? [ drop -1 ] when ]
285 : (i-cmp2) ( s1 s2 ls1 ls2 -- i )
286 2dup > [ swap 2swap swap 2swap (i-cmp2) neg ] [ (i-cmp3) ] if ; inline
288 : cmp-g++ ( s1 s2 -- i )
289 2dup (i-eq?) [ 2drop 0 ]
290 [ 2dup [ i-length ] 2apply (i-cmp2) ] if ; inline
292 : cmp-g-- ( s1 s2 -- i )
293 [ -- ] 2apply swap cmp-g++ ; inline
295 : cmp-g+- ( s1 s2 -- i ) 2drop 1 ; inline
297 : cmp-g-+ ( s1 s2 -- i ) 2drop -1 ; inline
299 : cmp-gg ( s1 s2 -- i )
300 2dup [ neg? ] 2apply [ [ cmp-g-- ] [ cmp-g+- ] if ]
301 [ [ cmp-g-+ ] [ cmp-g++ ] if ] if ;
304 GENERIC: object/i-cmp ( s2 s1 -- s )
305 M: object object/i-cmp swap cmp-gg ;
306 M: object i-cmp swap object/i-cmp ;
309 dup i-length 1 = [ 0 i-at ] [ ileft ifirst ] if ; inline
312 dup i-length 1 = [ 0 i-at ] [ iright ilast ] if ; inline
314 : (ascending2?) ( s1 s2 -- ? )
315 ifirst swap ilast i-cmp 0 >= ;
317 : (ascending?) ( s -- ? )
320 [ left-right 2dup [ ascending? ] both? [ (ascending2?) ] [ 2drop f ] if ]
323 : (descending2?) ( s1 s2 -- ? )
324 ifirst swap ilast i-cmp 0 <= ;
326 : (descending?) ( s -- ? )
329 [ left-right 2dup [ descending? ] both? [ (descending2?) ] [ 2drop f ] if ]
332 M: object ascending? (ascending?) ;
333 M: object descending? (descending?) ;
334 M: integer ascending? drop t ;
335 M: integer descending? drop t ;
338 ! **** dual-sided isequences ****
341 TUPLE: iturned sequence ;
342 TUPLE: iright-sided value ;
343 TUPLE: idual-sided left right ;
345 M: iturned i-length iturned-sequence i-length ;
346 M: iturned i-at >r iturned-sequence r> i-at :v: ;
347 M: iturned ileft iturned-sequence ileft <iturned> ;
348 M: iturned iright iturned-sequence iright <iturned> ;
349 M: iturned ihead >r iturned-sequence r> ihead <iturned> ;
350 M: iturned itail >r iturned-sequence r> itail <iturned> ;
351 M: iturned $$ iturned-sequence dup -- [ $$ ] 2apply quick-hash ;
353 : <i-right-sided> ( v -- lv )
354 dup i-length zero? [ drop 0 ] [ <iright-sided> ] if ; inline
356 : <i-dual-sided> ( v1 v2 -- dv )
357 2dup [ i-length ] 2apply zero?
358 [ zero? [ 2drop 0 ] [ drop ] if ]
359 [ zero? [ nip <i-right-sided> ] [ <idual-sided> ] if ]
362 : i-cmp-left-right ( s1 s2 -- i )
363 2dup [ left-side ] 2apply i-cmp dup zero?
364 [ drop [ right-side ] 2apply i-cmp ]
369 dup i-length 0 < [ -- <iturned> -- ] [ <iturned> ] if ; inline
372 M: iturned :: iturned-sequence ;
375 GENERIC: iright-sided/i-cmp ( s1 s2 -- i )
376 GENERIC: idual-sided/i-cmp ( s1 s2 -- i )
378 M: object iright-sided/i-cmp swap i-cmp-left-right ;
379 M: object idual-sided/i-cmp swap i-cmp-left-right ;
380 M: iright-sided object/i-cmp swap i-cmp-left-right ;
381 M: idual-sided object/i-cmp swap i-cmp-left-right ;
382 M: iright-sided i-cmp swap iright-sided/i-cmp ;
383 M: idual-sided i-cmp swap idual-sided/i-cmp ;
386 M: object left-side ;
387 M: object right-side drop 0 ;
388 M: iright-sided left-side drop 0 ;
389 M: iright-sided right-side iright-sided-value ;
390 M: idual-sided left-side idual-sided-left ;
391 M: idual-sided right-side idual-sided-right ;
392 M: object :v: <i-right-sided> ;
393 M: idual-sided :v: dup idual-sided-right swap idual-sided-left <i-dual-sided> ;
394 M: iright-sided :v: iright-sided-value ;
396 : dual++ ( v2 v1 -- v ) swap 0 <i-dual-sided> ++ ; inline
398 M: iright-sided object/++ iright-sided-value swap <i-dual-sided> ;
399 M: idual-sided object/++ dual++ ;
400 M: iright-sided integer/++ iright-sided-value swap <i-dual-sided> ;
401 M: idual-sided integer/++ dual++ ;
403 GENERIC: iright-sided/++ ( s1 s2 -- s )
404 GENERIC: idual-sided/++ ( s1 s2 -- s )
406 M: iright-sided idual-sided/++
407 swap dup idual-sided-left swap idual-sided-right
408 rot iright-sided-value ++ <i-dual-sided> ;
410 M: iright-sided iright-sided/++
411 swap [ iright-sided-value ] 2apply ++ <i-right-sided> ;
413 M: idual-sided iright-sided/++
414 dup idual-sided-left swap idual-sided-right
415 rot iright-sided-value swap ++ <i-dual-sided> ;
417 M: idual-sided idual-sided/++
418 swap 2dup [ idual-sided-left ] 2apply ++
419 >r [ idual-sided-right ] 2apply ++ r> <i-dual-sided> ;
421 M: iright-sided ++ swap iright-sided/++ ;
422 M: idual-sided ++ swap idual-sided/++ ;
424 M: object iright-sided/++
425 >r iright-sided-value r> swap <i-dual-sided> ;
426 M: object idual-sided/++
427 >r dup idual-sided-left swap idual-sided-right r> ++ <i-dual-sided> ;
430 ! **** lazy left product of an isequence ****
433 TUPLE: imul sequence multiplier ;
435 : <i-muls> ( seq mul -- imul ) <imul> ; foldable
437 : *_g++ ( s n -- s ) i-length dup zero? [ nip ] [ <i-muls> ] if ; inline
439 : *_g+- ( s n -- s ) -- *_ ; inline
441 : *_g-+ ( s n -- s ) swap -- swap *_ -- ; inline
443 : *_g-- ( s n -- s ) [ -- ] 2apply *_ ; inline
446 : imul-unpack ( imul -- m s )
447 dup imul-multiplier swap imul-sequence ; inline
449 : imul-ileft ( imul -- imul )
450 imul-unpack dup i-length 1 =
455 : imul-iright ( imul -- imul )
456 imul-unpack dup i-length 1 =
461 : check-bounds ( s i -- s i )
462 2dup swap i-length >= [ index-error ] when ; inline
464 : imul-i-at ( imul i -- v )
465 i-length check-bounds swap dup imul-multiplier swap imul-sequence
466 -rot /i i-at ; inline
469 2dup [ neg? ] 2apply [ [ *_g-- ] [ *_g+- ] if ]
470 [ [ *_g-+ ] [ *_g++ ] if ] if ; inline
474 M: integer *_ i-length abs * ;
475 M: imul i-at imul-i-at ;
476 M: imul i-length imul-unpack i-length swap * ;
477 M: imul ileft imul-ileft ;
478 M: imul iright imul-iright ;
479 M: imul ihead (ihead) ;
480 M: imul itail (itail) ;
481 M: imul $$ imul-unpack [ $$ 2/ ] 2apply quick-hash ;
483 M: imul ascending? imul-sequence ascending? ;
484 M: imul descending? imul-sequence descending? ;
487 ! **** sort, union, intersect and diff ****
492 : (ifind3) ( s1 v s e -- i )
493 2dup >r >r + 2/ pick swap i-at over i-cmp 0 <
494 [ r> r> swap over + 1+ 2/ swap (ifind2) ]
495 [ r> r> over + 2/ (ifind2) ]
498 : (ifind2) ( s1 v s e -- i )
499 2dup = [ -roll 3drop ] [ (ifind3) ] if ; inline
501 : ifind ( s1 v -- i )
502 over i-length 0 swap (ifind2) ; inline
504 : icontains? ( s1 v -- ? )
505 2dup ifind pick i-length dupd <
506 [ rot swap i-at i-cmp zero? ] [ 3drop f ] if ; inline
508 : icut ( s v -- s2 s2 )
509 dupd ifind 2dup ihead -rot itail ; inline
513 : (union6) ( s1 s2 -- s )
514 2dup [ 0 i-at ] 2apply i-cmp 0 >
515 [ swap ] when ++ ; inline
517 : (union5) ( s1 s2 -- s )
518 over ileft i-length pick swap i-at icut rot left-right
519 swap roll (union) -rot swap (union) ++ ;
521 : (union4) ( s1 s2 -- s )
522 2dup ifirst swap ilast i-cmp 0 >= [ ++ ] [ (union5) ] if ; inline
524 : (union3) ( s1 s2 ls1 ls2 -- s )
526 [ 1 = [ (union6) ] [ (union4) ] if ]
527 [ 1 = [ swap ] when (union4) ] if ; inline
529 : (union2) ( s1 s2 -- s )
530 2dup [ i-length ] 2apply 2dup zero?
531 [ 3drop drop ] [ zero? [ 2drop nip ] [ (union3) ] if ] if ; inline
533 : (union) ( s1 s2 -- s )
534 2dup eq? [ drop 2 *_ ] [ (union2) ] if ; inline
538 : (i-sort) ( s -- s )
540 [ left-right [ i-sort ] 2apply (union) ]
545 : (diff7) ( s1 s2 -- s )
546 dupd swap 0 i-at icontains? [ drop 0 ] when ; inline
548 : (diff6) ( s1 s2 -- s )
549 2dup [ 0 i-at ] 2apply i-cmp zero?
550 [ 2drop 0 ] [ drop ] if ; inline
552 : (diff5) ( s1 s2 -- s )
553 over ileft i-length pick swap i-at icut rot left-right
554 swap roll (diff) -rot swap (diff) ++ ; inline
556 : (diff4) ( s1 s2 -- s )
557 2dup [ i-length ] 2apply 1 =
558 [ 1 = [ (diff6) ] [ (diff5) ] if ]
559 [ 1 = [ (diff7) ] [ (diff5) ] if ] if ; inline
561 : (diff3) ( s1 s2 -- s )
562 2dup ifirst swap ilast i-cmp 0 >
563 [ drop ] [ (diff4) ] if ; inline
565 : (diff2) ( s1 s2 -- s )
566 2dup [ i-length zero? ] either?
567 [ drop ] [ (diff3) ] if ; inline
569 : (diff) ( s1 s2 -- s )
570 2dup eq? [ 2drop 0 ] [ (diff2) ] if ; inline
573 ! **** sort, diff, union and intersect assumes positive isequences ****
576 dup ascending? [ dup descending? [ `` ] [ (i-sort) ] if ] unless ;
578 : i-diff ( s1 s2 -- s )
579 [ i-sort ] 2apply (diff) ; inline
581 : i-union ( s1 s2 -- s )
582 [ i-sort ] 2apply (union) ; inline
584 : i-intersect ( s1 s2 -- s )
585 [ i-sort ] 2apply over -rot i-diff i-diff ;