packages feed

Zora 1.1.10.2 → 1.1.10.4

raw patch · 4 files changed

+364/−102 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Zora.Math: int_to_double :: Double -> Integer
+ Zora.List: (<$*>) :: Applicative f => (a -> a -> b) -> f a -> f b
+ Zora.List: bsearch :: (Integer -> Ordering) -> Maybe Integer
+ Zora.List: bsearch_1st_geq :: (Integer -> Ordering) -> Maybe Integer
+ Zora.List: count :: (a -> Bool) -> [a] -> Integer
+ Zora.List: elem_counts :: Ord a => [a] -> [(a, Integer)]
+ Zora.List: find_and_rest :: (a -> Bool) -> [a] -> Maybe (a, [a])
+ Zora.List: fst3 :: (a, b, c) -> a
+ Zora.List: interleave :: [a] -> [a] -> [a]
+ Zora.List: map_fst :: (a -> c) -> (a, b) -> (c, b)
+ Zora.List: map_pair :: (a -> c) -> (b -> d) -> (a, b) -> (c, d)
+ Zora.List: map_snd :: (b -> c) -> (a, b) -> (a, c)
+ Zora.List: minima_by :: (a -> a -> Ordering) -> [a] -> [a]
+ Zora.List: pair_op :: (a -> b -> c) -> (a, b) -> c
+ Zora.List: running_bests :: Ord a => [a] -> [a]
+ Zora.List: running_bests_by :: Ord a => (a -> a -> Ordering) -> [a] -> [a]
+ Zora.List: snd3 :: (a, b, c) -> b
+ Zora.List: subsets_of_size_with_replacement :: Integer -> [a] -> [[a]]
+ Zora.List: trd3 :: (a, b, c) -> c
+ Zora.List: triple_op :: (a -> b -> c -> d) -> (a, b, c) -> d
+ Zora.Math: double_to_int :: Double -> Integer
+ Zora.Math: fibs :: [Integer]
+ Zora.Math: num_divisors :: Integer -> Integer
+ Zora.Math: sqrt_perfect_square :: Integer -> Integer
+ Zora.Math: square :: Integer -> Bool

Files

Zora.cabal view
@@ -1,5 +1,5 @@ Name:		   Zora-Version:	   1.1.10.2+Version:	   1.1.10.4 Synopsis:      Graphing library wrapper + assorted useful functions  Description:   A library of assorted useful functions for working with lists, doing mathematical operations and graphing custom data types. Category:      Unclassified
Zora/Graphing/DAGGraphing.hs view
@@ -56,8 +56,8 @@ 	-- | Expands a node into its show_node and children. For example, 	--  	-- > expand (Empty) = Nothing-	-- > expand (Leaf x) = Just (x, [])-	-- > expand (Node x l r) = Just (x, [("L child", l), ("R child", r)])+	-- > expand (Leaf x) = Just (show x, [])+	-- > expand (Node x l r) = Just (show x, [("L child", l), ("R child", r)]) 	expand :: g -> Maybe (Maybe String, [(Maybe String, g)])  -- | Returns whether a node is empty. Sometimes, when declaring algebraic data types, it is desirable to have an \"Empty\" show_node constructor. If your data type does not have an \"Empty\" show_node constructor, just always return @False@.
Zora/List.hs view
@@ -1,10 +1,10 @@ {-# LANGUAGE ScopedTypeVariables #-}  -- |--- Module      : Zora.List+-- Module   : Zora.List -- Copyright   : (c) Brett Wines 2014 ----- License     : BSD-style+-- License   : BSD-style -- -- Maintainer  : bgwines@cs.stanford.edu -- Stability   : experimental@@ -15,8 +15,13 @@  module Zora.List (+-- * Partitioning+  partition_with_block_size+, partition_into_k+, powerpartition+ -- * List transformations-  uniqueify+, uniqueify , pairify , decyclify , shuffle@@ -25,14 +30,10 @@ , powerset , permutations , subsets_of_size+, subsets_of_size_with_replacement , cycles , has_cycles --- * Partitioning-, partition_with_block_size-, partition_into_k-, powerpartition- -- * Operations with two lists , diff_infinite , merge@@ -44,6 +45,7 @@ , subseq , take_while_keep_last , take_while_and_rest+, find_and_rest , subsequences , contiguous_subsequences @@ -56,14 +58,33 @@ , contains_duplicates  -- * Assorted functions+, bsearch+, bsearch_1st_geq+, elem_counts+, running_bests+, running_bests_by+, (<$*>)+, interleave+, count , map_keep , maximum_with_index , minimum_with_index+, minima_by , length' , drop' , take' , cons , snoc++-- * Tuples+, map_fst+, map_snd+, map_pair+, fst3+, snd3+, trd3+, pair_op+, triple_op ) where  import qualified Data.List as List@@ -72,10 +93,60 @@  import System.Random +import Control.Applicative+ import Data.Monoid import Data.Maybe  -- ---------------------------------------------------------------------+-- Partitioning++-- | /O(n)/ Partitions the given list into blocks of the specified length. Truncation behaves as follows:+-- +-- > partition_with_block_size 3 [1..10] == [[1,2,3],[4,5,6],[7,8,9],[10]]+partition_with_block_size :: Int -> [a] -> [[a]]+partition_with_block_size len l =+    if (length l) <= len+        then [l]+        else (take len l) : (partition_with_block_size len (drop len l))++-- | /O(n)/ Partitions the given list into /k/ blocks. Truncation behavior is best described by example:+-- +-- > partition_into_k  3 [1..9]  == [[1,2,3],[4,5,6],[7,8,9]]+-- > partition_into_k  3 [1..10] == [[1,2,3,4],[5,6,7,8],[9,10]]+-- > partition_into_k  3 [1..11] == [[1,2,3,4],[5,6,7,8],[9,10,11]]+-- > partition_into_k  3 [1..12] == [[1,2,3,4],[5,6,7,8],[9,10,11,12]]+-- > partition_into_k  3 [1..13] == [[1,2,3,4,5],[6,7,8,9,10],[11,12,13]]+partition_into_k :: Int -> [a] -> [[a]]+partition_into_k k arr = partition_with_block_size block_size arr+    where+        block_size :: Int+        block_size = if (((length arr) `mod` k) == 0)+            then (length arr) `div` k+            else (length arr) `div` k + 1++-- | /O(B(n))/, where /B(n)/ is the /n/^th <http://en.wikipedia.org/wiki/Bell_number Bell number>. Computes all partitions of the given list. For example,+-- +-- > powerpartition [1..3] == [[[1],[2],[3]], [[1,2],[3]], [[2],[1,3]], [[1],[2,3]], [[1,2,3]]]+powerpartition :: [a] -> [[[a]]]+powerpartition [] = []+powerpartition l@(x:xs) =+    if length l == 1+        then [[[x]]]+        else concatMap (get_next_partitions x) . powerpartition $ xs+        where+            get_next_partitions :: a -> [[a]] -> [[[a]]]+            get_next_partitions e l = ([e] : l) : (map f indices)+                where+                    f i = (a i) ++ (b i) ++ (c i)+                    +                    a i = ((take' i) l)+                    b i = [e : (l !! (fromInteger i))]+                    c i = (drop' (i+1) l)++                    indices = [0..((length' l) - 1)]++-- --------------------------------------------------------------------- -- List transformations  -- | /O(n log(n))/ Removes duplicate elements. Like `Data.List.nub`, but for `Ord` types, so it can be faster.@@ -91,6 +162,8 @@ pairify l = []  -- | /O(l m)/, where /l/ is the cycle length and /m/ is the index of the start of the cycle. If the list contains no cycles, then the runtime is /O(n)/.+--+-- NOTE: this function will only find cycles in a list can be the output of an iterated function -- that is, no element may be succeeded by two separate elements (e.g. [2,3,2,4]). decyclify :: (Eq a) => [a] -> [a] decyclify = fromJust . List.find (not . has_cycles) . iterate decyclify_once @@ -100,11 +173,11 @@         then l         else take' (lambda' + mu'') l     where-        i       = alg1 (tail l) (tail . tail $ l)-        i'      = fromJust i+        i    = alg1 (tail l) (tail . tail $ l)+        i'  = fromJust i -        mu      = if (i  == Nothing) then Nothing else alg2 l (drop' i' l)-        mu'     = fromInteger . fromJust $ mu+        mu  = if (i  == Nothing) then Nothing else alg2 l (drop' i' l)+        mu'  = fromInteger . fromJust $ mu         mu''    = fromJust mu          lambda  = if (mu == Nothing) then Nothing else alg3 (drop (mu' + 1) l) (l !! mu')@@ -183,7 +256,7 @@         powerset_rec [] so_far = [so_far]         powerset_rec src so_far = without ++ with             where without = powerset_rec (tail src) (so_far)-                  with    = powerset_rec (tail src) ((head src) : so_far)+                  with  = powerset_rec (tail src) ((head src) : so_far)  -- TODO: actually O(n!)? -- | /O(n!)/ Computes all permutations of the given list.@@ -213,16 +286,20 @@                 without = subsets_of_size_rec (tail src) so_far size                 with    = subsets_of_size_rec (tail src) ((head src) : so_far) (size-1) -{-subsets_of_size_with_replacement_rec :: Integer -> [a] -> [a] -> [[a]]-subsets_of_size_with_replacement_rec size src so_far =-    case size == 0 of-        True  -> [so_far]-        False -> concat [map (e:) rec | e <- src]-        where rec = subsets_of_size_with_replacement_rec (size - 1)+-- | /O(n^m)/ Computes all sets comprised of elements in the given list, where the elements may be used multiple times, where `n` is the size of the given list and `m` is the size of the sets to generate. For example,+--+--   > subsets_of_size_with_replacement 3 [1,2] == [[1,1,1],[2,1,1],[1,2,1],[2,2,1],[1,1,2],[2,1,2],[1,2,2],[2,2,2]] -subsets_of_size_with_replacement :: [a] -> Integer -> [[a]]-subsets_of_size_with_replacement l size =-    subsets_of_size_with_replacement_rec size l []-}+subsets_of_size_with_replacement :: Integer -> [a] -> [[a]]+subsets_of_size_with_replacement n src = subsets_of_size_with_replacement' n src []+    where+        subsets_of_size_with_replacement' :: forall a. Integer -> [a] -> [a] -> [[a]]+        subsets_of_size_with_replacement' 0 src so_far = [so_far]+        subsets_of_size_with_replacement' n src so_far+            = concatMap (subsets_of_size_with_replacement' (n-1) src) $ nexts+            where+                nexts :: [[a]]+                nexts = map (: so_far) src  -- | /O(n)/ Generates all cycles of a given list. For example, -- @@ -243,54 +320,6 @@ has_cycles l = (decyclify_once l) /= l  -- ------------------------------------------------------------------------ Partitioning---- | /O(n)/ Partitions the given list into blocks of the specified length. Truncation behaves as follows:--- --- > partition_with_block_size 3 [1..10] == [[1,2,3],[4,5,6],[7,8,9],[10]]-partition_with_block_size :: Int -> [a] -> [[a]]-partition_with_block_size len l =-    if (length l) <= len-        then [l]-        else (take len l) : (partition_with_block_size len (drop len l))---- | /O(n)/ Partitions the given list into /k/ blocks. Truncation behavior is best described by example:--- --- > partition_into_k  3 [1..9]  == [[1,2,3],[4,5,6],[7,8,9]]--- > partition_into_k  3 [1..10] == [[1,2,3,4],[5,6,7,8],[9,10]]--- > partition_into_k  3 [1..11] == [[1,2,3,4],[5,6,7,8],[9,10,11]]--- > partition_into_k  3 [1..12] == [[1,2,3,4],[5,6,7,8],[9,10,11,12]]--- > partition_into_k  3 [1..13] == [[1,2,3,4,5],[6,7,8,9,10],[11,12,13]]-partition_into_k :: Int -> [a] -> [[a]]-partition_into_k k arr = partition_with_block_size block_size arr-    where-        block_size :: Int-        block_size = if (((length arr) `mod` k) == 0)-            then (length arr) `div` k-            else (length arr) `div` k + 1---- | /O(B(n))/, where /B(n)/ is the /n/^th <http://en.wikipedia.org/wiki/Bell_number Bell number>. Computes all partitions of the given list. For example,--- --- > powerpartition [1..3] == [[[1],[2],[3]], [[1,2],[3]], [[2],[1,3]], [[1],[2,3]], [[1,2,3]]]-powerpartition :: [a] -> [[[a]]]-powerpartition [] = []-powerpartition l@(x:xs) =-    if length l == 1-        then [[[x]]]-        else concatMap (get_next_partitions x) . powerpartition $ xs-        where-            get_next_partitions :: a -> [[a]] -> [[[a]]]-            get_next_partitions e l = ([e] : l) : (map f indices)-                where-                    f i = (a i) ++ (b i) ++ (c i)-                    -                    a i = ((take' i) l)-                    b i = [e : (l !! (fromInteger i))]-                    c i = (drop' (i+1) l)--                    indices = [0..((length' l) - 1)]---- --------------------------------------------------------------------- -- Operations with two lists  -- | Given two infinite sorted lists, generates a list of elements in the first but not the second. Implementation from <http://en.literateprograms.org/Sieve_of_Eratosthenes_(Haskell)>.@@ -355,7 +384,7 @@  -- | /(O(n))/ Returns a pair where the first element is identical to what `takeWhile` returns and the second element is the rest of the list -- --- > take_while_keep_last (<3) [1..] == [1,2,3]+-- > take_while_and_rest (<3) [1..10] == ([1,2],[3,4,5,6,7,8,9,10]) take_while_and_rest :: (a -> Bool) -> [a] -> ([a], [a]) take_while_and_rest f [] = ([], []) take_while_and_rest f l@(x:xs) = if not . f $ x@@ -364,6 +393,15 @@     where         rec = take_while_and_rest f xs +-- | /O(n)/ Like @Data.List.Find@, but returns a Maybe 2-tuple, instead, where the second element of the pair is the elements in the list after the first element of the pair.+--+-- > (find_and_rest ((==) 3) [1..10]) == Just (3, [4..10])+find_and_rest :: (a -> Bool) -> [a] -> Maybe (a, [a])+find_and_rest _ [] = Nothing+find_and_rest f (x:xs) = if f x+    then Just (x, xs)+    else find_and_rest f xs+ -- | /(O(n^2))/ Returns all contiguous subsequences. contiguous_subsequences :: [a] -> [[a]] contiguous_subsequences = (:) [] . concatMap (tail . List.inits) . List.tails@@ -372,7 +410,6 @@ subsequences :: [a] -> [[a]] subsequences = map reverse . powerset - -- --------------------------------------------------------------------- -- Sorting @@ -387,18 +424,14 @@         then l         else merge (mergesort a) (mergesort b)         where-            (a, b) = splitAt (floor ((fromIntegral $ length l) / 2)) l+            (a, b) = splitAt (((fromIntegral $ length l) `div` 2)) l  -- --------------------------------------------------------------------- -- Predicates --- TODO: O(n log(n))--- | /O(n^2)/ Returns whether the given list is a palindrome.+-- | /O(n)/ Returns whether the given list is a palindrome. is_palindrome :: (Eq e) => [e] -> Bool-is_palindrome s =-    if length s <= 1-        then True-        else (head s == last s) && (is_palindrome $ tail . init $ s)+is_palindrome l = l == (reverse l)  -- TODO: do this more monadically? -- | /O(n log(n))/ Returns whether the given list contains any element more than once.@@ -418,6 +451,121 @@ -- --------------------------------------------------------------------- -- Assorted functions +-- | /O(nlog(n))/ Counts the number of time each element appears in the given list. For example:+--+--  > elem_counts [1,2,1,4] == [(1,2),(2,1),(4,1)]+elem_counts :: (Ord a) => [a] -> [(a, Integer)]+elem_counts+    = map (\l -> (head l, length' l))+    . List.group+    . List.sort++-- | Shorthand for applicative functors:+--+--  > f <$*> l = f <$> l <*> l+(<$*>) :: Applicative f => (a -> a -> b) -> f a -> f b+f <$*> l = f <$> l <*> l++-- | /O(f log k)/, where k is the returnvalue, and f is the runtime of the input function on the lowest power of 2 above the returnvalue.+bsearch :: (Integer -> Ordering) -> Maybe Integer+bsearch f = bsearch' f lb ub+    where+        lb :: Integer+        lb+            = last+            . takeWhile (\n -> (f n) == LT)+            . map (\e -> 2^e)+            $ [1..]++        ub :: Integer+        ub = lb * 2++        bsearch' :: (Integer -> Ordering) -> Integer -> Integer -> Maybe Integer+        bsearch' f lb ub+            | (lb - ub <= 10)+                = List.find ((==) EQ . f)+                $ [lb..ub]+            | otherwise =+                case f curr of+                    LT -> bsearch' f curr ub+                    EQ -> Just curr+                    GT -> bsearch' f lb curr+                where+                    curr :: Integer+                    curr = (lb + ub) `div` 2++-- | /O(f log k)/, where k is the returnvalue, and f is the runtime of the input function on the lowest power of 2 above the returnvalue.+bsearch_1st_geq :: (Integer -> Ordering) -> Maybe Integer+bsearch_1st_geq f = bsearch_1st_geq' f lb ub+    where+        lb :: Integer+        lb+            = last+            . takeWhile (\n -> (f n) == LT)+            . map (\e -> 2^e)+            $ [1..]++        ub :: Integer+        ub = lb * 2++        bsearch_1st_geq' :: (Integer -> Ordering) -> Integer -> Integer -> Maybe Integer+        bsearch_1st_geq' f lb ub+            | (lb - ub <= 10)+                = List.find (\x -> ((==) EQ . f $ x) || ((==) GT . f $ x))+                $ [lb..ub]+            | otherwise =+                case f curr of+                    LT -> bsearch_1st_geq' f curr ub+                    EQ -> bsearch_1st_geq' f lb curr+                    GT -> bsearch_1st_geq' f lb curr+                where+                    curr :: Integer+                    curr = (lb + ub) `div` 2++-- | /O(n)/ Returns the noncontiguous sublist of elements greater than all previous elements. For example:+--+--   > running_bests [1,3,2,4,6,5] == [1,3,4,6]+running_bests :: forall a. (Ord a) => [a] -> [a]+running_bests = running_bests_by compare++-- | /O(n)/ Returns the noncontiguous sublist of elements greater than all previous elements, where "greater" is determined by the provided comparison function. For example:+--+--   > running_bests_by (Data.Ord.comparing length) [[1],[3,3,3],[2,2]] == [[1],[3,3,3]]+running_bests_by :: forall a. (Ord a) => (a -> a -> Ordering) -> [a] -> [a]+running_bests_by cmp [] = []+running_bests_by cmp (x:xs) = (:) x $ running_bests_by' xs x+    where+        running_bests_by' :: (Ord a) => [a] -> a -> [a]+        running_bests_by' [] _ = []+        running_bests_by' (x:xs) best_so_far = +            case best_so_far `cmp` x of+                LT -> x : (running_bests_by' xs x)+                EQ -> x : (running_bests_by' xs x)+                GT ->      running_bests_by' xs best_so_far++-- | /O(min(n, m))/ Interleaves elements from the two given lists of respective lengths `n` and `m` in an alternating fashion. For example:+--+--  > interleave [1,3,5,7] [2,4,6,8] == [1,2,3,4,5,6,7,8]+--+--  > interleave [1,3,5,7] [2,4,6] == [1,2,3,4,5,6,7]+--+--  > interleave [1,3,5] [2,4,6,8] == [1,2,3,4,5,6,8]+interleave :: [a] -> [a] -> [a]+interleave [] bs = bs+interleave as [] = as+interleave (a:as) (b:bs) = a : b : (interleave as bs)++-- /O(nf)/ Filters a list of length `n` leaving elemnts the indices of which satisfy the given predicate function, which has runtime `f`.+passing_index_elems :: (Int -> Bool) -> [a] -> [a]+passing_index_elems f+    = map snd+    . filter (f . fst)+    . zip [0..]++-- | /O(n)/ counts the number of elements in a list that satisfy a given predicate function.+count :: (a -> Bool) -> [a] -> Integer+count f = toInteger . length . filter f+ -- | /O(n)/ Maps the given function over the list while keeping the original list. For example: --  -- > map_keep chr [97..100] == [(97,'a'),(98,'b'),(99,'c'),(100,'d')]@@ -440,7 +588,9 @@ cons :: a -> [a] -> [a] cons = (:) --- | List post-pending.+-- | List appending.+--+--   > snoc 4 [1,2,3] == [1,2,3,4] snoc :: a -> [a] -> [a] snoc e l = l ++ [e] @@ -453,3 +603,53 @@ minimum_with_index :: (Ord a) => [a] -> (a, Integer) minimum_with_index xs =     List.minimumBy (Ord.comparing fst) (zip xs [0..])++-- | /O(n)/ Finds all minima of the given list by the given comparator function. For example,+--   > minima_by (Data.Ord.comparing length) [[1,2], [1], [3,3,3], [2]]+--   [[1], [2]]+minima_by :: (a -> a -> Ordering) -> [a] -> [a]+minima_by cmp [] = []+minima_by cmp (x:xs) = minima_by' cmp xs [x]+    where+        minima_by' :: (a -> a -> Ordering) -> [a] -> [a] -> [a]+        minima_by' _ [] so_far = so_far+        minima_by' cmp (x:xs) so_far =+            case x `cmp` (head so_far) of+                LT -> minima_by' cmp xs [x]+                EQ -> minima_by' cmp xs (x : so_far)+                GT -> minima_by' cmp xs so_far++-- ---------------------------------------------------------------------+-- Tuples++-- | Applies the given function to the first element of the tuple.+map_fst :: (a -> c) -> (a, b) -> (c, b)+map_fst = flip map_pair $ id++-- | Applies the given function to the second element of the tuple.+map_snd :: (b -> c) -> (a, b) -> (a, c)+map_snd = map_pair id++-- | Applies the given two functions to the respective first and second elements of the tuple.+map_pair :: (a -> c) -> (b -> d) -> (a, b) -> (c, d)+map_pair f g (a, b) = (f a, g b)++-- | Extracts the first element of a 3-tuple.+fst3 :: (a, b, c) -> a+fst3 (a, _, _) = a++-- | Extracts the second element of a 3-tuple.+snd3 :: (a, b, c) -> b+snd3 (_, b, _) = b++-- | Extracts the third element of a 3-tuple.+trd3 :: (a, b, c) -> c+trd3 (_, _, c) = c++-- | Applies the given binary function to both elements of the given tuple.+pair_op :: (a -> b -> c) -> (a, b) -> c+pair_op op (a, b) = op a b++-- | Applies the given ternary function to all three elements of the given tuple.+triple_op :: (a -> b -> c -> d) -> (a, b, c) -> d+triple_op op (a, b, c) = op a b c
Zora/Math.hs view
@@ -1,8 +1,8 @@ -- |--- Module      : Zora.Math+-- Module	  : Zora.Math -- Copyright   : (c) Brett Wines 2014 ----- License     : BSD-style+-- License	 : BSD-style -- -- Maintainer  : bgwines@cs.stanford.edu -- Stability   : experimental@@ -20,41 +20,47 @@ , euler_phi , factor , divisors+, num_divisors  -- * Square roots , irrational_squares , sqrt_convergents , continued_fraction_sqrt , continued_fraction_sqrt_infinite+, square  -- * Assorted functions+, fibs+, sqrt_perfect_square , is_int , is_power_of_int-, int_to_double+, double_to_int , num_digits , tri_area , tri_area_double ) where +import qualified Zora.List as ZList+ import qualified Data.List as List  import Data.Maybe -import Zora.List+import Control.Applicative  -- --------------------------------------------------------------------- -- Prime numbers and division  -- | A complete, monotonically increasing, infinite list of primes. Implementation from <http://en.literateprograms.org/Sieve_of_Eratosthenes_(Haskell)>. primes :: [Integer]-primes = [2, 3, 5] ++ (diff_infinite [7, 9 ..] composites)+primes = [2, 3, 5] ++ (ZList.diff_infinite [7, 9 ..] composites) --- | A complete, monotonically increa?ing, infinite list of composite numbers.+-- | A complete, monotonically increasing, infinite list of composite numbers. composites :: [Integer] composites = foldr1 f $ map g $ tail primes 	where 		f (x:xt) ys = x : (merge_infinite xt ys)-		g p		 = [ n * p | n <- [p, p + 2 ..]]+		g p = [ n * p | n <- [p, p + 2 ..]]  		merge_infinite :: (Ord a) => [a] -> [a] -> [a] 		merge_infinite xs@(x:xt) ys@(y:yt) = @@ -104,15 +110,57 @@ -- TODO: don't start over in `primes` -- | /O(k n log(n)^-1)/, where /k/ is the number of primes dividing /n/ (double-counting for powers). /n log(n)^-1/ is an approximation for <http://en.wikipedia.org/wiki/Prime-counting_function the number of primes below a number>. factor :: Integer -> [Integer]-factor 0 = []-factor 1 = []-factor n = p : factor (n `div` p)-	where p = fromJust . List.find (\p -> (n `mod` p) == 0) $ primes+factor = factor' primes +factor' :: [Integer] -> Integer -> [Integer]+factor' _ 0 = []+factor' _ 1 = []+factor' primes' n = (:) p $ factor' primes_rest (n `div` p)+	where+		p :: Integer+		primes_rest :: [Integer]+		(p, primes_rest)+			= fromJust+			. ZList.find_and_rest (\p -> (n `mod` p) == 0)+			$ primes++-- | /O(k n log(n)^-1)/, where /k/ is the number of primes dividing /n/ (double-counting for powers). /n log(n)^-1/ is an approximation for <http://en.wikipedia.org/wiki/Prime-counting_function the number of primes below a number>. Essentially, linear in the time it takes to factor the number.+num_divisors :: Integer -> Integer+num_divisors+	= pred+	. product+	. map (succ . snd) -- succ because p_i^0 is a valid choice+	. ZList.elem_counts+	. factor++-- TODO: provide better bound here -- | /O(4^(k n log(n)^-1))/, where /k/ is the number of primes dividing /n/ (double-counting for powers). divisors :: Integer -> [Integer]-divisors = init . uniqueify . map product . powerset . factor+divisors = factors_to_divisors . ZList.elem_counts . factor+	where+		factors_to_divisors :: [(Integer, Integer)] -> [Integer]+		factors_to_divisors+			= init+			. List.sort+			. map product+			. map (map (\(p, a) -> p^a))+			. factors_to_divisors_rec +		factors_to_divisors_rec :: [(Integer, Integer)] -> [[(Integer, Integer)]]+		factors_to_divisors_rec = map (filter ((/=) 0 . snd)) . factors_to_divisors_rec'++		factors_to_divisors_rec' :: [(Integer, Integer)] -> [[(Integer, Integer)]]+		factors_to_divisors_rec' [] = []+		factors_to_divisors_rec' ((p, a):[]) = [[(p, a')] | a' <- [0..a]]+		factors_to_divisors_rec' ((p, a):factors) =+			(:) <$> curr_pairs <*> recs+			where+				curr_pairs :: [(Integer, Integer)]+				curr_pairs = [(p, a') | a' <- [0..a]]++				recs :: [[(Integer, Integer)]]+				recs = factors_to_divisors_rec factors+ -- --------------------------------------------------------------------- -- Square roots @@ -164,14 +212,28 @@  -- | /O(k)/ The <http://en.wikipedia.org/wiki/Continued_fraction continued fraction> representation of the square root of the parameter. /k/ is the length of the continued fraction. continued_fraction_sqrt :: Integer -> [Integer]-continued_fraction_sqrt n =-	take_while_keep_last (/= (2 * a0)) . continued_fraction_sqrt_infinite $ n+continued_fraction_sqrt n+	= ZList.take_while_keep_last (/= (2 * a0))+	. continued_fraction_sqrt_infinite+	$ n 		where 			a0 = floor . sqrt . fromInteger $ n +-- | Determines whether the given integer is a square number.+square :: Integer -> Bool+square = is_int . sqrt . fromIntegral+ -- --------------------------------------------------------------------- -- Assorted functions +-- | An infinite list of the Fibonacci numbers.+fibs :: [Integer]+fibs = 1 : 1 : zipWith (+) fibs (tail fibs)++-- | Takes the square root of a perfect square.+sqrt_perfect_square :: Integer -> Integer+sqrt_perfect_square = toInteger . ceiling . sqrt . fromInteger+ -- | /O(1)/ Area of a triangle, where the parameters are the edge lengths (Heron's formula). tri_area :: Integer -> Integer -> Integer -> Double tri_area a b c = @@ -187,21 +249,21 @@ tri_area_double a b c =  	sqrt $ p * (p-a) * (p-b) * (p-c) 		where+			p :: Double 			p = (a + b + c) / 2 - -- | /O(1)/ Calculates whether /n/ is the /e/^th power of any integer, where /n/ is the first parameter and /e/ is the second. is_power_of_int :: Integer -> Integer -> Bool is_power_of_int n e = (round (fromIntegral n ** (1/(fromInteger e))))^e == n --- | /O(log_10(n))/ Calculates the number of digits in an integer.+-- | /O(log_10(n))/ Calculates the number of digits in an integer. Relies on @logBase@, so gives wrong answer for very large `n`. num_digits :: Integer -> Integer num_digits n = (1 + (floor $ logBase 10 (fromInteger n)))  -- | Returns whether a @Double@ value is an integer. For example, @16.0 :: Double@ is an integer, but not @16.1@. is_int :: Double -> Bool-is_int x = x == (fromInteger (round x))+is_int x = x == (fromInteger . round $ x)  -- | Converts a @Double@ to an @Integer@.-int_to_double :: Double -> Integer-int_to_double = (toInteger . round)+double_to_int :: Double -> Integer+double_to_int = (toInteger . round)