Faster mergesort conses less and no longer does slice fiddling
parent
ad87a38ab8
commit
2a1f6885fb
|
@ -143,6 +143,14 @@ IN: optimizer.known-words
|
||||||
{ [ dup optimize-instance? ] [ optimize-instance ] }
|
{ [ dup optimize-instance? ] [ optimize-instance ] }
|
||||||
} define-optimizers
|
} define-optimizers
|
||||||
|
|
||||||
|
! This is a special-case hack
|
||||||
|
: redundant-array-capacity-check? ( #call -- ? )
|
||||||
|
dup in-d>> first node-literal [ 0 = ] [ fixnum? ] bi and ;
|
||||||
|
|
||||||
|
\ array-capacity? {
|
||||||
|
{ [ dup redundant-array-capacity-check? ] [ [ drop t ] f splice-quot ] }
|
||||||
|
} define-optimizers
|
||||||
|
|
||||||
! eq? on the same object is always t
|
! eq? on the same object is always t
|
||||||
{ eq? = } {
|
{ eq? = } {
|
||||||
{ { @ @ } [ 2drop t ] }
|
{ { @ @ } [ 2drop t ] }
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
USING: sorting sequences kernel math math.order random
|
USING: sorting sequences kernel math math.order random
|
||||||
tools.test vectors ;
|
tools.test vectors sets ;
|
||||||
IN: sorting.tests
|
IN: sorting.tests
|
||||||
|
|
||||||
[ [ ] ] [ [ ] natural-sort ] unit-test
|
[ { } ] [ { } natural-sort ] unit-test
|
||||||
|
|
||||||
[ { 270000000 270000001 } ]
|
[ { 270000000 270000001 } ]
|
||||||
[ T{ slice f 270000000 270000002 270000002 } natural-sort ]
|
[ T{ slice f 270000000 270000002 270000002 } natural-sort ]
|
||||||
|
@ -11,7 +11,9 @@ unit-test
|
||||||
[ t ] [
|
[ t ] [
|
||||||
100 [
|
100 [
|
||||||
drop
|
drop
|
||||||
100 [ 20 random [ 1000 random ] replicate ] replicate natural-sort [ before=? ] monotonic?
|
100 [ 20 random [ 1000 random ] replicate ] replicate
|
||||||
|
dup natural-sort
|
||||||
|
[ set= ] [ nip [ before=? ] monotonic? ] 2bi and
|
||||||
] all?
|
] all?
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
||||||
|
|
|
@ -4,46 +4,127 @@ USING: accessors arrays kernel math sequences vectors math.order
|
||||||
sequences sequences.private math.order ;
|
sequences sequences.private math.order ;
|
||||||
IN: sorting
|
IN: sorting
|
||||||
|
|
||||||
DEFER: sort
|
! Optimized merge-sort:
|
||||||
|
!
|
||||||
|
! 1) only allocates 2 temporary arrays
|
||||||
|
|
||||||
|
! 2) first phase (interchanging pairs x[i], x[i+1] where
|
||||||
|
! x[i] > x[i+1]) is handled specially
|
||||||
|
|
||||||
<PRIVATE
|
<PRIVATE
|
||||||
|
|
||||||
: <iterator> 0 tail-slice ; inline
|
TUPLE: merge
|
||||||
|
{ seq array }
|
||||||
|
{ accum vector }
|
||||||
|
{ accum1 vector }
|
||||||
|
{ accum2 vector }
|
||||||
|
{ from1 array-capacity }
|
||||||
|
{ to1 array-capacity }
|
||||||
|
{ from2 array-capacity }
|
||||||
|
{ to2 array-capacity } ;
|
||||||
|
|
||||||
: this ( slice -- obj )
|
: dump ( from to seq accum -- )
|
||||||
dup slice-from swap slice-seq nth-unsafe ; inline
|
#! Optimize common case where to - from = 1.
|
||||||
|
>r >r 2dup swap - 1 =
|
||||||
|
[ drop r> nth-unsafe r> push ]
|
||||||
|
[ r> <slice> r> push-all ]
|
||||||
|
if ; inline
|
||||||
|
|
||||||
: next ( iterator -- )
|
: l-elt [ from1>> ] [ seq>> ] bi nth-unsafe ; inline
|
||||||
dup slice-from 1+ swap set-slice-from ; inline
|
: r-elt [ from2>> ] [ seq>> ] bi nth-unsafe ; inline
|
||||||
|
: l-done? [ from1>> ] [ to1>> ] bi number= ; inline
|
||||||
|
: r-done? [ from2>> ] [ to2>> ] bi number= ; inline
|
||||||
|
: dump-l [ [ from1>> ] [ to1>> ] [ seq>> ] tri ] [ accum>> ] bi dump ; inline
|
||||||
|
: dump-r [ [ from2>> ] [ to2>> ] [ seq>> ] tri ] [ accum>> ] bi dump ; inline
|
||||||
|
: l-next [ [ l-elt ] [ [ 1+ ] change-from1 drop ] bi ] [ accum>> ] bi push ; inline
|
||||||
|
: r-next [ [ r-elt ] [ [ 1+ ] change-from2 drop ] bi ] [ accum>> ] bi push ; inline
|
||||||
|
: decide [ [ l-elt ] [ r-elt ] bi ] dip call +lt+ eq? ; inline
|
||||||
|
|
||||||
: smallest ( iter1 iter2 quot -- elt )
|
: (merge) ( merge quot -- )
|
||||||
>r over this over this r> call +lt+ eq?
|
over l-done? [ drop dump-r ] [
|
||||||
-rot ? [ this ] keep next ; inline
|
over r-done? [ drop dump-l ] [
|
||||||
|
2dup decide
|
||||||
: (merge) ( iter1 iter2 quot accum -- )
|
[ over l-next ] [ over r-next ] if
|
||||||
>r pick empty? [
|
(merge)
|
||||||
drop nip r> push-all
|
|
||||||
] [
|
|
||||||
over empty? [
|
|
||||||
2drop r> push-all
|
|
||||||
] [
|
|
||||||
3dup smallest r> [ push ] keep (merge)
|
|
||||||
] if
|
] if
|
||||||
] if ; inline
|
] if ; inline
|
||||||
|
|
||||||
: merge ( sorted1 sorted2 quot -- result )
|
: flip-accum ( merge -- )
|
||||||
>r [ [ <iterator> ] bi@ ] 2keep r>
|
dup [ accum>> ] [ accum1>> ] bi eq? [
|
||||||
rot length rot length + <vector>
|
dup accum1>> underlying>> >>seq
|
||||||
[ (merge) ] [ underlying>> ] bi ; inline
|
dup accum2>> >>accum
|
||||||
|
] [
|
||||||
|
dup accum1>> >>accum
|
||||||
|
dup accum2>> underlying>> >>seq
|
||||||
|
] if
|
||||||
|
dup accum>> 0 >>length 2drop ; inline
|
||||||
|
|
||||||
: conquer ( first second quot -- result )
|
: <merge> ( seq -- merge )
|
||||||
[ tuck >r >r sort r> r> sort ] keep merge ; inline
|
\ merge new
|
||||||
|
over >vector >>accum1
|
||||||
|
swap length <vector> >>accum2
|
||||||
|
dup accum1>> underlying>> >>seq
|
||||||
|
dup accum2>> >>accum
|
||||||
|
dup accum>> 0 >>length drop ; inline
|
||||||
|
|
||||||
|
: compute-midpoint ( merge -- merge )
|
||||||
|
dup [ from1>> ] [ to2>> ] bi + 2/ >>to1 ; inline
|
||||||
|
|
||||||
|
: merging ( from to merge -- )
|
||||||
|
swap >>to2
|
||||||
|
swap >>from1
|
||||||
|
compute-midpoint
|
||||||
|
dup [ to1>> ] [ seq>> length ] bi min >>to1
|
||||||
|
dup [ to2>> ] [ seq>> length ] bi min >>to2
|
||||||
|
dup to1>> >>from2
|
||||||
|
drop ; inline
|
||||||
|
|
||||||
|
: nth-chunk ( n size -- from to ) [ * dup ] keep + ; inline
|
||||||
|
|
||||||
|
: chunks ( length size -- n ) [ align ] keep /i ; inline
|
||||||
|
|
||||||
|
: each-chunk ( length size quot -- )
|
||||||
|
[ [ chunks ] keep ] dip
|
||||||
|
[ nth-chunk ] prepose curry
|
||||||
|
each-integer ; inline
|
||||||
|
|
||||||
|
: merge ( from to merge quot -- )
|
||||||
|
[ [ merging ] keep ] dip (merge) ; inline
|
||||||
|
|
||||||
|
: sort-pass ( merge size quot -- )
|
||||||
|
[
|
||||||
|
over flip-accum
|
||||||
|
over [ seq>> length ] 2dip
|
||||||
|
] dip
|
||||||
|
[ merge ] 2curry each-chunk ; inline
|
||||||
|
|
||||||
|
: sort-loop ( merge quot -- )
|
||||||
|
2 swap
|
||||||
|
[ pick seq>> length pick > ]
|
||||||
|
[ [ dup ] [ 1 shift ] [ ] tri* [ sort-pass ] 2keep ]
|
||||||
|
[ ] while 3drop ; inline
|
||||||
|
|
||||||
|
: each-pair ( seq quot -- )
|
||||||
|
[ [ length 1+ 2/ ] keep ] dip
|
||||||
|
[ [ 1 shift dup 1+ ] dip ] prepose curry each-integer ; inline
|
||||||
|
|
||||||
|
: (sort-pairs) ( i1 i2 seq quot accum -- )
|
||||||
|
>r >r 2dup length = [
|
||||||
|
nip nth r> drop r> push
|
||||||
|
] [
|
||||||
|
tuck [ nth-unsafe ] 2bi@ 2dup r> call +gt+ eq?
|
||||||
|
[ swap ] when r> tuck [ push ] 2bi@
|
||||||
|
] if ; inline
|
||||||
|
|
||||||
|
: sort-pairs ( merge quot -- )
|
||||||
|
[ [ seq>> ] [ accum>> ] bi ] dip swap
|
||||||
|
[ (sort-pairs) ] 2curry each-pair ; inline
|
||||||
|
|
||||||
PRIVATE>
|
PRIVATE>
|
||||||
|
|
||||||
: sort ( seq quot -- sortedseq )
|
: sort ( seq quot -- seq' )
|
||||||
over length 1 <=
|
[ <merge> ] dip
|
||||||
[ drop ] [ over >r >r halves r> conquer r> like ] if ;
|
[ sort-pairs ] [ sort-loop ] [ drop accum>> underlying>> ] 2tri ;
|
||||||
inline
|
inline
|
||||||
|
|
||||||
: natural-sort ( seq -- sortedseq ) [ <=> ] sort ;
|
: natural-sort ( seq -- sortedseq ) [ <=> ] sort ;
|
||||||
|
|
Loading…
Reference in New Issue