packages feed

apportionment 0.0.0.3 → 0.0.0.4

raw patch · 5 files changed

+199/−7 lines, 5 filesdep +QuickCheckdep +apportionmentdep +doctest-exitcode-stdiodep ~basedep ~containersPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: QuickCheck, apportionment, doctest-exitcode-stdio, doctest-lib

Dependency ranges changed: base, containers

API changes (from Hackage documentation)

- Math.Apportionment: highestAveragesScaled :: (RealFrac a) => [a] -> Int -> [a] -> [Int]
+ Math.Apportionment: highestAveragesScaled :: RealFrac a => [a] -> Int -> [a] -> [Int]
- Math.Apportionment: largestRemainder :: (RealFrac a) => [a] -> [Int]
+ Math.Apportionment: largestRemainder :: RealFrac a => [a] -> [Int]
- Math.Apportionment: largestRemainderScaled :: (RealFrac a) => Int -> [a] -> [Int]
+ Math.Apportionment: largestRemainderScaled :: RealFrac a => Int -> [a] -> [Int]

Files

+ Makefile view
@@ -0,0 +1,8 @@+run-test:	update-test+	runhaskell Setup configure --user --enable-tests+	runhaskell Setup build+	runhaskell Setup haddock+	runhaskell Setup test apportionment-test --show-details=streaming++update-test:+	doctest-extract-0.1 -i src/ -o test/ --import-tested --executable-main=Main.hs Math.Apportionment
apportionment.cabal view
@@ -1,12 +1,12 @@ Name:                apportionment-Version:             0.0.0.3+Version:             0.0.0.4 Synopsis:            Round a set of numbers while maintaining its sum Description:   Round a set of numbers while maintaining its sum.   According procedures are used to assign seats to parties in a parliament.   You may also use it to round percentages that sum up to 100%.   <https://en.wikipedia.org/wiki/Apportionment_(politics)>-Homepage:            http://hub.darcs.net/thielema/apportionment+Homepage:            https://hub.darcs.net/thielema/apportionment License:             BSD3 License-File:        LICENSE Author:              Henning Thielemann@@ -14,15 +14,17 @@ Category:            Math Build-Type:          Simple Cabal-Version:       >=1.10+Extra-Source-Files:+  Makefile  Source-Repository this-  Tag:         0.0.0.3+  Tag:         0.0.0.4   Type:        darcs-  Location:    http://hub.darcs.net/thielema/apportionment+  Location:    https://hub.darcs.net/thielema/apportionment  Source-Repository head   Type:        darcs-  Location:    http://hub.darcs.net/thielema/apportionment+  Location:    https://hub.darcs.net/thielema/apportionment  Library   Exposed-Modules:     Math.Apportionment@@ -33,3 +35,17 @@   Hs-Source-Dirs:      src   Default-Language:    Haskell2010   GHC-Options:         -Wall++Test-Suite apportionment-test+  Type:             exitcode-stdio-1.0+  Default-Language: Haskell2010+  GHC-Options:      -Wall+  Hs-source-dirs:   test+  Main-Is:          Main.hs+  Other-Modules:    Test.Math.Apportionment+  Build-Depends:+    apportionment,+    doctest-exitcode-stdio >=0.0 && <0.1,+    doctest-lib >=0.1 && <0.2,+    QuickCheck >=2 && <3,+    base
src/Math/Apportionment.hs view
@@ -18,6 +18,16 @@ import Data.Ord.HT (comparing, )  +{- $setup+>>> import Control.Applicative ((<$>))+>>> import qualified Test.QuickCheck as QC+>>>+>>> forAllNonNegatives ::+>>>    (Num a, Ord a, Show a, QC.Arbitrary a) => ([a] -> Bool) -> QC.Property+>>> forAllNonNegatives = QC.forAll $+>>>    (map QC.getNonNegative <$> QC.arbitrary) `QC.suchThat` (\xs -> sum xs > 0)+-}+ {- | Like 'largestRemainder' but result values are sorted with respect to descending fractional parts of the inputs.@@ -33,6 +43,12 @@           List.sortBy (comparing (negate.snd)) intFracs    in  map (1+) intUps ++ intDowns +-- ToDo: generalize to Traversable++-- ToDo: require NonEmpty++-- ToDo: It would be safer to use Integer+ {- | This function rounds values such that the sum of the rounded values@@ -42,6 +58,14 @@ <https://en.wikipedia.org/wiki/Largest_remainder_method>  Input values must be non-negative, otherwise 'properFraction' bites us.++>>> largestRemainder [1,2,3::Rational]+[1,2,3]+>>> largestRemainder [1.1,2.2,3.3,4.4::Rational]+[1,2,3,5]++prop> \xs -> xs == largestRemainder (map fromIntegral xs :: [Rational])+prop> forAllNonNegatives $ \xs -> round (sum xs) == sum (largestRemainder (xs :: [Rational])) -} largestRemainder :: (RealFrac a) => [a] -> [Int] largestRemainder = largestRemainderCore . fractions@@ -50,8 +74,16 @@ @largestRemainderScaled s xs@ scales and rounds the values in @xs@ such that their sum becomes @s@. -E.g. @largestRemainderScaled 100 [1,2,3]@-returns integral percentages proportional to 1:2:3.+>>> largestRemainderScaled 100 [1,2,3::Rational]+[17,33,50]++That is, it returns integral percentages almost proportional to 1:2:3.++>>> largestRemainderScaled 100 [1,10,100::Rational]+[1,9,90]++prop> forAllNonNegatives $ \xs -> xs == largestRemainderScaled (sum xs) (map fromIntegral xs :: [Rational])+prop> \(QC.Positive s) -> forAllNonNegatives $ \xs -> s == sum (largestRemainderScaled s (xs :: [Rational])) -} largestRemainderScaled :: (RealFrac a) => Int -> [a] -> [Int] largestRemainderScaled s = largestRemainderCore . fractionsScaled s@@ -89,6 +121,22 @@ In @highestAveragesScaled divs s xs@, @divs@ must be an infinite list of strictly increasing positive numbers. E.g. @highestAveragesScaled dHondtDivisors s xs@ runs the d'Hondt method.++>>> highestAveragesScaled dHondtDivisors 100 [1,2,3::Rational]+[17,33,50]+>>> highestAveragesScaled dHondtDivisors 100 [1,10,100::Rational]+[0,9,91]++>>> highestAveragesScaled sainteLagueDivisors 100 [1,2,3::Rational]+[17,33,50]+>>> highestAveragesScaled sainteLagueDivisors 100 [1,10,100::Rational]+[1,9,90]++prop> forAllNonNegatives $ \xs -> xs == highestAveragesScaled dHondtDivisors (sum xs) (map fromIntegral xs :: [Rational])+prop> forAllNonNegatives $ \xs -> xs == highestAveragesScaled sainteLagueDivisors (sum xs) (map fromIntegral xs :: [Rational])++prop> \(QC.Positive s) -> forAllNonNegatives $ \xs -> s == sum (highestAveragesScaled dHondtDivisors s (xs :: [Rational]))+prop> \(QC.Positive s) -> forAllNonNegatives $ \xs -> s == sum (highestAveragesScaled sainteLagueDivisors s (xs :: [Rational])) -} highestAveragesScaled :: (RealFrac a) => [a] -> Int -> [a] -> [Int] highestAveragesScaled divs s xs =@@ -98,6 +146,7 @@        take s $ Fold.foldl (ListHT.mergeBy (compose2 (>=) snd)) [] $        Map.mapWithKey (map . (,)) $ outerProduct (/) m divs +-- ToDo: use Stream dHondtDivisors :: Num a => [a] dHondtDivisors = iterate (1+) 1 
+ test/Main.hs view
@@ -0,0 +1,11 @@+-- Do not edit! Automatically created with doctest-extract.+module Main where++import qualified Test.Math.Apportionment+import qualified Test.QuickCheck as QC++import qualified Test.DocTest.Driver as DocTest++main :: IO ()+main = DocTest.runWith QC.stdArgs{QC.maxSuccess=3000} $ do+    Test.Math.Apportionment.test
+ test/Test/Math/Apportionment.hs view
@@ -0,0 +1,108 @@+-- Do not edit! Automatically created with doctest-extract from src/Math/Apportionment.hs+{-# LINE 21 "src/Math/Apportionment.hs" #-}++module Test.Math.Apportionment where++import Math.Apportionment+import Test.DocTest.Base+import qualified Test.DocTest.Driver as DocTest++{-# LINE 22 "src/Math/Apportionment.hs" #-}+import     Control.Applicative ((<$>))+import     qualified Test.QuickCheck as QC++forAllNonNegatives     ::+       (Num a, Ord a, Show a, QC.Arbitrary a) => ([a] -> Bool) -> QC.Property+forAllNonNegatives     = QC.forAll $+       (map QC.getNonNegative <$> QC.arbitrary) `QC.suchThat` (\xs -> sum xs > 0)++test :: DocTest.T ()+test = do+ DocTest.printPrefix "Math.Apportionment:67: "+{-# LINE 67 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 67 "src/Math/Apportionment.hs" #-}+     (\xs -> xs == largestRemainder (map fromIntegral xs :: [Rational]))+ DocTest.printPrefix "Math.Apportionment:68: "+{-# LINE 68 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 68 "src/Math/Apportionment.hs" #-}+     (forAllNonNegatives $ \xs -> round (sum xs) == sum (largestRemainder (xs :: [Rational])))+ DocTest.printPrefix "Math.Apportionment:62: "+{-# LINE 62 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 62 "src/Math/Apportionment.hs" #-}+   (largestRemainder [1,2,3::Rational])+  [ExpectedLine [LineChunk "[1,2,3]"]]+ DocTest.printPrefix "Math.Apportionment:64: "+{-# LINE 64 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 64 "src/Math/Apportionment.hs" #-}+   (largestRemainder [1.1,2.2,3.3,4.4::Rational])+  [ExpectedLine [LineChunk "[1,2,3,5]"]]+ DocTest.printPrefix "Math.Apportionment:85: "+{-# LINE 85 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 85 "src/Math/Apportionment.hs" #-}+     (forAllNonNegatives $ \xs -> xs == largestRemainderScaled (sum xs) (map fromIntegral xs :: [Rational]))+ DocTest.printPrefix "Math.Apportionment:86: "+{-# LINE 86 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 86 "src/Math/Apportionment.hs" #-}+     (\(QC.Positive s) -> forAllNonNegatives $ \xs -> s == sum (largestRemainderScaled s (xs :: [Rational])))+ DocTest.printPrefix "Math.Apportionment:77: "+{-# LINE 77 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 77 "src/Math/Apportionment.hs" #-}+   (largestRemainderScaled 100 [1,2,3::Rational])+  [ExpectedLine [LineChunk "[17,33,50]"]]+ DocTest.printPrefix "Math.Apportionment:82: "+{-# LINE 82 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 82 "src/Math/Apportionment.hs" #-}+   (largestRemainderScaled 100 [1,10,100::Rational])+  [ExpectedLine [LineChunk "[1,9,90]"]]+ DocTest.printPrefix "Math.Apportionment:135: "+{-# LINE 135 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 135 "src/Math/Apportionment.hs" #-}+     (forAllNonNegatives $ \xs -> xs == highestAveragesScaled dHondtDivisors (sum xs) (map fromIntegral xs :: [Rational]))+ DocTest.printPrefix "Math.Apportionment:136: "+{-# LINE 136 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 136 "src/Math/Apportionment.hs" #-}+     (forAllNonNegatives $ \xs -> xs == highestAveragesScaled sainteLagueDivisors (sum xs) (map fromIntegral xs :: [Rational]))+ DocTest.printPrefix "Math.Apportionment:138: "+{-# LINE 138 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 138 "src/Math/Apportionment.hs" #-}+     (\(QC.Positive s) -> forAllNonNegatives $ \xs -> s == sum (highestAveragesScaled dHondtDivisors s (xs :: [Rational])))+ DocTest.printPrefix "Math.Apportionment:139: "+{-# LINE 139 "src/Math/Apportionment.hs" #-}+ DocTest.property+{-# LINE 139 "src/Math/Apportionment.hs" #-}+     (\(QC.Positive s) -> forAllNonNegatives $ \xs -> s == sum (highestAveragesScaled sainteLagueDivisors s (xs :: [Rational])))+ DocTest.printPrefix "Math.Apportionment:125: "+{-# LINE 125 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 125 "src/Math/Apportionment.hs" #-}+   (highestAveragesScaled dHondtDivisors 100 [1,2,3::Rational])+  [ExpectedLine [LineChunk "[17,33,50]"]]+ DocTest.printPrefix "Math.Apportionment:127: "+{-# LINE 127 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 127 "src/Math/Apportionment.hs" #-}+   (highestAveragesScaled dHondtDivisors 100 [1,10,100::Rational])+  [ExpectedLine [LineChunk "[0,9,91]"]]+ DocTest.printPrefix "Math.Apportionment:130: "+{-# LINE 130 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 130 "src/Math/Apportionment.hs" #-}+   (highestAveragesScaled sainteLagueDivisors 100 [1,2,3::Rational])+  [ExpectedLine [LineChunk "[17,33,50]"]]+ DocTest.printPrefix "Math.Apportionment:132: "+{-# LINE 132 "src/Math/Apportionment.hs" #-}+ DocTest.example+{-# LINE 132 "src/Math/Apportionment.hs" #-}+   (highestAveragesScaled sainteLagueDivisors 100 [1,10,100::Rational])+  [ExpectedLine [LineChunk "[1,9,90]"]]