]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor into llvm
authorMatthew Willis <matthew.willis@mac.com>
Tue, 30 Jun 2009 02:44:40 +0000 (11:44 +0900)
committerMatthew Willis <matthew.willis@mac.com>
Tue, 30 Jun 2009 02:44:40 +0000 (11:44 +0900)
basis/compiler/cfg/linear-scan/resolve/resolve-tests.factor
basis/compiler/cfg/linear-scan/resolve/resolve.factor
basis/compiler/cfg/stack-analysis/merge/merge.factor
basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor
basis/compiler/cfg/stack-analysis/stack-analysis.factor
basis/math/primes/factors/factors-docs.factor
basis/math/primes/factors/factors-tests.factor
basis/math/primes/factors/factors.factor

index fad1c022ef285dd2aaf1b2b19e34b0960d476080..7579b46175cd98f896b45d77befb5a7ad18091ee 100644 (file)
@@ -67,119 +67,94 @@ T{ live-interval
 
 [
     {
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
+        T{ _copy { dst 5 } { src 4 } { class int-regs } }
+        T{ _spill { src 0 } { class int-regs } { n 6 } }
+        T{ _copy { dst 0 } { src 1 } { class int-regs } }
+        T{ _reload { dst 1 } { class int-regs } { n 6 } }
+        T{ _spill { src 0 } { class float-regs } { n 7 } }
+        T{ _copy { dst 0 } { src 1 } { class float-regs } }
+        T{ _reload { dst 1 } { class float-regs } { n 7 } }
     }
 ] [
     {
         T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-    } trace-chains
+        T{ register->register { from 1 } { to 0 } { reg-class int-regs } }
+        T{ register->register { from 0 } { to 1 } { reg-class float-regs } }
+        T{ register->register { from 1 } { to 0 } { reg-class float-regs } }
+        T{ register->register { from 4 } { to 5 } { reg-class int-regs } }
+    } mapping-instructions
 ] unit-test
 
 [
     {
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
+        T{ _spill { src 0 } { class int-regs } { n 3 } }
+        T{ _copy { dst 0 } { src 2 } { class int-regs } }
+        T{ _copy { dst 2 } { src 1 } { class int-regs } }
+        T{ _reload { dst 1 } { class int-regs } { n 3 } }
     }
 ] [
     {
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-    } trace-chains
-] unit-test
-
-[
-    {
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
         T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-    }
-] [
-    {
         T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-    } trace-chains
+        T{ register->register { from 2 } { to 0 } { reg-class int-regs } }
+    } mapping-instructions
 ] unit-test
 
 [
     {
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
+        T{ _spill { src 0 } { class int-regs } { n 3 } }
+        T{ _copy { dst 0 } { src 2 } { class int-regs } }
+        T{ _copy { dst 2 } { src 1 } { class int-regs } }
+        T{ _reload { dst 1 } { class int-regs } { n 3 } }
     }
 ] [
     {
         T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
+        T{ register->register { from 2 } { to 0 } { reg-class int-regs } }
         T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-    } trace-chains
+    } mapping-instructions
 ] unit-test
 
 [
     {
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
-        T{ register->memory { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
+        T{ _copy { dst 1 } { src 0 } { class int-regs } }
+        T{ _copy { dst 2 } { src 0 } { class int-regs } }
     }
 ] [
     {
-        T{ register->memory { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 2 } { to 3 } { reg-class int-regs } }
         T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-    } trace-chains
+        T{ register->register { from 0 } { to 2 } { reg-class int-regs } }
+    } mapping-instructions
 ] unit-test
 
 [
-    {
-        T{ _copy { dst 5 } { src 4 } { class int-regs } }
-        T{ _spill { src 1 } { class int-regs } { n 6 } }
-        T{ _copy { dst 1 } { src 0 } { class int-regs } }
-        T{ _reload { dst 0 } { class int-regs } { n 6 } }
-        T{ _spill { src 1 } { class float-regs } { n 7 } }
-        T{ _copy { dst 1 } { src 0 } { class float-regs } }
-        T{ _reload { dst 0 } { class float-regs } { n 7 } }
-    }
+    { }
 ] [
     {
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-        T{ register->register { from 1 } { to 0 } { reg-class int-regs } }
-        T{ register->register { from 0 } { to 1 } { reg-class float-regs } }
-        T{ register->register { from 1 } { to 0 } { reg-class float-regs } }
-        T{ register->register { from 4 } { to 5 } { reg-class int-regs } }
+       T{ register->register { from 4 } { to 4 } { reg-class int-regs } }
     } mapping-instructions
 ] unit-test
 
 [
-    {
-        T{ _spill { src 1 } { class int-regs } { n 3 } }
-        T{ _copy { dst 1 } { src 0 } { class int-regs } }
-        T{ _copy { dst 0 } { src 2 } { class int-regs } }
-        T{ _reload { dst 2 } { class int-regs } { n 3 } }
-    }
+    { T{ _spill { src 4 } { class int-regs } { n 4 } } }
 ] [
     {
-        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 2 } { to 0 } { reg-class int-regs } }
+       T{ register->memory { from 4 } { to 4 } { reg-class int-regs } }
     } mapping-instructions
 ] unit-test
 
+
 [
     {
-        T{ _spill { src 1 } { class int-regs } { n 3 } }
         T{ _copy { dst 1 } { src 0 } { class int-regs } }
-        T{ _copy { dst 0 } { src 2 } { class int-regs } }
-        T{ _reload { dst 2 } { class int-regs } { n 3 } }
+        T{ _copy { dst 2 } { src 0 } { class int-regs } }
+        T{ _copy { dst 0 } { src 3 } { class int-regs } }
     }
 ] [
     {
-        T{ register->register { from 1 } { to 2 } { reg-class int-regs } }
-        T{ register->register { from 2 } { to 0 } { reg-class int-regs } }
         T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
+        T{ register->register { from 3 } { to 0 } { reg-class int-regs } }
+        T{ register->register { from 0 } { to 2 } { reg-class int-regs } }
     } mapping-instructions
 ] unit-test
 
@@ -187,26 +162,38 @@ T{ live-interval
     {
         T{ _copy { dst 1 } { src 0 } { class int-regs } }
         T{ _copy { dst 2 } { src 0 } { class int-regs } }
+        T{ _spill { src 3 } { class int-regs } { n 5 } }
+        T{ _copy { dst 4 } { src 0 } { class int-regs } }
+        T{ _copy { dst 3 } { src 4 } { class int-regs } }
+        T{ _reload { dst 0 } { class int-regs } { n 5 } }
     }
 ] [
     {
         T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
         T{ register->register { from 0 } { to 2 } { reg-class int-regs } }
+        T{ register->register { from 3 } { to 0 } { reg-class int-regs } }
+        T{ register->register { from 4 } { to 3 } { reg-class int-regs } }
+        T{ register->register { from 0 } { to 4 } { reg-class int-regs } }
     } mapping-instructions
 ] unit-test
 
 [
-    { }
-] [
     {
-       T{ register->register { from 4 } { to 4 } { reg-class int-regs } }
-    } mapping-instructions
-] unit-test
-
-[
-    { T{ _spill { src 4 } { class int-regs } { n 4 } } }
+        T{ _copy { dst 2 } { src 0 } { class int-regs } }
+        T{ _copy { dst 9 } { src 1 } { class int-regs } }
+        T{ _copy { dst 1 } { src 0 } { class int-regs } }
+        T{ _spill { src 3 } { class int-regs } { n 10 } }
+        T{ _copy { dst 4 } { src 0 } { class int-regs } }
+        T{ _copy { dst 3 } { src 4 } { class int-regs } }
+        T{ _reload { dst 0 } { class int-regs } { n 10 } }
+    }
 ] [
     {
-       T{ register->memory { from 4 } { to 4 } { reg-class int-regs } }
+        T{ register->register { from 0 } { to 1 } { reg-class int-regs } }
+        T{ register->register { from 0 } { to 2 } { reg-class int-regs } }
+        T{ register->register { from 1 } { to 9 } { reg-class int-regs } }
+        T{ register->register { from 3 } { to 0 } { reg-class int-regs } }
+        T{ register->register { from 4 } { to 3 } { reg-class int-regs } }
+        T{ register->register { from 0 } { to 4 } { reg-class int-regs } }
     } mapping-instructions
 ] unit-test
index b29a661fbf45864e6b9e8b24de186a43180d74f4..182686a0fad15f0fac4ca37e189516d35dda5345 100644 (file)
@@ -1,11 +1,10 @@
 ! Copyright (C) 2009 Slava Pestov, Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays assocs classes.parser classes.tuple
-combinators combinators.short-circuit compiler.cfg.instructions
-compiler.cfg.linear-scan.live-intervals compiler.cfg.liveness
-fry hashtables histogram kernel locals make math math.order
-namespaces parser prettyprint random sequences sets
-sorting.functor sorting.slots words ;
+combinators combinators.short-circuit fry hashtables kernel locals
+make math math.order namespaces sequences sets words parser
+compiler.cfg.instructions compiler.cfg.linear-scan.live-intervals
+compiler.cfg.liveness ;
 IN: compiler.cfg.linear-scan.resolve
 
 <<
@@ -114,38 +113,39 @@ M: register->register to-loc drop register ;
 : to-reg ( operation -- seq )
     [ to-loc ] [ to>> ] [ reg-class>> ] tri 3array ;
 
-: (trace-chain) ( pair -- )
-    to-reg froms get at [
-        dup length 1 = [
-            first [ , ] [ (trace-chain) ] bi
-        ] [
-            drop
-        ] if
-    ] when* ;
-
-: trace-chain ( pair -- seq )
-    [ [ , ] [ (trace-chain) ] bi ] { } make reverse ;
-
 : start? ( operations -- pair )
     from-reg tos get key? not ;
 
+: independent-assignment? ( operations -- pair )
+    to-reg froms get key? not ;
+
 : init-temp-spill ( operations -- )
     [ [ to>> ] [ from>> ] bi max ] [ max ] map-reduce
     1 + temp-spill set ;
 
 : set-tos/froms ( operations -- )
-    {
-        [ [ from-reg ] collect-values froms set ]
-        [ [ to-reg ] collect-values tos set ]
-    } cleave ;
+    [ [ [ from-reg ] keep ] H{ } map>assoc froms set ]
+    [ [ [ to-reg ] keep ] H{ } map>assoc tos set ]
+    bi ;
+
+:: (trace-chain) ( obj hashtable -- )
+    obj to-reg froms get at* [
+        obj over hashtable clone [ maybe-set-at ] keep swap
+        [ (trace-chain) ] [ , drop ] if
+    ] [
+        drop hashtable ,
+    ] if ;
+
+: trace-chain ( obj -- seq )
+    [
+        dup dup associate (trace-chain)
+    ] { } make [ keys ] map concat reverse ;
 
-: trace-chains ( operations -- operations' )
-    [ set-tos/froms ]
-    [ [ start? ] filter [ trace-chain ] map concat ] bi ;
+: trace-chains ( seq -- seq' )
+    [ trace-chain ] map concat ;
 
 : break-cycle-n ( operations -- operations' )
-    unclip [ trace-chains ] dip
-    [
+    unclip [
         [ from>> temp-spill get ]
         [ reg-class>> ] bi \ register->memory boa
     ] [
@@ -155,32 +155,30 @@ M: register->register to-loc drop register ;
 
 : break-cycle ( operations -- operations' )
     dup length {
-        { 1 [ drop { } ] }
+        { 1 [ ] }
         [ drop break-cycle-n ]
     } case ;
 
-: follow-cycle ( obj -- seq )
-   dup dup associate [
-        [ to-reg froms get at first dup dup ] dip
-        [ maybe-set-at ] keep swap
-    ] loop nip keys ;
-
 : (group-cycles) ( seq -- )
     [
-        unclip follow-cycle [ diff ] keep , (group-cycles)
+        dup set-tos/froms
+        unclip trace-chain
+        [ diff ] keep , (group-cycles)
     ] unless-empty ;
 
 : group-cycles ( seq -- seqs )
     [ (group-cycles) ] { } make ;
 
-: partition-mappings ( mappings -- no-cycles cycles )
-    [ start? not ] partition
-    [ trace-chain ] map concat tuck diff ;
+: remove-dead-mappings ( seq -- seq' )
+    prune [ [ from-reg ] [ to-reg ] bi = not ] filter ;
 
 : parallel-mappings ( operations -- seq )
-    partition-mappings [
-        group-cycles [ break-cycle ] map concat append
-    ] unless-empty ;
+    [
+        [ independent-assignment? not ] partition %
+        [ start? not ] partition
+        [ trace-chain ] map concat dup %
+        diff group-cycles [ break-cycle ] map concat %
+    ] { } make remove-dead-mappings ;
 
 : mapping-instructions ( mappings -- insns )
     [
@@ -191,15 +189,19 @@ M: register->register to-loc drop register ;
     ] with-scope ;
 
 : fork? ( from to -- ? )
-    [ successors>> length 1 >= ]
-    [ predecessors>> length 1 = ] bi* and ; inline
+    {
+        [ drop successors>> length 1 >= ]
+        [ nip predecessors>> length 1 = ]
+    } 2&& ; inline
 
 : insert-position/fork ( from to -- before after )
     nip instructions>> [ >array ] [ dup delete-all ] bi swap ;
 
 : join? ( from to -- ? )
-    [ successors>> length 1 = ]
-    [ predecessors>> length 1 >= ] bi* and ; inline
+    {
+        [ drop successors>> length 1 = ]
+        [ nip predecessors>> length 1 >= ]
+    } 2&& ; inline
 
 : insert-position/join ( from to -- before after )
     drop instructions>> dup pop 1array ;
index 25b0c3003374234e12ce9b18b3e984d58704a5cb..04643a31f0ac56796285d4fc3317b6f9e1536b60 100644 (file)
@@ -37,25 +37,25 @@ IN: compiler.cfg.stack-analysis.merge
     '[ _ untranslate-loc ] assoc-map-values ;
 
 : collect-locs ( loc-maps states -- assoc )
-    ! assoc maps locs to sequences of vregs
+    ! assoc maps locs to sequences
     [ untranslate-locs ] 2map
     [ [ keys ] map concat prune ] keep
     '[ dup _ [ at ] with map ] H{ } map>assoc ;
 
-: insert-peek ( predecessor state loc -- vreg )
-    '[ _ _ swap translate-loc ^^peek ] add-instructions ;
+: insert-peek ( predecessor loc state -- vreg )
+    '[ _ _ translate-loc ^^peek ] add-instructions ;
 
-: merge-loc ( predecessors states vregs loc -- vreg )
+: merge-loc ( predecessors vregs loc state -- vreg )
     ! Insert a ##phi in the current block where the input
     ! is the vreg storing loc from each predecessor block
-    '[ dup [ 2nip ] [ drop _ insert-peek ] if ] 3map
+    '[ [ ] [ _ _ insert-peek ] ?if ] 2map
     dup all-equal? [ first ] [ ^^phi ] if ;
 
 :: merge-locs ( state predecessors states -- state )
     states [ locs>vregs>> ] map states collect-locs
     [| key value |
         key
-        predecessors states value key merge-loc
+        predecessors value key state merge-loc
     ] assoc-map
     state translate-locs
     state (>>locs>vregs)
@@ -64,14 +64,17 @@ IN: compiler.cfg.stack-analysis.merge
 : merge-actual-loc ( vregs -- vreg/f )
     dup all-equal? [ first ] [ drop f ] if ;
 
-: merge-actual-locs ( state states -- state )
-    [ [ actual-locs>vregs>> ] map ] keep collect-locs
+:: merge-actual-locs ( state states -- state )
+    states [ actual-locs>vregs>> ] map states collect-locs
     [ merge-actual-loc ] assoc-map [ nip ] assoc-filter
-    over translate-locs
-    >>actual-locs>vregs ;
+    state translate-locs
+    state (>>actual-locs>vregs)
+    state ;
 
 : merge-changed-locs ( state states -- state )
-    [ changed-locs>> ] map assoc-combine >>changed-locs ;
+    [ [ changed-locs>> ] keep untranslate-locs ] map assoc-combine
+    over translate-locs
+    >>changed-locs ;
 
 ERROR: cannot-merge-poisoned states ;
 
index e01d870bf2b42e64ec8b02f7a2b9dfcef75d435f..1bef0c396748f0cd29f9261a2302b36018c4ffb7 100644 (file)
@@ -8,26 +8,11 @@ sets namespaces arrays cpu.architecture ;
 IN: compiler.cfg.stack-analysis.tests
 
 ! Fundamental invariant: a basic block should not load or store a value more than once
-: check-for-redundant-ops ( cfg -- )
-    [
-        instructions>>
-        [
-            [ ##peek? ] filter [ loc>> ] map duplicates empty?
-            [ "Redundant peeks" throw ] unless
-        ] [
-            [ ##replace? ] filter [ loc>> ] map duplicates empty?
-            [ "Redundant replaces" throw ] unless
-        ] bi
-    ] each-basic-block ;
-
 : test-stack-analysis ( quot -- cfg )
     dup cfg? [ test-cfg first ] unless
     compute-predecessors
-    delete-useless-blocks
-    delete-useless-conditionals
     stack-analysis
-    dup check-cfg
-    dup check-for-redundant-ops ;
+    dup check-cfg ;
 
 : linearize ( cfg -- mr )
     flatten-cfg instructions>> ;
@@ -116,7 +101,7 @@ local-only? off
 ! Correct height tracking
 [ t ] [
     [ pick [ <array> ] [ drop ] if swap ] test-stack-analysis eliminate-dead-code
-    reverse-post-order 2 swap nth
+    reverse-post-order 3 swap nth
     instructions>> [ ##peek? ] filter first2 [ loc>> ] [ loc>> ] bi*
     2array { D 1 D 0 } set=
 ] unit-test
@@ -144,4 +129,78 @@ local-only? off
     drop
 
     3 get instructions>> second loc>>
+] unit-test
+
+! Do inserted ##peeks reference the correct stack location if
+! an ##inc-d/r was also inserted?
+[ D 0 ] [
+    V{ T{ ##branch } } 0 test-bb
+
+    V{ T{ ##branch } } 1 test-bb
+
+    V{
+        T{ ##peek f V int-regs 1 D 0 }
+        T{ ##branch }
+    } 2 test-bb
+
+    V{
+        T{ ##call f \ + -1 }
+        T{ ##inc-d f 1 }
+        T{ ##branch }
+    } 3 test-bb
+
+    V{ T{ ##return } } 4 test-bb
+
+    test-diamond
+
+    cfg new 0 get >>entry
+    compute-predecessors
+    stack-analysis
+    drop
+
+    3 get instructions>> [ ##peek? ] find nip loc>>
+] unit-test
+
+! Missing ##replace
+[ t ] [
+    [ [ "B" ] 2dip dup [ [ /mod ] dip ] when ] test-stack-analysis
+    reverse-post-order last
+    instructions>> [ ##replace? ] filter [ loc>> ] map
+    { D 0 D 1 D 2 } set=
+] unit-test
+
+! Inserted ##peeks reference the wrong stack location
+[ t ] [
+    [ [ "B" ] 2dip dup [ [ /mod ] dip ] when ] test-stack-analysis
+    eliminate-dead-code reverse-post-order 3 swap nth
+    instructions>> [ ##peek? ] filter [ loc>> ] map
+    { R 0 D 0 D 1 } set=
+] unit-test
+
+[ D 0 ] [
+    V{ T{ ##branch } } 0 test-bb
+
+    V{ T{ ##branch } } 1 test-bb
+
+    V{
+        T{ ##peek f V int-regs 1 D 0 }
+        T{ ##inc-d f 1 }
+        T{ ##branch }
+    } 2 test-bb
+
+    V{
+        T{ ##inc-d f 1 }
+        T{ ##branch }
+    } 3 test-bb
+
+    V{ T{ ##return } } 4 test-bb
+
+    test-diamond
+
+    cfg new 0 get >>entry
+    compute-predecessors
+    stack-analysis
+    drop
+
+    3 get instructions>> [ ##peek? ] find nip loc>>
 ] unit-test
\ No newline at end of file
index 0e06a2fdf5f2f2c06b21b4b23f924b7b9fa00bd0..5679d8bd11320a32b2cfa3194deaa3bd6f70c7e2 100644 (file)
@@ -18,10 +18,10 @@ IN: compiler.cfg.stack-analysis
     [ 2drop t ] [ state get actual-locs>vregs>> at = ] if ;
 
 : save-changed-locs ( state -- )
-    [ changed-locs>> ] [ locs>vregs>> ] bi '[
-        _ at swap 2dup redundant-replace?
+    [ changed-locs>> keys ] [ locs>vregs>> ] bi '[
+        dup _ at swap 2dup redundant-replace?
         [ 2drop ] [ state get untranslate-loc ##replace ] if
-    ] assoc-each ;
+    ] each ;
 
 ERROR: poisoned-state state ;
 
index f9fe4d5dcbacee61a8f3e0903a3719ade14fb168..b22d1ba1a511964c832aa518920e1733c62da473 100644 (file)
@@ -1,7 +1,7 @@
 USING: help.markup help.syntax math sequences ;
 IN: math.primes.factors
 
-{ factors group-factors unique-factors } related-words
+{ divisors factors group-factors unique-factors } related-words
 
 HELP: factors
 { $values { "n" "a positive integer" } { "seq" sequence } }
@@ -21,3 +21,7 @@ HELP: unique-factors
 HELP: totient
 { $values { "n" "a positive integer" } { "t" integer } }
 { $description { "Return the number of integers between 1 and " { $snippet "n-1" } " that are relatively prime to " { $snippet "n" } "." } } ;
+
+HELP: divisors
+{ $values { "n" "a positive integer" } { "seq" sequence } }
+{ $description { "Return the ordered list of divisors of " { $snippet "n" } ", including 1 and " { $snippet "n" } "." } } ;
index 8e2e10711a3766e80034f9e895b2c061b12acab8..eea59b6f9b53009326bb3211d410e2429880ca0c 100644 (file)
@@ -1,4 +1,4 @@
-USING: math.primes.factors tools.test ;
+USING: math.primes.factors sequences tools.test ;
 
 { { 999983 999983 1000003 } } [ 999969000187000867 factors ] unit-test
 { { } } [ -5 factors ] unit-test
@@ -8,3 +8,5 @@ USING: math.primes.factors tools.test ;
 { 0 } [ 1 totient ] unit-test
 { { 425612003 } } [ 425612003 factors ] unit-test
 { { 13 4253 15823 32472893749823741 } } [ 28408516453955558205925627 factors ] unit-test
+{ { 1 2 3 4 6 8 12 24 } } [ 24 divisors ] unit-test
+{ 24 } [ 360 divisors length ] unit-test
index f5fa468687f1f38eb5d5a98906bd1fee8adca2e4..439d55ee8d405a2e947eff19c3067d8fd151aa66 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2007-2009 Samuel Tardieu.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: arrays combinators kernel make math math.functions
-math.primes sequences ;
+math.primes math.ranges sequences sequences.product sorting ;
 IN: math.primes.factors
 
 <PRIVATE
@@ -41,3 +41,7 @@ PRIVATE>
         { [ dup 2 < ] [ drop 0 ] }
         [ dup unique-factors [ 1 [ 1- * ] reduce ] [ product ] bi / * ]
     } cond ; foldable
+
+: divisors ( n -- seq )
+    group-factors [ first2 [0,b] [ ^ ] with map ] map
+    [ product ] product-map natural-sort ;