2010-07-14 12:09:57 -04:00
|
|
|
! Copyright (c) 2007-2010 Slava Pestov, Doug Coleman, Aaron Schaefer, John Benediktsson.
|
2008-01-27 20:00:31 -05:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2010-07-26 11:12:36 -04:00
|
|
|
|
2012-04-23 11:29:20 -04:00
|
|
|
USING: accessors arrays assocs binary-search classes.tuple fry
|
|
|
|
kernel locals math math.order math.ranges namespaces sequences
|
|
|
|
sequences.private sorting ;
|
2010-07-26 11:12:36 -04:00
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
IN: math.combinatorics
|
|
|
|
|
2008-01-27 20:00:31 -05:00
|
|
|
<PRIVATE
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-27 20:00:31 -05:00
|
|
|
: possible? ( n m -- ? )
|
|
|
|
0 rot between? ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-27 20:00:31 -05:00
|
|
|
: twiddle ( n k -- n k )
|
|
|
|
2dup - dupd > [ dupd - ] when ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2009-05-05 22:43:07 -04:00
|
|
|
PRIVATE>
|
|
|
|
|
|
|
|
: factorial ( n -- n! )
|
2010-01-14 10:10:13 -05:00
|
|
|
iota 1 [ 1 + * ] reduce ;
|
2009-05-05 22:43:07 -04:00
|
|
|
|
|
|
|
: nPk ( n k -- nPk )
|
|
|
|
2dup possible? [ dupd - [a,b) product ] [ 2drop 0 ] if ;
|
|
|
|
|
|
|
|
: nCk ( n k -- nCk )
|
|
|
|
twiddle [ nPk ] keep factorial / ;
|
|
|
|
|
|
|
|
|
|
|
|
! Factoradic-based permutation methodology
|
|
|
|
|
|
|
|
<PRIVATE
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2008-01-27 20:00:31 -05:00
|
|
|
: factoradic ( n -- factoradic )
|
2009-05-05 22:43:07 -04:00
|
|
|
0 [ over 0 > ] [ 1 + [ /mod ] keep swap ] produce reverse 2nip ;
|
2008-01-27 20:00:31 -05:00
|
|
|
|
|
|
|
: (>permutation) ( seq n -- seq )
|
2009-05-05 22:43:07 -04:00
|
|
|
[ '[ _ dupd >= [ 1 + ] when ] map ] keep prefix ;
|
2008-01-27 20:00:31 -05:00
|
|
|
|
|
|
|
: >permutation ( factoradic -- permutation )
|
|
|
|
reverse 1 cut [ (>permutation) ] each ;
|
|
|
|
|
|
|
|
: permutation-indices ( n seq -- permutation )
|
2009-01-29 23:19:07 -05:00
|
|
|
length [ factoradic ] dip 0 pad-head >permutation ;
|
2008-01-27 20:00:31 -05:00
|
|
|
|
2012-04-18 18:17:48 -04:00
|
|
|
: permutation-iota ( seq -- iota )
|
|
|
|
length factorial iota ; inline
|
|
|
|
|
2008-01-27 20:00:31 -05:00
|
|
|
PRIVATE>
|
|
|
|
|
2010-02-18 18:31:52 -05:00
|
|
|
: permutation ( n seq -- seq' )
|
2008-10-03 03:19:03 -04:00
|
|
|
[ permutation-indices ] keep nths ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2012-04-23 11:29:20 -04:00
|
|
|
TUPLE: permutations length seq ;
|
|
|
|
|
|
|
|
: <permutations> ( seq -- permutations )
|
|
|
|
[ length factorial ] keep permutations boa ;
|
|
|
|
|
|
|
|
M: permutations length length>> ; inline
|
|
|
|
M: permutations nth-unsafe seq>> permutation ;
|
|
|
|
M: permutations hashcode* tuple-hashcode ;
|
|
|
|
|
|
|
|
INSTANCE: permutations immutable-sequence
|
2008-01-27 20:00:31 -05:00
|
|
|
|
2008-11-06 12:07:19 -05:00
|
|
|
: each-permutation ( seq quot -- )
|
2012-04-18 18:17:48 -04:00
|
|
|
[ [ permutation-iota ] keep ] dip
|
2008-11-06 12:07:19 -05:00
|
|
|
'[ _ permutation @ ] each ; inline
|
|
|
|
|
2012-04-18 18:17:48 -04:00
|
|
|
: map-permutations ( seq quot -- seq' )
|
|
|
|
[ [ permutation-iota ] keep ] dip
|
2012-04-18 17:43:08 -04:00
|
|
|
'[ _ permutation @ ] map ; inline
|
|
|
|
|
2012-04-18 18:17:48 -04:00
|
|
|
: filter-permutations ( seq quot -- seq' )
|
|
|
|
selector [ each-permutation ] dip ; inline
|
|
|
|
|
2012-04-23 11:29:20 -04:00
|
|
|
: all-permutations ( seq -- seq' )
|
|
|
|
[ ] map-permutations ;
|
|
|
|
|
2012-04-21 02:31:40 -04:00
|
|
|
: find-permutation ( seq quot -- elt )
|
|
|
|
[ dup [ permutation-iota ] keep ] dip
|
2012-04-21 23:11:47 -04:00
|
|
|
'[ _ permutation @ ] find drop
|
|
|
|
[ swap permutation ] [ drop f ] if* ; inline
|
2012-04-21 02:31:40 -04:00
|
|
|
|
2009-05-06 01:17:35 -04:00
|
|
|
: reduce-permutations ( seq identity quot -- result )
|
2008-11-06 12:07:19 -05:00
|
|
|
swapd each-permutation ; inline
|
|
|
|
|
2008-01-27 20:00:31 -05:00
|
|
|
: inverse-permutation ( seq -- permutation )
|
2011-04-07 12:01:21 -04:00
|
|
|
<enum> sort-values keys ;
|
2009-05-05 22:43:07 -04:00
|
|
|
|
2012-03-02 12:54:11 -05:00
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: cut-point ( seq -- n )
|
|
|
|
[ last ] keep [ [ > ] keep swap ] find-last drop nip ;
|
|
|
|
|
|
|
|
: greater-from-last ( n seq -- i )
|
|
|
|
[ nip ] [ nth ] 2bi [ > ] curry find-last drop ;
|
|
|
|
|
|
|
|
: reverse-tail! ( n seq -- seq )
|
|
|
|
[ swap 1 + tail-slice reverse! drop ] keep ;
|
|
|
|
|
|
|
|
: (next-permutation) ( seq -- seq )
|
|
|
|
dup cut-point [
|
|
|
|
swap [ greater-from-last ] 2keep
|
|
|
|
[ exchange ] [ reverse-tail! nip ] 3bi
|
|
|
|
] [ reverse! ] if* ;
|
|
|
|
|
|
|
|
PRIVATE>
|
|
|
|
|
|
|
|
: next-permutation ( seq -- seq )
|
|
|
|
dup [ ] [ drop (next-permutation) ] if-empty ;
|
2009-05-05 22:43:07 -04:00
|
|
|
|
|
|
|
! Combinadic-based combination methodology
|
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
2009-05-06 01:17:35 -04:00
|
|
|
TUPLE: combo
|
|
|
|
{ seq sequence }
|
|
|
|
{ k integer } ;
|
|
|
|
|
|
|
|
C: <combo> combo
|
2009-05-05 22:43:07 -04:00
|
|
|
|
2009-05-06 20:18:21 -04:00
|
|
|
: choose ( combo -- nCk )
|
|
|
|
[ seq>> length ] [ k>> ] bi nCk ;
|
|
|
|
|
2009-05-05 22:43:07 -04:00
|
|
|
: largest-value ( a b x -- v )
|
2009-05-06 20:46:41 -04:00
|
|
|
dup 0 = [
|
|
|
|
drop 1 - nip
|
|
|
|
] [
|
2010-01-14 14:05:50 -05:00
|
|
|
[ iota ] 2dip '[ _ nCk _ >=< ] search nip
|
2009-05-06 20:46:41 -04:00
|
|
|
] if ;
|
2009-05-05 22:43:07 -04:00
|
|
|
|
|
|
|
:: next-values ( a b x -- a' b' x' v )
|
|
|
|
a b x largest-value dup :> v ! a'
|
|
|
|
b 1 - ! b'
|
|
|
|
x v b nCk - ! x'
|
|
|
|
v ; ! v == a'
|
|
|
|
|
2009-05-06 20:18:21 -04:00
|
|
|
: dual-index ( m combo -- m' )
|
|
|
|
choose 1 - swap - ;
|
2009-05-06 01:17:35 -04:00
|
|
|
|
2009-05-06 20:18:21 -04:00
|
|
|
: initial-values ( combo m -- n k m )
|
|
|
|
[ [ seq>> length ] [ k>> ] bi ] dip ;
|
2009-05-05 22:43:07 -04:00
|
|
|
|
2009-05-06 01:17:35 -04:00
|
|
|
: combinadic ( combo m -- combinadic )
|
2009-05-05 22:43:07 -04:00
|
|
|
initial-values [ over 0 > ] [ next-values ] produce
|
|
|
|
[ 3drop ] dip ;
|
|
|
|
|
2009-11-05 18:03:24 -05:00
|
|
|
:: combination-indices ( m combo -- seq )
|
|
|
|
combo m combo dual-index combinadic
|
|
|
|
combo seq>> length 1 - swap [ - ] with map ;
|
2009-05-06 01:17:35 -04:00
|
|
|
|
|
|
|
: apply-combination ( m combo -- seq )
|
|
|
|
[ combination-indices ] keep seq>> nths ;
|
|
|
|
|
2009-11-27 23:50:06 -05:00
|
|
|
: combinations-quot ( seq k quot -- seq quot )
|
2010-01-14 14:05:50 -05:00
|
|
|
[ <combo> [ choose iota ] keep ] dip
|
2009-11-27 23:50:06 -05:00
|
|
|
'[ _ apply-combination @ ] ; inline
|
|
|
|
|
2009-05-05 22:43:07 -04:00
|
|
|
PRIVATE>
|
|
|
|
|
2012-04-21 23:11:47 -04:00
|
|
|
: combination ( m seq k -- seq' )
|
|
|
|
<combo> apply-combination ;
|
|
|
|
|
2012-04-23 11:29:20 -04:00
|
|
|
TUPLE: combinations combo length ;
|
|
|
|
|
|
|
|
: <combinations> ( seq k -- combinations )
|
|
|
|
[ <combo> ] 2keep [ length ] [ nCk ] bi* combinations boa ;
|
|
|
|
|
|
|
|
M: combinations length length>> ; inline
|
|
|
|
M: combinations nth-unsafe combo>> apply-combination ;
|
|
|
|
M: combinations hashcode* tuple-hashcode ;
|
|
|
|
|
|
|
|
INSTANCE: combinations immutable-sequence
|
|
|
|
|
2009-11-27 23:50:06 -05:00
|
|
|
: each-combination ( seq k quot -- )
|
|
|
|
combinations-quot each ; inline
|
|
|
|
|
2012-04-21 02:31:40 -04:00
|
|
|
: map-combinations ( seq k quot -- seq' )
|
2009-11-27 23:50:06 -05:00
|
|
|
combinations-quot map ; inline
|
|
|
|
|
2012-04-18 18:17:48 -04:00
|
|
|
: filter-combinations ( seq k quot -- seq' )
|
|
|
|
selector [ each-combination ] dip ; inline
|
|
|
|
|
2009-11-27 23:50:06 -05:00
|
|
|
: map>assoc-combinations ( seq k quot exemplar -- )
|
|
|
|
[ combinations-quot ] dip map>assoc ; inline
|
|
|
|
|
2010-02-18 18:31:52 -05:00
|
|
|
: all-combinations ( seq k -- seq' )
|
2011-10-15 22:19:44 -04:00
|
|
|
[ ] map-combinations ;
|
2009-05-07 21:23:58 -04:00
|
|
|
|
2012-04-21 02:31:40 -04:00
|
|
|
: find-combination ( seq k quot -- i elt )
|
2012-04-21 23:11:47 -04:00
|
|
|
[ combinations-quot find drop ]
|
|
|
|
[ drop pick [ combination ] [ 3drop f ] if ] 3bi ; inline
|
2012-04-21 02:31:40 -04:00
|
|
|
|
2009-05-07 21:23:58 -04:00
|
|
|
: reduce-combinations ( seq k identity quot -- result )
|
|
|
|
[ -rot ] dip each-combination ; inline
|
2010-07-14 12:09:57 -04:00
|
|
|
|
|
|
|
: all-subsets ( seq -- subsets )
|
2010-07-26 11:12:36 -04:00
|
|
|
dup length [0,b] [ all-combinations ] with map concat ;
|
2010-07-14 12:09:57 -04:00
|
|
|
|
2010-08-13 17:34:14 -04:00
|
|
|
<PRIVATE
|
|
|
|
|
2010-07-14 12:09:57 -04:00
|
|
|
: (selections) ( seq n -- selections )
|
2010-08-13 17:34:14 -04:00
|
|
|
[ [ 1array ] map dup ] [ 1 - ] bi* [
|
|
|
|
cartesian-product concat [ { } concat-as ] map
|
|
|
|
] with times ;
|
|
|
|
|
|
|
|
PRIVATE>
|
2010-07-14 12:09:57 -04:00
|
|
|
|
|
|
|
: selections ( seq n -- selections )
|
2010-07-26 11:12:36 -04:00
|
|
|
dup 0 > [ (selections) ] [ 2drop { } ] if ;
|
|
|
|
|