forked from haskell/random
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix quality and performance issues, add monadic API
This patch is mostly backwards compatible. See "Breaking Changes" below for the full list of backwards incompatible changes. This patch fixes quality and performance issues, addresses additional miscellaneous issues, and introduces a monadic API. Issues addressed ================ Priority issues fixed in this patch: - Title: "The seeds generated by split are not independent" Link: haskell#25 Fixed: changed algorithm to SplitMix, which provides a robust 'split' operation - Title: "Very low throughput" Link: haskell#51 Fixed: see "Performance" below Additional issues addressed in this patch: - Title: "Add Random instances for tuples" Link: haskell#26 Addressed: added 'Uniform' instances for up to 6-tuples - Title: "Add Random instance for Natural" Link: haskell#44 Addressed: added 'UniformRange' instance for 'Natural' - Title: "incorrect distribution of randomR for floating-point numbers" Link: haskell#53 Addressed: see "Regarding floating-point numbers" below - Title: "System/Random.hs:43:1: warning: [-Wtabs]" Link: haskell#55 Fixed: no more tabs - Title: "Why does random for Float and Double produce exactly 24 or 53 bits?" Link: haskell#58 Fixed: see "Regarding floating-point numbers" below - Title: "read :: StdGen fails for strings longer than 6" Link: haskell#59 Addressed: 'StdGen' is no longer an instance of 'Read' Regarding floating-point numbers: with this patch, the relevant instances for 'Float' and 'Double' sample more bits than before but do not sample every possible representable value. The documentation now clearly spells out what this means for users. Quality (issue 25) ================== The algorithm [1] in version 1.1 of this library fails empirical PRNG tests when used to generate "split sequences" as proposed in [3]. SplitMix [2] passes the same tests. This patch changes 'StdGen' to use the SplitMix implementation provided by the splitmix package. Test batteries used: dieharder, TestU1, PractRand. [1]: P. L'Ecuyer, "Efficient and portable combined random number generators". https://doi.org/10.1145/62959.62969 [2]: G. L. Steele, D. Lea, C. H. Flood, "Fast splittable pseudorandom number generators". https://doi.org/10.1145/2714064.2660195 [3]: H. G. Schaathun, "Evaluation of splittable pseudo-random generators". https://doi.org/10.1017/S095679681500012X Performance (issue 51) ====================== The "improvement" column in the following table is a multiplier: the improvement for 'random' for type 'Float' is 1038, so this operation is 1038 times faster with this patch. | Name | Mean (1.1) | Mean (patch) | Improvement| | ----------------------- | ---------- | ------------ | ---------- | | pure/random/Float | 30 | 0.03 | 1038| | pure/random/Double | 52 | 0.03 | 1672| | pure/random/Integer | 43 | 0.33 | 131| | pure/uniform/Word8 | 14 | 0.03 | 422| | pure/uniform/Word16 | 13 | 0.03 | 375| | pure/uniform/Word32 | 21 | 0.03 | 594| | pure/uniform/Word64 | 42 | 0.03 | 1283| | pure/uniform/Word | 44 | 0.03 | 1491| | pure/uniform/Int8 | 15 | 0.03 | 511| | pure/uniform/Int16 | 15 | 0.03 | 507| | pure/uniform/Int32 | 22 | 0.03 | 749| | pure/uniform/Int64 | 44 | 0.03 | 1405| | pure/uniform/Int | 43 | 0.03 | 1512| | pure/uniform/Char | 17 | 0.49 | 35| | pure/uniform/Bool | 18 | 0.03 | 618| | pure/uniform/CChar | 14 | 0.03 | 485| | pure/uniform/CSChar | 14 | 0.03 | 455| | pure/uniform/CUChar | 13 | 0.03 | 448| | pure/uniform/CShort | 14 | 0.03 | 473| | pure/uniform/CUShort | 13 | 0.03 | 457| | pure/uniform/CInt | 21 | 0.03 | 737| | pure/uniform/CUInt | 21 | 0.03 | 742| | pure/uniform/CLong | 43 | 0.03 | 1544| | pure/uniform/CULong | 42 | 0.03 | 1460| | pure/uniform/CPtrdiff | 43 | 0.03 | 1494| | pure/uniform/CSize | 43 | 0.03 | 1475| | pure/uniform/CWchar | 22 | 0.03 | 785| | pure/uniform/CSigAtomic | 21 | 0.03 | 749| | pure/uniform/CLLong | 43 | 0.03 | 1554| | pure/uniform/CULLong | 42 | 0.03 | 1505| | pure/uniform/CIntPtr | 43 | 0.03 | 1476| | pure/uniform/CUIntPtr | 42 | 0.03 | 1463| | pure/uniform/CIntMax | 43 | 0.03 | 1535| | pure/uniform/CUIntMax | 42 | 0.03 | 1493| API changes =========== StatefulGen ----------- This patch adds a class 'StatefulGen': -- | 'StatefulGen' is an interface to monadic pseudo-random number generators. class Monad m => StatefulGen g m where uniformWord32 :: g -> m Word32 -- default implementation in terms of uniformWord64 uniformWord64 :: g -> m Word64 -- default implementation in terms of uniformWord32 -- plus methods for other word sizes and for byte strings -- all have default implementations so the MINIMAL pragma holds In 'StatefulGen g m', 'g' is the type of the generator and 'm' the underlying monad. Four 'StatefulGen' instances ("monadic adapters") are provided for pure generators to enable their use in monadic code. The documentation describes them in detail. FrozenGen --------- This patch also introduces a class 'FrozenGen': -- | 'FrozenGen' is designed for stateful pseudo-random number generators -- that can be saved as and restored from an immutable data type. class StatefulGen (MutableGen f m) m => FrozenGen f m where type MutableGen f m = (g :: Type) | g -> f freezeGen :: MutableGen f m -> m f thawGen :: f -> m (MutableGen f m) 'f' is the type of the generator's state "at rest" and 'm' the underlying monad. 'MutableGen' is defined as an injective type family via 'g -> f' so for any generator 'g', the type 'f' of its at-rest state is well-defined. Both 'StatefulGen' and 'FrozenGen' are generic enough to accommodate, for example, the 'Gen' type from the 'mwc-random' package, which itself abstracts over the underlying primitive monad and state token. The documentation shows the full instances. 'Uniform' and 'UniformRange' ---------------------------- The 'Random' typeclass has conceptually been split into 'Uniform' and 'UniformRange'. The 'Random' typeclass is still included for backwards compatibility. 'Uniform' is for types where it is possible to sample from the type's entire domain; 'UniformRange' is for types where one can sample from a specified range. Breaking Changes ================ This patch introduces these breaking changes: * requires 'base >= 4.10' (GHC-8.2) * 'StdGen' is no longer an instance of 'Read' * 'randomIO' and 'randomRIO' where extracted from the 'Random' class into separate functions In addition, there may be import clashes with new functions, e.g. 'uniform' and 'uniformR'. Deprecations ============ This patch introduces 'genWord64', 'genWord32' and similar methods to the 'RandomGen' class. The significantly slower method 'next' and its companion 'genRange' are now deprecated. Co-authored-by: Alexey Kuleshevich <[email protected]> Co-authored-by: idontgetoutmuch <[email protected]> Co-authored-by: Leonhard Markert <[email protected]>
1 parent
cfdfe6f
commit 64fa9bb
Showing
38 changed files
with
3,930 additions
and
1,576 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,3 @@ | ||
*~ | ||
|
||
Thumbs.db | ||
.DS_Store | ||
|
||
GNUmakefile | ||
dist-install/ | ||
ghc.mk | ||
|
||
dist | ||
.cabal-sandbox | ||
cabal.sandbox.config | ||
stack.yaml.lock | ||
.stack-work/ | ||
cabal.project.local |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,192 @@ | ||
language: haskell | ||
ghc: | ||
- 7.4 | ||
- 7.6 | ||
- 7.8 | ||
# This Travis job script has been generated by a script via | ||
# | ||
# haskell-ci '--travis-patches' '.travis.yml.patch' 'random.cabal' | ||
# | ||
# To regenerate the script (for example after adjusting tested-with) run | ||
# | ||
# haskell-ci regenerate | ||
# | ||
# For more information, see https://github.com/haskell-CI/haskell-ci | ||
# | ||
# version: 0.10 | ||
# | ||
version: ~> 1.0 | ||
language: c | ||
os: linux | ||
dist: xenial | ||
git: | ||
# whether to recursively clone submodules | ||
submodules: false | ||
cache: | ||
directories: | ||
- $HOME/.cabal/packages | ||
- $HOME/.cabal/store | ||
- $HOME/.hlint | ||
- $HOME/.stack | ||
- $TRAVIS_BUILD_DIR/.stack-work | ||
before_cache: | ||
- rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log | ||
# remove files that are regenerated by 'cabal update' | ||
- rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.* | ||
- rm -fv $CABALHOME/packages/hackage.haskell.org/*.json | ||
- rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache | ||
- rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar | ||
- rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx | ||
- rm -rfv $CABALHOME/packages/head.hackage | ||
jobs: | ||
include: | ||
- compiler: ghc-8.10.1 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.8.2 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.2","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.8.1 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.1","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.6.5 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}} | ||
env: COVERALLS_STACK_YAML="stack-coveralls.yaml" | ||
os: linux | ||
- compiler: ghc-8.6.4 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.6.3 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.3","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.4.4 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.4.3 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.3","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.2.2 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-8.0.2 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-7.10.3 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2"]}} | ||
os: linux | ||
- compiler: ghc-7.10.2 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.2","cabal-install-3.2"]}} | ||
os: linux | ||
before_install: | ||
- HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//') | ||
- WITHCOMPILER="-w $HC" | ||
- HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//') | ||
- HCPKG="$HC-pkg" | ||
- unset CC | ||
- CABAL=/opt/ghc/bin/cabal | ||
- CABALHOME=$HOME/.cabal | ||
- export PATH="$CABALHOME/bin:$PATH" | ||
- TOP=$(pwd) | ||
- "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')" | ||
- echo $HCNUMVER | ||
- CABAL="$CABAL -vnormal+nowrap" | ||
- set -o pipefail | ||
- TEST=--enable-tests | ||
- BENCH=--enable-benchmarks | ||
- HEADHACKAGE=false | ||
- rm -f $CABALHOME/config | ||
- | | ||
echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config | ||
echo "remote-build-reporting: anonymous" >> $CABALHOME/config | ||
echo "write-ghc-environment-files: always" >> $CABALHOME/config | ||
echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config | ||
echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config | ||
echo "world-file: $CABALHOME/world" >> $CABALHOME/config | ||
echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config | ||
echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config | ||
echo "installdir: $CABALHOME/bin" >> $CABALHOME/config | ||
echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config | ||
echo "store-dir: $CABALHOME/store" >> $CABALHOME/config | ||
echo "install-dirs user" >> $CABALHOME/config | ||
echo " prefix: $CABALHOME" >> $CABALHOME/config | ||
echo "repository hackage.haskell.org" >> $CABALHOME/config | ||
echo " url: http://hackage.haskell.org/" >> $CABALHOME/config | ||
# Download and unpack the stack executable | ||
- mkdir -p ~/.local/bin | ||
- | | ||
if [ -n "${COVERALLS_STACK_YAML}" ]; then | ||
if [ `uname` = "Darwin" ] | ||
then | ||
travis_retry curl --insecure -L https://get.haskellstack.org/stable/osx-x86_64.tar.gz | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin | ||
else | ||
travis_retry curl -L https://get.haskellstack.org/stable/linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' | ||
fi | ||
fi | ||
install: | ||
- ${CABAL} --version | ||
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]" | ||
- | | ||
echo "program-default-options" >> $CABALHOME/config | ||
echo " ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config | ||
- cat $CABALHOME/config | ||
- rm -fv cabal.project cabal.project.local cabal.project.freeze | ||
- travis_retry ${CABAL} v2-update -v | ||
# Generate cabal.project | ||
- rm -rf cabal.project cabal.project.local cabal.project.freeze | ||
- touch cabal.project | ||
- | | ||
echo "packages: ." >> cabal.project | ||
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package random' >> cabal.project ; fi | ||
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi" | ||
- | | ||
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(random)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done" | ||
- cat cabal.project || true | ||
- cat cabal.project.local || true | ||
- if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi | ||
- ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH} | ||
- "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'" | ||
- rm cabal.project.freeze | ||
- travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all | ||
- travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all | ||
script: | ||
- DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) | ||
# Coverage | ||
- | | ||
if [ -n "${COVERALLS_STACK_YAML}" ]; then | ||
stack --stack-yaml $COVERALLS_STACK_YAML test --coverage | ||
stack --stack-yaml $COVERALLS_STACK_YAML hpc report --all | ||
travis_retry curl -L https://github.com/lehins/stack-hpc-coveralls/releases/download/0.0.5.0/shc.tar.gz | tar xz shc | ||
STACK_YAML="$COVERALLS_STACK_YAML" ./shc combined custom | ||
fi | ||
# Packaging... | ||
- ${CABAL} v2-sdist all | ||
# Unpacking... | ||
- mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/ | ||
- cd ${DISTDIR} || false | ||
- find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \; | ||
- find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \; | ||
- PKGDIR_random="$(find . -maxdepth 1 -type d -regex '.*/random-[0-9.]*')" | ||
# Generate cabal.project | ||
- rm -rf cabal.project cabal.project.local cabal.project.freeze | ||
- touch cabal.project | ||
- | | ||
echo "packages: ${PKGDIR_random}" >> cabal.project | ||
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package random' >> cabal.project ; fi | ||
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi" | ||
- | | ||
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(random)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done" | ||
- cat cabal.project || true | ||
- cat cabal.project.local || true | ||
# Building... | ||
# this builds all libraries and executables (without tests/benchmarks) | ||
- ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | ||
# Building with tests and benchmarks... | ||
# build & run tests, build benchmarks | ||
- ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all | ||
# Testing... | ||
- ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all | ||
# cabal check... | ||
- (cd ${PKGDIR_random} && ${CABAL} -vnormal check) | ||
# haddock... | ||
- ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all | ||
# Building without installed constraints for packages in global-db... | ||
- rm -f cabal.project.local | ||
- ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | ||
|
||
# REGENDATA ("0.10",["--travis-patches",".travis.yml.patch","random.cabal"]) | ||
# EOF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
@@ -22,6 +22,8 @@ cache: | ||
- $HOME/.cabal/packages | ||
- $HOME/.cabal/store | ||
- $HOME/.hlint | ||
+ - $HOME/.stack | ||
+ - $TRAVIS_BUILD_DIR/.stack-work | ||
before_cache: | ||
- rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log | ||
# remove files that are regenerated by 'cabal update' | ||
@@ -44,6 +49,7 @@ jobs: | ||
os: linux | ||
- compiler: ghc-8.6.5 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}} | ||
+ env: COVERALLS_STACK_YAML="stack-coveralls.yaml" | ||
os: linux | ||
- compiler: ghc-8.6.4 | ||
addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.4","cabal-install-3.2"]}} | ||
@@ -103,6 +109,17 @@ before_install: | ||
echo " prefix: $CABALHOME" >> $CABALHOME/config | ||
echo "repository hackage.haskell.org" >> $CABALHOME/config | ||
echo " url: http://hackage.haskell.org/" >> $CABALHOME/config | ||
+ # Download and unpack the stack executable | ||
+ - mkdir -p ~/.local/bin | ||
+ - | | ||
+ if [ -n "${COVERALLS_STACK_YAML}" ]; then | ||
+ if [ `uname` = "Darwin" ] | ||
+ then | ||
+ travis_retry curl --insecure -L https://get.haskellstack.org/stable/osx-x86_64.tar.gz | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin | ||
+ else | ||
+ travis_retry curl -L https://get.haskellstack.org/stable/linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' | ||
+ fi | ||
+ fi | ||
install: | ||
- ${CABAL} --version | ||
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]" | ||
@@ -131,6 +148,14 @@ install: | ||
- travis_wait 40 ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all | ||
script: | ||
- DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) | ||
+ # Coverage | ||
+ - | | ||
+ if [ -n "${COVERALLS_STACK_YAML}" ]; then | ||
+ stack --stack-yaml $COVERALLS_STACK_YAML test --coverage | ||
+ stack --stack-yaml $COVERALLS_STACK_YAML hpc report --all | ||
+ travis_retry curl -L https://github.com/lehins/stack-hpc-coveralls/releases/download/0.0.5.0/shc.tar.gz | tar xz shc | ||
+ STACK_YAML="$COVERALLS_STACK_YAML" ./shc combined custom | ||
+ fi | ||
# Packaging... | ||
- ${CABAL} v2-sdist all | ||
# Unpacking... |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
module Main (main) where | ||
|
||
import Distribution.Simple | ||
|
||
main :: IO () | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
|
||
{- | ||
Binary search over benchmark input sizes. | ||
There are many good ways to measure the time it takes to perform a | ||
certain computation on a certain input. However, frequently, it's | ||
challenging to pick the right input size for all platforms and all | ||
compilataion modes. | ||
Sometimes for linear-complexity benchmarks it is better to measure | ||
/throughput/, i.e. elements processed per second. That is, fixing | ||
the time of execution and measuring the amount of work done (rather | ||
than the reverse). This library provides a simple way to search for | ||
an appropriate input size that results in the desired execution time. | ||
An alternative approach is to kill the computation after a certain | ||
amount of time and observe how much work it has completed. | ||
-} | ||
module BinSearch | ||
( | ||
binSearch | ||
) | ||
where | ||
|
||
import Control.Monad | ||
import Data.Time.Clock -- Not in 6.10 | ||
import Data.List | ||
import System.IO | ||
import Prelude hiding (min,max,log) | ||
|
||
|
||
|
||
-- | Binary search for the number of inputs to a computation that | ||
-- results in a specified amount of execution time in seconds. For example: | ||
-- | ||
-- > binSearch verbose N (min,max) kernel | ||
-- | ||
-- ... will find the right input size that results in a time | ||
-- between min and max, then it will then run for N trials and | ||
-- return the median (input,time-in-seconds) pair. | ||
binSearch :: Bool -> Integer -> (Double,Double) -> (Integer -> IO ()) -> IO (Integer, Double) | ||
binSearch verbose trials (min, max) kernel = do | ||
when verbose $ | ||
putStrLn $ | ||
"[binsearch] Binary search for input size resulting in time in range " ++ | ||
show (min, max) | ||
let desired_exec_length = 1.0 | ||
good_trial t = | ||
(toRational t <= toRational max) && (toRational t >= toRational min) | ||
-- At some point we must give up... | ||
loop n | ||
| n > ((2 :: Integer) ^ (100 :: Integer)) = | ||
error | ||
"ERROR binSearch: This function doesn't seem to scale in proportion to its last argument." | ||
-- Not allowed to have "0" size input, bump it back to one: | ||
loop 0 = loop 1 | ||
loop n = do | ||
when verbose $ putStr $ "[binsearch:" ++ show n ++ "] " | ||
time <- timeit $ kernel n | ||
when verbose $ putStrLn $ "Time consumed: " ++ show time | ||
let rate = fromIntegral n / time | ||
-- [2010.06.09] Introducing a small fudge factor to help our guess get over the line: | ||
let initial_fudge_factor = 1.10 | ||
fudge_factor = 1.01 -- Even in the steady state we fudge a little | ||
guess = desired_exec_length * rate | ||
-- TODO: We should keep more history here so that we don't re-explore input space we | ||
-- have already explored. This is a balancing act because of randomness in | ||
-- execution time. | ||
if good_trial time | ||
then do | ||
when verbose $ | ||
putStrLn | ||
"[binsearch] Time in range. LOCKING input size and performing remaining trials." | ||
print_trial 1 n time | ||
lockin (trials - 1) n [time] | ||
else if time < 0.100 | ||
then loop (2 * n) | ||
else do | ||
when verbose $ | ||
putStrLn $ | ||
"[binsearch] Estimated rate to be " ++ | ||
show (round rate :: Integer) ++ | ||
" per second. Trying to scale up..." | ||
-- Here we've exited the doubling phase, but we're making our | ||
-- first guess as to how big a real execution should be: | ||
if time > 0.100 && time < 0.33 * desired_exec_length | ||
then do | ||
when verbose $ | ||
putStrLn | ||
"[binsearch] (Fudging first guess a little bit extra)" | ||
loop (round $ guess * initial_fudge_factor) | ||
else loop (round $ guess * fudge_factor) | ||
-- Termination condition: Done with all trials. | ||
lockin 0 n log = do | ||
when verbose $ | ||
putStrLn $ | ||
"[binsearch] Time-per-unit for all trials: " ++ | ||
concat | ||
(intersperse " " (map (show . (/ toDouble n) . toDouble) $ sort log)) | ||
return (n, log !! (length log `quot` 2)) -- Take the median | ||
lockin trials_left n log = do | ||
when verbose $ | ||
putStrLn | ||
"[binsearch]------------------------------------------------------------" | ||
time <- timeit $ kernel n | ||
-- hFlush stdout | ||
print_trial (trials - trials_left + 1) n time | ||
-- whenverbose$ hFlush stdout | ||
lockin (trials_left - 1) n (time : log) | ||
print_trial :: Integer -> Integer -> NominalDiffTime -> IO () | ||
print_trial trialnum n time = | ||
let rate = fromIntegral n / time | ||
timeperunit = time / fromIntegral n | ||
in when verbose $ | ||
putStrLn $ | ||
"[binsearch] TRIAL: " ++ | ||
show trialnum ++ | ||
" secPerUnit: " ++ | ||
showTime timeperunit ++ | ||
" ratePerSec: " ++ show rate ++ " seconds: " ++ showTime time | ||
(n, t) <- loop 1 | ||
return (n, fromRational $ toRational t) | ||
|
||
|
||
showTime :: NominalDiffTime -> String | ||
showTime t = show ((fromRational $ toRational t) :: Double) | ||
|
||
toDouble :: Real a => a -> Double | ||
toDouble = fromRational . toRational | ||
|
||
|
||
-- Could use cycle counters here.... but the point of this is to time | ||
-- things on the order of a second. | ||
timeit :: IO () -> IO NominalDiffTime | ||
timeit io = do | ||
strt <- getCurrentTime | ||
io | ||
end <- getCurrentTime | ||
return (diffUTCTime end strt) | ||
{- | ||
test :: IO (Integer,Double) | ||
test = | ||
binSearch True 3 (1.0, 1.05) | ||
(\n -> | ||
do v <- newIORef 0 | ||
forM_ [1..n] $ \i -> do | ||
old <- readIORef v | ||
writeIORef v (old+i)) | ||
-} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
{-# LANGUAGE BangPatterns, ScopedTypeVariables, ForeignFunctionInterface #-} | ||
{-# OPTIONS_GHC -fwarn-unused-imports #-} | ||
|
||
-- | A simple script to do some very basic timing of the RNGs. | ||
|
||
module Main where | ||
|
||
import System.Exit (exitSuccess, exitFailure) | ||
import System.Environment | ||
import System.Random | ||
import System.CPUTime (getCPUTime) | ||
import System.CPUTime.Rdtsc | ||
import System.Console.GetOpt | ||
|
||
import GHC.Conc | ||
import Control.Concurrent | ||
import Control.Monad | ||
import Control.Exception | ||
|
||
import Data.IORef | ||
import Data.Word | ||
import Data.List hiding (last,sum) | ||
import Data.Int | ||
import Data.List.Split hiding (split) | ||
import Text.Printf | ||
|
||
import Foreign.Ptr | ||
import Foreign.C.Types | ||
import Foreign.ForeignPtr | ||
import Foreign.Storable (peek,poke) | ||
|
||
import Prelude hiding (last,sum) | ||
import BinSearch | ||
|
||
---------------------------------------------------------------------------------------------------- | ||
-- Miscellaneous helpers: | ||
|
||
-- Readable large integer printing: | ||
commaint :: Show a => a -> String | ||
commaint n = reverse $ concat $ intersperse "," $ chunk 3 $ reverse (show n) | ||
|
||
padleft :: Int -> String -> String | ||
padleft n str | length str >= n = str | ||
padleft n str | otherwise = take (n - length str) (repeat ' ') ++ str | ||
|
||
padright :: Int -> String -> String | ||
padright n str | length str >= n = str | ||
padright n str | otherwise = str ++ take (n - length str) (repeat ' ') | ||
|
||
fmt_num :: (RealFrac a, PrintfArg a) => a -> String | ||
fmt_num n = | ||
if n < 100 | ||
then printf "%.2f" n | ||
else commaint (round n :: Integer) | ||
|
||
|
||
-- Measure clock frequency, spinning rather than sleeping to try to | ||
-- stay on the same core. | ||
measureFreq :: IO Int64 | ||
measureFreq = do | ||
let second = 1000 * 1000 * 1000 * 1000 -- picoseconds are annoying | ||
t1 <- rdtsc | ||
start <- getCPUTime | ||
let loop !n !last = do | ||
t2 <- rdtsc | ||
when (t2 < last) $ putStrLn $ "COUNTERS WRAPPED " ++ show (last, t2) | ||
cput <- getCPUTime | ||
if cput - start < second | ||
then loop (n + 1) t2 | ||
else return (n, t2) | ||
(n, t2) <- loop 0 t1 | ||
putStrLn $ " Approx getCPUTime calls per second: " ++ commaint (n :: Int64) | ||
when (t2 < t1) $ | ||
putStrLn $ | ||
"WARNING: rdtsc not monotonically increasing, first " ++ | ||
show t1 ++ " then " ++ show t2 ++ " on the same OS thread" | ||
return $ fromIntegral (t2 - t1) | ||
|
||
---------------------------------------------------------------------------------------------------- | ||
|
||
-- Test overheads without actually generating any random numbers: | ||
data NoopRNG = NoopRNG | ||
instance RandomGen NoopRNG where | ||
next g = (0, g) | ||
genRange _ = (0, 0) | ||
split g = (g, g) | ||
|
||
-- An RNG generating only 0 or 1: | ||
data BinRNG = BinRNG StdGen | ||
instance RandomGen BinRNG where | ||
next (BinRNG g) = (x `mod` 2, BinRNG g') | ||
where | ||
(x, g') = next g | ||
genRange _ = (0, 1) | ||
split (BinRNG g) = (BinRNG g1, BinRNG g2) | ||
where | ||
(g1, g2) = split g | ||
|
||
|
||
---------------------------------------------------------------------------------------------------- | ||
-- Drivers to get random numbers repeatedly. | ||
|
||
type Kern = Int -> Ptr Int -> IO () | ||
|
||
-- [2011.01.28] Changing this to take "count" and "accumulator ptr" as arguments: | ||
-- foreign import ccall "cbits/c_test.c" blast_rands :: Kern | ||
-- foreign import ccall "cbits/c_test.c" store_loop :: Kern | ||
-- foreign import ccall unsafe "stdlib.hs" rand :: IO Int | ||
|
||
{-# INLINE timeit #-} | ||
timeit :: (Random a, RandomGen g) => Int -> Int64 -> String -> g -> (g -> (a,g)) -> IO () | ||
timeit numthreads freq msg gen nxt = do | ||
counters <- forM [1 .. numthreads] (const $ newIORef (1 :: Int64)) | ||
tids <- forM counters $ \counter -> forkIO $ infloop counter (nxt gen) | ||
threadDelay (1000 * 1000) -- One second | ||
mapM_ killThread tids | ||
finals <- mapM readIORef counters | ||
let mean :: Double = | ||
fromIntegral (foldl1 (+) finals) / fromIntegral numthreads | ||
cycles_per :: Double = fromIntegral freq / mean | ||
printResult (round mean :: Int64) msg cycles_per | ||
where | ||
infloop !counter (!_, !g) = do | ||
incr counter | ||
infloop counter (nxt g) | ||
incr !counter | ||
-- modifyIORef counter (+1) -- Not strict enough! | ||
= do | ||
c <- readIORef counter | ||
let c' = c + 1 | ||
_ <- evaluate c' | ||
writeIORef counter c' | ||
|
||
|
||
-- This function times an IO function on one or more threads. Rather | ||
-- than running a fixed number of iterations, it uses a binary search | ||
-- to find out how many iterations can be completed in a second. | ||
timeit_foreign :: Int -> Int64 -> String -> (Int -> Ptr Int -> IO ()) -> IO Int64 | ||
timeit_foreign numthreads freq msg ffn = do | ||
ptr :: ForeignPtr Int <- mallocForeignPtr | ||
let kern = | ||
if numthreads == 1 | ||
then ffn | ||
else replicate_kernel numthreads ffn | ||
wrapped n = withForeignPtr ptr (kern $ fromIntegral n) | ||
(n, t) <- binSearch False 1 (1.0, 1.05) wrapped | ||
let total_per_second = round $ fromIntegral n * (1 / t) | ||
cycles_per = fromIntegral freq * t / fromIntegral n | ||
printResult total_per_second msg cycles_per | ||
return total_per_second | ||
-- This lifts a C kernel to operate simultaneously on N threads. | ||
where | ||
replicate_kernel :: Int -> Kern -> Kern | ||
replicate_kernel nthreads kern n ptr = do | ||
ptrs <- forM [1 .. nthreads] (const mallocForeignPtr) | ||
tmpchan <- newChan | ||
-- let childwork = ceiling$ fromIntegral n / fromIntegral nthreads | ||
let childwork = n -- Keep it the same.. interested in per-thread throughput. | ||
-- Fork/join pattern: | ||
forM_ ptrs $ \pt -> | ||
forkIO $ | ||
withForeignPtr pt $ \p -> do | ||
kern (fromIntegral childwork) p | ||
result <- peek p | ||
writeChan tmpchan result | ||
results <- forM [1 .. nthreads] $ \_ -> readChan tmpchan | ||
-- Meaningless semantics here... sum the child ptrs and write to the input one: | ||
poke ptr (foldl1 (+) results) | ||
|
||
|
||
printResult :: Int64 -> String -> Double -> IO () | ||
printResult total msg cycles_per = | ||
putStrLn $ | ||
" " ++ | ||
padleft 11 (commaint total) ++ | ||
" randoms generated " ++ | ||
padright 27 ("[" ++ msg ++ "]") ++ | ||
" ~ " ++ fmt_num cycles_per ++ " cycles/int" | ||
|
||
---------------------------------------------------------------------------------------------------- | ||
-- Main Script | ||
|
||
data Flag = NoC | Help | ||
deriving (Show, Eq) | ||
|
||
options :: [OptDescr Flag] | ||
options = | ||
[ Option ['h'] ["help"] (NoArg Help) "print program help" | ||
, Option [] ["noC"] (NoArg NoC) "omit C benchmarks, haskell only" | ||
] | ||
|
||
main :: IO () | ||
main = do | ||
argv <- getArgs | ||
let (opts,_,other) = getOpt Permute options argv | ||
|
||
unless (null other) $ do | ||
putStrLn "ERROR: Unrecognized options: " | ||
mapM_ putStr other | ||
exitFailure | ||
|
||
when (Help `elem` opts) $ do | ||
putStr $ usageInfo "Benchmark random number generation" options | ||
exitSuccess | ||
|
||
putStrLn "\nHow many random numbers can we generate in a second on one thread?" | ||
|
||
t1 <- rdtsc | ||
t2 <- rdtsc | ||
putStrLn (" Cost of rdtsc (ffi call): " ++ show (t2 - t1)) | ||
|
||
freq <- measureFreq | ||
putStrLn $ " Approx clock frequency: " ++ commaint freq | ||
|
||
let randInt = random :: RandomGen g => g -> (Int,g) | ||
randWord16 = random :: RandomGen g => g -> (Word16,g) | ||
randFloat = random :: RandomGen g => g -> (Float,g) | ||
randCFloat = random :: RandomGen g => g -> (CFloat,g) | ||
randDouble = random :: RandomGen g => g -> (Double,g) | ||
randCDouble = random :: RandomGen g => g -> (CDouble,g) | ||
randInteger = random :: RandomGen g => g -> (Integer,g) | ||
randBool = random :: RandomGen g => g -> (Bool,g) | ||
randChar = random :: RandomGen g => g -> (Char,g) | ||
|
||
gen = mkStdGen 23852358661234 | ||
gamut th = do | ||
putStrLn " First, timing System.Random.next:" | ||
timeit th freq "constant zero gen" NoopRNG next | ||
timeit th freq "System.Random stdGen/next" gen next | ||
|
||
putStrLn "\n Second, timing System.Random.random at different types:" | ||
timeit th freq "System.Random Ints" gen randInt | ||
timeit th freq "System.Random Word16" gen randWord16 | ||
timeit th freq "System.Random Floats" gen randFloat | ||
timeit th freq "System.Random CFloats" gen randCFloat | ||
timeit th freq "System.Random Doubles" gen randDouble | ||
timeit th freq "System.Random CDoubles" gen randCDouble | ||
timeit th freq "System.Random Integers" gen randInteger | ||
timeit th freq "System.Random Bools" gen randBool | ||
timeit th freq "System.Random Chars" gen randChar | ||
|
||
putStrLn "\n Next timing range-restricted System.Random.randomR:" | ||
timeit th freq "System.Random Ints" gen (randomR (-100, 100::Int)) | ||
timeit th freq "System.Random Word16s" gen (randomR ( 100, 300::Word16)) | ||
timeit th freq "System.Random Floats" gen (randomR (-100, 100::Float)) | ||
timeit th freq "System.Random CFloats" gen (randomR (-100, 100::CFloat)) | ||
timeit th freq "System.Random Doubles" gen (randomR (-100, 100::Double)) | ||
timeit th freq "System.Random CDoubles" gen (randomR (-100, 100::CDouble)) | ||
timeit th freq "System.Random Integers" gen (randomR (-100, 100::Integer)) | ||
timeit th freq "System.Random Bools" gen (randomR (False, True::Bool)) | ||
timeit th freq "System.Random Chars" gen (randomR ('a', 'z')) | ||
timeit th freq "System.Random BIG Integers" gen (randomR (0, (2::Integer) ^ (5000::Int))) | ||
|
||
-- when (not$ NoC `elem` opts) $ do | ||
-- putStrLn$ " Comparison to C's rand():" | ||
-- timeit_foreign th freq "ptr store in C loop" store_loop | ||
-- timeit_foreign th freq "rand/store in C loop" blast_rands | ||
-- timeit_foreign th freq "rand in Haskell loop" (\n ptr -> forM_ [1..n]$ \_ -> rand ) | ||
-- timeit_foreign th freq "rand/store in Haskell loop" (\n ptr -> forM_ [1..n]$ \_ -> do n <- rand; poke ptr n ) | ||
-- return () | ||
|
||
-- Test with 1 thread and numCapabilities threads: | ||
gamut 1 | ||
when (numCapabilities > 1) $ do | ||
putStrLn $ "\nNow "++ show numCapabilities ++" threads, reporting mean randoms-per-second-per-thread:" | ||
void $ gamut numCapabilities | ||
|
||
putStrLn "Finished." | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,309 @@ | ||
{-# LANGUAGE BangPatterns #-} | ||
{-# LANGUAGE FlexibleContexts #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
module Main (main) where | ||
|
||
import Control.Monad | ||
import Control.Monad.State.Strict | ||
import Data.Int | ||
import Data.Proxy | ||
import Data.Typeable | ||
import Data.Word | ||
import Foreign.C.Types | ||
import Gauge.Main | ||
import Numeric.Natural (Natural) | ||
import System.Random.SplitMix as SM | ||
|
||
import System.Random.Stateful | ||
|
||
main :: IO () | ||
main = do | ||
let !sz = 100000 | ||
genLengths = | ||
-- create 5000 small lengths that are needed for ShortByteString generation | ||
runStateGen (mkStdGen 2020) $ \g -> replicateM 5000 (uniformRM (16 + 1, 16 + 7) g) | ||
defaultMain | ||
[ bgroup "baseline" | ||
[ let !smGen = SM.mkSMGen 1337 in bench "nextWord32" $ nf (genMany SM.nextWord32 smGen) sz | ||
, let !smGen = SM.mkSMGen 1337 in bench "nextWord64" $ nf (genMany SM.nextWord64 smGen) sz | ||
, let !smGen = SM.mkSMGen 1337 in bench "nextInt" $ nf (genMany SM.nextInt smGen) sz | ||
, let !smGen = SM.mkSMGen 1337 in bench "split" $ nf (genMany SM.splitSMGen smGen) sz | ||
] | ||
, bgroup "pure" | ||
[ bgroup "random" | ||
[ pureRandomBench (Proxy :: Proxy Float) sz | ||
, pureRandomBench (Proxy :: Proxy Double) sz | ||
, pureRandomBench (Proxy :: Proxy Integer) sz | ||
] | ||
, bgroup "uniform" | ||
[ pureUniformBench (Proxy :: Proxy Word8) sz | ||
, pureUniformBench (Proxy :: Proxy Word16) sz | ||
, pureUniformBench (Proxy :: Proxy Word32) sz | ||
, pureUniformBench (Proxy :: Proxy Word64) sz | ||
, pureUniformBench (Proxy :: Proxy Word) sz | ||
, pureUniformBench (Proxy :: Proxy Int8) sz | ||
, pureUniformBench (Proxy :: Proxy Int16) sz | ||
, pureUniformBench (Proxy :: Proxy Int32) sz | ||
, pureUniformBench (Proxy :: Proxy Int64) sz | ||
, pureUniformBench (Proxy :: Proxy Int) sz | ||
, pureUniformBench (Proxy :: Proxy Char) sz | ||
, pureUniformBench (Proxy :: Proxy Bool) sz | ||
, pureUniformBench (Proxy :: Proxy CChar) sz | ||
, pureUniformBench (Proxy :: Proxy CSChar) sz | ||
, pureUniformBench (Proxy :: Proxy CUChar) sz | ||
, pureUniformBench (Proxy :: Proxy CShort) sz | ||
, pureUniformBench (Proxy :: Proxy CUShort) sz | ||
, pureUniformBench (Proxy :: Proxy CInt) sz | ||
, pureUniformBench (Proxy :: Proxy CUInt) sz | ||
, pureUniformBench (Proxy :: Proxy CLong) sz | ||
, pureUniformBench (Proxy :: Proxy CULong) sz | ||
, pureUniformBench (Proxy :: Proxy CPtrdiff) sz | ||
, pureUniformBench (Proxy :: Proxy CSize) sz | ||
, pureUniformBench (Proxy :: Proxy CWchar) sz | ||
, pureUniformBench (Proxy :: Proxy CSigAtomic) sz | ||
, pureUniformBench (Proxy :: Proxy CLLong) sz | ||
, pureUniformBench (Proxy :: Proxy CULLong) sz | ||
, pureUniformBench (Proxy :: Proxy CIntPtr) sz | ||
, pureUniformBench (Proxy :: Proxy CUIntPtr) sz | ||
, pureUniformBench (Proxy :: Proxy CIntMax) sz | ||
, pureUniformBench (Proxy :: Proxy CUIntMax) sz | ||
] | ||
, bgroup "uniformR" | ||
[ bgroup "full" | ||
[ pureUniformRFullBench (Proxy :: Proxy Word8) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Word16) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Word32) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Word64) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Word) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Int8) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Int16) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Int32) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Int64) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Int) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Char) sz | ||
, pureUniformRFullBench (Proxy :: Proxy Bool) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CChar) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CSChar) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CUChar) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CShort) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CUShort) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CInt) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CUInt) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CLong) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CULong) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CPtrdiff) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CSize) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CWchar) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CSigAtomic) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CLLong) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CULLong) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CIntPtr) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CUIntPtr) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CIntMax) sz | ||
, pureUniformRFullBench (Proxy :: Proxy CUIntMax) sz | ||
] | ||
, bgroup "excludeMax" | ||
[ pureUniformRExcludeMaxBench (Proxy :: Proxy Word8) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Word16) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Word32) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Word64) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Word) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Int8) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Int16) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Int32) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Int64) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Int) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Char) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy Bool) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CChar) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CSChar) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CUChar) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CShort) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CUShort) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CInt) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CUInt) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CLong) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CULong) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CPtrdiff) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CSize) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CWchar) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CSigAtomic) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CLLong) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CULLong) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CIntPtr) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CUIntPtr) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CIntMax) sz | ||
, pureUniformRExcludeMaxBench (Proxy :: Proxy CUIntMax) sz | ||
] | ||
, bgroup "includeHalf" | ||
[ pureUniformRIncludeHalfBench (Proxy :: Proxy Word8) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Word16) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Word32) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Word64) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Word) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Int8) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Int16) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Int32) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Int64) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy Int) sz | ||
, pureUniformRIncludeHalfEnumBench (Proxy :: Proxy Char) sz | ||
, pureUniformRIncludeHalfEnumBench (Proxy :: Proxy Bool) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CChar) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CSChar) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CUChar) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CShort) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CUShort) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CInt) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CUInt) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CLong) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CULong) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CPtrdiff) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CSize) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CWchar) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CSigAtomic) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CLLong) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CULLong) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CIntPtr) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CUIntPtr) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CIntMax) sz | ||
, pureUniformRIncludeHalfBench (Proxy :: Proxy CUIntMax) sz | ||
] | ||
, bgroup "unbounded" | ||
[ pureUniformRBench (Proxy :: Proxy Float) (1.23e-4, 5.67e8) sz | ||
, pureUniformRBench (Proxy :: Proxy Double) (1.23e-4, 5.67e8) sz | ||
, let !i = (10 :: Integer) ^ (100 :: Integer) | ||
!range = (-i - 1, i + 1) | ||
in pureUniformRBench (Proxy :: Proxy Integer) range sz | ||
, let !n = (10 :: Natural) ^ (100 :: Natural) | ||
!range = (1, n - 1) | ||
in pureUniformRBench (Proxy :: Proxy Natural) range sz | ||
] | ||
, bgroup "floating" | ||
[ bgroup "IO" | ||
[ bench "uniformFloat01M" $ nfIO $ runStateGenT_ (mkStdGen 1337) $ \g -> | ||
replicateM_ sz $ do !_ <- uniformFloat01M g | ||
return () | ||
, bench "uniformFloatPositive01M" $ nfIO $ runStateGenT_ (mkStdGen 1337) $ \g -> | ||
replicateM_ sz $ do !_ <- uniformFloatPositive01M g | ||
return () | ||
, bench "uniformDouble01M" $ nfIO $ runStateGenT_ (mkStdGen 1337) $ \g -> | ||
replicateM_ sz $ do !_ <- uniformDouble01M g | ||
return () | ||
, bench "uniformDoublePositive01M" $ nfIO $ runStateGenT_ (mkStdGen 1337) $ \g -> | ||
replicateM_ sz $ do !_ <- uniformDoublePositive01M g | ||
return () | ||
] | ||
-- | ||
, bgroup "St" | ||
[ bench "uniformFloat01M" $ nf | ||
(\n -> runStateGen_ (mkStdGen 1337) $ \g -> replicateM_ n $ do !_ <- uniformFloat01M g | ||
return () | ||
) sz | ||
, bench "uniformFloatPositive01M" $ nf | ||
(\n -> runStateGen_ (mkStdGen 1337) $ \g -> replicateM_ n $ do !_ <- uniformFloatPositive01M g | ||
return () | ||
) sz | ||
, bench "uniformDouble01M" $ nf | ||
(\n -> runStateGen_ (mkStdGen 1337) $ \g -> replicateM_ n $ do !_ <- uniformDouble01M g | ||
return () | ||
) sz | ||
, bench "uniformDoublePositive01M" $ nf | ||
(\n -> runStateGen_ (mkStdGen 1337) $ \g -> replicateM_ n $ do !_ <- uniformDoublePositive01M g | ||
return () | ||
) sz | ||
] | ||
, bgroup "pure" | ||
[ let !stdGen = mkStdGen 1337 | ||
in bench "uniformFloat01M" $ nf | ||
(genMany (runState $ uniformFloat01M (StateGenM :: StateGenM StdGen)) stdGen) | ||
sz | ||
, let !stdGen = mkStdGen 1337 | ||
in bench "uniformFloatPositive01M" $ nf | ||
(genMany (runState $ uniformFloatPositive01M (StateGenM :: StateGenM StdGen)) stdGen) | ||
sz | ||
, let !stdGen = mkStdGen 1337 | ||
in bench "uniformDouble01M" $ nf | ||
(genMany (runState $ uniformDouble01M (StateGenM :: StateGenM StdGen)) stdGen) | ||
sz | ||
, let !stdGen = mkStdGen 1337 | ||
in bench "uniformDoublePositive01M" $ nf | ||
(genMany (runState $ uniformDoublePositive01M (StateGenM :: StateGenM StdGen)) stdGen) | ||
sz | ||
] | ||
] | ||
, bgroup "ShortByteString" | ||
[ env (pure genLengths) $ \ ~(ns, gen) -> | ||
bench "genShortByteString" $ | ||
nfIO $ runStateGenT_ gen $ \g -> mapM (`uniformShortByteString` g) ns | ||
] | ||
] | ||
] | ||
] | ||
|
||
pureRandomBench :: forall a. (Typeable a, Random a) => Proxy a -> Int -> Benchmark | ||
pureRandomBench px = | ||
let !stdGen = mkStdGen 1337 | ||
in pureBench px (genMany (random :: StdGen -> (a, StdGen)) stdGen) | ||
|
||
pureUniformBench :: forall a. (Typeable a, Uniform a) => Proxy a -> Int -> Benchmark | ||
pureUniformBench px = | ||
let !stdGen = mkStdGen 1337 | ||
in pureBench px (genMany (uniform :: StdGen -> (a, StdGen)) stdGen) | ||
|
||
pureUniformRFullBench :: | ||
forall a. (Typeable a, UniformRange a, Bounded a) | ||
=> Proxy a | ||
-> Int | ||
-> Benchmark | ||
pureUniformRFullBench px = | ||
let range = (minBound :: a, maxBound :: a) | ||
in pureUniformRBench px range | ||
|
||
pureUniformRExcludeMaxBench :: | ||
forall a. (Typeable a, UniformRange a, Bounded a, Enum a) | ||
=> Proxy a | ||
-> Int | ||
-> Benchmark | ||
pureUniformRExcludeMaxBench px = | ||
let range = (minBound :: a, pred (maxBound :: a)) | ||
in pureUniformRBench px range | ||
|
||
pureUniformRIncludeHalfBench :: | ||
forall a. (Typeable a, UniformRange a, Bounded a, Integral a) | ||
=> Proxy a | ||
-> Int | ||
-> Benchmark | ||
pureUniformRIncludeHalfBench px = | ||
let range = ((minBound :: a) + 1, ((maxBound :: a) `div` 2) + 1) | ||
in pureUniformRBench px range | ||
|
||
pureUniformRIncludeHalfEnumBench :: | ||
forall a. (Typeable a, UniformRange a, Bounded a, Enum a) | ||
=> Proxy a | ||
-> Int | ||
-> Benchmark | ||
pureUniformRIncludeHalfEnumBench px = | ||
let range = (succ (minBound :: a), toEnum ((fromEnum (maxBound :: a) `div` 2) + 1)) | ||
in pureUniformRBench px range | ||
|
||
pureUniformRBench :: | ||
forall a. (Typeable a, UniformRange a) | ||
=> Proxy a | ||
-> (a, a) | ||
-> Int | ||
-> Benchmark | ||
pureUniformRBench px range@(!_, !_) = | ||
let !stdGen = mkStdGen 1337 | ||
in pureBench px (genMany (uniformR range) stdGen) | ||
|
||
pureBench :: forall a. (Typeable a) => Proxy a -> (Int -> ()) -> Int -> Benchmark | ||
pureBench px f sz = bench (showsTypeRep (typeRep px) "") $ nf f sz | ||
|
||
genMany :: (g -> (a, g)) -> g -> Int -> () | ||
genMany f g0 n = go g0 0 | ||
where | ||
go g i | ||
| i < n = | ||
case f g of | ||
(x, g') -> x `seq` go g' (i + 1) | ||
| otherwise = g `seq` () |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,193 @@ | ||
name: random | ||
version: 1.1 | ||
|
||
|
||
|
||
|
||
license: BSD3 | ||
license-file: LICENSE | ||
maintainer: core-libraries-committee@haskell.org | ||
bug-reports: https://github.com/haskell/random/issues | ||
synopsis: random number library | ||
category: System | ||
cabal-version: >=1.10 | ||
name: random | ||
version: 1.2.0 | ||
license: BSD3 | ||
license-file: LICENSE | ||
maintainer: core-libraries-committee@haskell.org | ||
bug-reports: https://github.com/haskell/random/issues | ||
synopsis: Pseudo-random number generation | ||
description: | ||
This package provides a basic random number generation | ||
library, including the ability to split random number | ||
generators. | ||
|
||
This package provides basic pseudo-random number generation, including the | ||
ability to split random number generators. | ||
. | ||
== "System.Random": pure pseudo-random number interface | ||
. | ||
In pure code, use 'System.Random.uniform' and 'System.Random.uniformR' from | ||
"System.Random" to generate pseudo-random numbers with a pure pseudo-random | ||
number generator like 'System.Random.StdGen'. | ||
. | ||
As an example, here is how you can simulate rolls of a six-sided die using | ||
'System.Random.uniformR': | ||
. | ||
>>> let roll = uniformR (1, 6) :: RandomGen g => g -> (Word, g) | ||
>>> let rolls = unfoldr (Just . roll) :: RandomGen g => g -> [Word] | ||
>>> let pureGen = mkStdGen 42 | ||
>>> take 10 (rolls pureGen) :: [Word] | ||
[1,1,3,2,4,5,3,4,6,2] | ||
. | ||
See "System.Random" for more details. | ||
. | ||
== "System.Random.Stateful": monadic pseudo-random number interface | ||
. | ||
In monadic code, use 'System.Random.Stateful.uniformM' and | ||
'System.Random.Stateful.uniformRM' from "System.Random.Stateful" to generate | ||
pseudo-random numbers with a monadic pseudo-random number generator, or | ||
using a monadic adapter. | ||
. | ||
As an example, here is how you can simulate rolls of a six-sided die using | ||
'System.Random.Stateful.uniformRM': | ||
. | ||
>>> let rollM = uniformRM (1, 6) :: StatefulGen g m => g -> m Word | ||
>>> let pureGen = mkStdGen 42 | ||
>>> runStateGen_ pureGen (replicateM 10 . rollM) :: [Word] | ||
[1,1,3,2,4,5,3,4,6,2] | ||
. | ||
The monadic adapter 'System.Random.Stateful.runGenState_' is used here to lift | ||
the pure pseudo-random number generator @pureGen@ into the | ||
'System.Random.Stateful.StatefulGen' context. | ||
. | ||
The monadic interface can also be used with existing monadic pseudo-random | ||
number generators. In this example, we use the one provided in the | ||
<https://hackage.haskell.org/package/mwc-random mwc-random> package: | ||
. | ||
>>> import System.Random.MWC as MWC | ||
>>> let rollM = uniformRM (1, 6) :: StatefulGen g m => g -> m Word | ||
>>> monadicGen <- MWC.create | ||
>>> replicateM 10 (rollM monadicGen) :: IO [Word] | ||
[2,3,6,6,4,4,3,1,5,4] | ||
. | ||
See "System.Random.Stateful" for more details. | ||
|
||
category: System | ||
build-type: Simple | ||
extra-source-files: | ||
.travis.yml | ||
README.md | ||
CHANGELOG.md | ||
.gitignore | ||
.darcs-boring | ||
|
||
|
||
|
||
build-type: Simple | ||
-- cabal-version 1.8 needed because "the field 'build-depends: random' refers | ||
-- to a library which is defined within the same package" | ||
cabal-version: >= 1.8 | ||
|
||
|
||
|
||
Library | ||
exposed-modules: | ||
System.Random | ||
extensions: CPP | ||
GHC-Options: -O2 | ||
build-depends: base >= 3 && < 5, time | ||
README.md | ||
CHANGELOG.md | ||
tested-with: GHC == 7.10.2 | ||
, GHC == 7.10.3 | ||
, GHC == 8.0.2 | ||
, GHC == 8.2.2 | ||
, GHC == 8.4.3 | ||
, GHC == 8.4.4 | ||
, GHC == 8.6.3 | ||
, GHC == 8.6.4 | ||
, GHC == 8.6.5 | ||
, GHC == 8.8.1 | ||
, GHC == 8.8.2 | ||
, GHC == 8.10.1 | ||
|
||
source-repository head | ||
type: git | ||
location: http://git.haskell.org/packages/random.git | ||
location: https://github.com/haskell/random.git | ||
|
||
-- To run the Test-Suite: | ||
-- $ cabal configure --enable-tests | ||
-- $ cabal test --show-details=always --test-options="+RTS -M1M -RTS" | ||
|
||
Test-Suite T7936 | ||
type: exitcode-stdio-1.0 | ||
main-is: T7936.hs | ||
hs-source-dirs: tests | ||
build-depends: base >= 3 && < 5, random | ||
ghc-options: -rtsopts -O2 | ||
|
||
Test-Suite TestRandomRs | ||
type: exitcode-stdio-1.0 | ||
main-is: TestRandomRs.hs | ||
hs-source-dirs: tests | ||
build-depends: base >= 3 && < 5, random | ||
ghc-options: -rtsopts -O2 | ||
-- TODO. Why does the following not work? | ||
--test-options: +RTS -M1M -RTS | ||
|
||
Test-Suite TestRandomIOs | ||
type: exitcode-stdio-1.0 | ||
main-is: TestRandomIOs.hs | ||
hs-source-dirs: tests | ||
build-depends: base >= 3 && < 5, random | ||
ghc-options: -rtsopts -O2 | ||
library | ||
exposed-modules: | ||
System.Random | ||
System.Random.Internal | ||
System.Random.Stateful | ||
|
||
hs-source-dirs: src | ||
default-language: Haskell2010 | ||
ghc-options: | ||
-Wall | ||
if impl(ghc >= 8.0) | ||
ghc-options: | ||
-Wincomplete-record-updates -Wincomplete-uni-patterns | ||
|
||
build-depends: | ||
base >=4.8 && <5, | ||
bytestring >=0.10.4 && <0.11, | ||
deepseq >=1.1 && <2, | ||
mtl >=2.2 && <2.3, | ||
splitmix >=0.1 && <0.2 | ||
if impl(ghc < 8.0) | ||
build-depends: | ||
transformers | ||
|
||
test-suite legacy-test | ||
type: exitcode-stdio-1.0 | ||
main-is: Legacy.hs | ||
hs-source-dirs: test-legacy | ||
other-modules: | ||
T7936 | ||
TestRandomIOs | ||
TestRandomRs | ||
Random1283 | ||
RangeTest | ||
|
||
default-language: Haskell2010 | ||
ghc-options: -with-rtsopts=-M4M | ||
if impl(ghc >= 8.0) | ||
ghc-options: | ||
-Wno-deprecations | ||
build-depends: | ||
base -any, | ||
containers >=0.5 && <0.7, | ||
random -any | ||
|
||
test-suite doctests | ||
type: exitcode-stdio-1.0 | ||
main-is: doctests.hs | ||
hs-source-dirs: test | ||
default-language: Haskell2010 | ||
build-depends: | ||
base -any, | ||
doctest >=0.15 && <0.18, | ||
mwc-random >=0.13 && <0.15, | ||
primitive >=0.6 && <0.8, | ||
random -any, | ||
unliftio >=0.2 && <0.3, | ||
vector >= 0.10 && <0.14 | ||
|
||
test-suite spec | ||
type: exitcode-stdio-1.0 | ||
main-is: Spec.hs | ||
hs-source-dirs: test | ||
other-modules: | ||
Spec.Range | ||
Spec.Run | ||
|
||
default-language: Haskell2010 | ||
ghc-options: -Wall | ||
build-depends: | ||
base -any, | ||
bytestring -any, | ||
random -any, | ||
smallcheck >=1.2 && <1.3, | ||
tasty >=1.0 && <1.4, | ||
tasty-smallcheck >=0.8 && <0.9, | ||
tasty-expected-failure >=0.11 && <0.12, | ||
tasty-hunit >=0.10 && <0.11 | ||
|
||
benchmark legacy-bench | ||
type: exitcode-stdio-1.0 | ||
main-is: SimpleRNGBench.hs | ||
hs-source-dirs: bench-legacy | ||
other-modules: BinSearch | ||
default-language: Haskell2010 | ||
ghc-options: | ||
-Wall -O2 -threaded -rtsopts -with-rtsopts=-N | ||
if impl(ghc >= 8.0) | ||
ghc-options: | ||
-Wno-deprecations | ||
|
||
build-depends: | ||
base -any, | ||
random -any, | ||
rdtsc -any, | ||
split >=0.2 && <0.3, | ||
time >=1.4 && <1.11 | ||
|
||
benchmark bench | ||
type: exitcode-stdio-1.0 | ||
main-is: Main.hs | ||
hs-source-dirs: bench | ||
default-language: Haskell2010 | ||
ghc-options: -Wall -O2 | ||
build-depends: | ||
base -any, | ||
gauge >=0.2.3 && <0.3, | ||
mtl, | ||
random -any, | ||
splitmix >=0.1 && <0.2 |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
resolver: lts-14.27 | ||
packages: | ||
- . | ||
extra-deps: | ||
- splitmix-0.1@sha256:d50c4d0801a35be7875a040470c09863342514930c82a7d25780a6c2efc4fda9,5249 | ||
- rdtsc-1.3.0.1@sha256:0a6e8dc715ba82ad72c7e2b1c2f468999559bec059d50540719a80b00dcc4e66,1557 | ||
- smallcheck-1.2.0@sha256:8b431572e6a0503223e0e52014d41084c1b01f2aeea3bd499f6f529b3f6dfa89,1482 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
resolver: lts-11.22 | ||
packages: | ||
- . | ||
extra-deps: | ||
- splitmix-0.1@sha256:d50c4d0801a35be7875a040470c09863342514930c82a7d25780a6c2efc4fda9,5249 | ||
- doctest-0.16.2@sha256:2f96e9bbe9aee11b47453c82c24b3dc76cdbb8a2a7c984dfd60b4906d08adf68,6942 | ||
- cabal-doctest-1.0.8@sha256:34dff6369d417df2699af4e15f06bc181d495eca9c51efde173deae2053c197c,1491 | ||
- rdtsc-1.3.0.1@sha256:0a6e8dc715ba82ad72c7e2b1c2f468999559bec059d50540719a80b00dcc4e66,1557 | ||
- smallcheck-1.2.0@sha256:8b431572e6a0503223e0e52014d41084c1b01f2aeea3bd499f6f529b3f6dfa89,1482 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
resolver: lts-3.22 | ||
packages: | ||
- . | ||
extra-deps: | ||
- splitmix-0.1@sha256:d50c4d0801a35be7875a040470c09863342514930c82a7d25780a6c2efc4fda9,5249 | ||
- doctest-0.17@sha256:684b9736321c255fc8da651a817a14d46afd9aa08a753b344abaa77b343123f2,6988 | ||
- cabal-doctest-1.0.8@sha256:34dff6369d417df2699af4e15f06bc181d495eca9c51efde173deae2053c197c,1491 | ||
- rdtsc-1.3.0.1@sha256:0a6e8dc715ba82ad72c7e2b1c2f468999559bec059d50540719a80b00dcc4e66,1557 | ||
- smallcheck-1.2.0@sha256:8b431572e6a0503223e0e52014d41084c1b01f2aeea3bd499f6f529b3f6dfa89,1482 | ||
- tasty-1.3.1@sha256:01e35c97f7ee5ccbc28f21debea02a38cd010d53b4c3087f5677c5d06617a507,2520 | ||
- tasty-smallcheck-0.8.1@sha256:37728da9451a857c7410353267c995abea92f8f395fcabd9fe7bf732cc2e3e2e,1013 | ||
- tasty-hunit-0.10.0.2@sha256:8e8bd5807cec650f5aebc5ada07b57620c863e69145e65249651c1b48d97bd70,1515 | ||
- ansi-wl-pprint-0.6.8.2@sha256:a890b713942c1aa0109fb632e9fee581ceb5b0763fd936ae8cae22e5f91a0877,2178 | ||
- ansi-terminal-0.9.1@sha256:48f53532d0f365ffa568c8cf0adc84c66f800a7d80d3329e4f04fa75392f4af1,3225 | ||
- optparse-applicative-0.15.1.0@sha256:29ff6146aabf54d46c4c8788e8d1eadaea27c94f6d360c690c5f6c93dac4b07e,4810 | ||
- unliftio-0.2.11@sha256:ab67a81f31f658c23d096881711ef3a7bda53b819b8149446fca7cc500385859,3064 | ||
- unliftio-core-0.2.0.1@sha256:9b3e44ea9aacacbfc35b3b54015af450091916ac3618a41868ebf6546977659a,1082 | ||
- wcwidth-0.0.2@sha256:77531eb6683c505c22ab3fa11bbc43d3ce1e7dac21401d4d5a19677d348bb5f3,1998 | ||
|
||
|
||
- semigroups-0.18@sha256:1ac1e991b2f97eab4e4526137b0b5ec6ac3791868e56e89242501cd2cdd7db97,3996 | ||
- hashable-1.2.7.0@sha256:03b6836ca9cd3ad0e5a2f3cce989b001dd0e05f306a873db3196037adb30e0a4,5215 | ||
|
||
- async-2.2.2@sha256:a178c166856da7ff22fe4500337b54812e94fd2059409452187d72e057ede9cd,2934 | ||
- call-stack-0.2.0@sha256:5ce796b78d5f964468ec6fe0717b4e7d0430817f37370c47b3e6b38e345b6643,1202 | ||
- code-page-0.2@sha256:f701393cb1ff7b3ec7880816abc44387647811be31670e884e02d6a20c4aa508,2356 | ||
- fail-4.9.0.0@sha256:35d1ee29364447c1b7d616bb1ee31f162b73e85fea91d7ca6441cf901398f572,1051 | ||
- tasty-expected-failure-0.11.1.2@sha256:ff9bad876ec28415e8fb6837362f2086331cf23d7f1468536aaabd91d53f66e4,1826 | ||
- gauge-0.2.5@sha256:8d60450bdec985c146d5632d4f5a8d60cec27d71ba6787ed1ee64d945d4c7c33,3923 | ||
- basement-0.0.6@sha256:8ef28b7ee2419f410919fb938fcf1e160d84759736baf007eb056a17bc34924a,5578 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
resolver: lts-15.1 | ||
packages: | ||
- . | ||
extra-deps: | ||
- splitmix-0.1@sha256:d50c4d0801a35be7875a040470c09863342514930c82a7d25780a6c2efc4fda9,5249 | ||
- doctest-0.17@sha256:684b9736321c255fc8da651a817a14d46afd9aa08a753b344abaa77b343123f2,6988 | ||
- smallcheck-1.2.0@sha256:8b431572e6a0503223e0e52014d41084c1b01f2aeea3bd499f6f529b3f6dfa89,1482 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module Main (main) where | ||
|
||
import qualified Random1283 as Random1283 | ||
import qualified RangeTest as RangeTest | ||
import qualified T7936 as T7936 | ||
import qualified TestRandomIOs as TestRandomIOs | ||
import qualified TestRandomRs as TestRandomRs | ||
|
||
main :: IO () | ||
main = do | ||
Random1283.main | ||
RangeTest.main | ||
T7936.main | ||
TestRandomIOs.main | ||
TestRandomRs.main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
{-# LANGUAGE AllowAmbiguousTypes #-} | ||
{-# LANGUAGE CPP #-} | ||
{-# LANGUAGE FlexibleContexts #-} | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE MultiParamTypeClasses #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
module Main (main) where | ||
|
||
import Data.ByteString.Short as SBS | ||
import Data.Int | ||
import Data.Typeable | ||
import Data.Word | ||
import Foreign.C.Types | ||
import Numeric.Natural (Natural) | ||
import System.Random | ||
import Test.SmallCheck.Series as SC | ||
import Test.Tasty | ||
import Test.Tasty.HUnit | ||
import Test.Tasty.SmallCheck as SC | ||
|
||
import qualified Spec.Range as Range | ||
import qualified Spec.Run as Run | ||
|
||
main :: IO () | ||
main = | ||
defaultMain $ | ||
testGroup | ||
"Spec" | ||
[ floatingSpec (Proxy :: Proxy Double) | ||
, floatingSpec (Proxy :: Proxy Float) | ||
, floatingSpec (Proxy :: Proxy CDouble) | ||
, floatingSpec (Proxy :: Proxy CFloat) | ||
, integralSpec (Proxy :: Proxy Word8) | ||
, integralSpec (Proxy :: Proxy Word16) | ||
, integralSpec (Proxy :: Proxy Word32) | ||
, integralSpec (Proxy :: Proxy Word64) | ||
, integralSpec (Proxy :: Proxy Word) | ||
, integralSpec (Proxy :: Proxy Int8) | ||
, integralSpec (Proxy :: Proxy Int16) | ||
, integralSpec (Proxy :: Proxy Int32) | ||
, integralSpec (Proxy :: Proxy Int64) | ||
, integralSpec (Proxy :: Proxy Int) | ||
, integralSpec (Proxy :: Proxy Char) | ||
, integralSpec (Proxy :: Proxy Bool) | ||
#if __GLASGOW_HASKELL >= 802 | ||
, integralSpec (Proxy :: Proxy CBool) | ||
#endif | ||
, integralSpec (Proxy :: Proxy CChar) | ||
, integralSpec (Proxy :: Proxy CSChar) | ||
, integralSpec (Proxy :: Proxy CUChar) | ||
, integralSpec (Proxy :: Proxy CShort) | ||
, integralSpec (Proxy :: Proxy CUShort) | ||
, integralSpec (Proxy :: Proxy CInt) | ||
, integralSpec (Proxy :: Proxy CUInt) | ||
, integralSpec (Proxy :: Proxy CLong) | ||
, integralSpec (Proxy :: Proxy CULong) | ||
, integralSpec (Proxy :: Proxy CPtrdiff) | ||
, integralSpec (Proxy :: Proxy CSize) | ||
, integralSpec (Proxy :: Proxy CWchar) | ||
, integralSpec (Proxy :: Proxy CSigAtomic) | ||
, integralSpec (Proxy :: Proxy CLLong) | ||
, integralSpec (Proxy :: Proxy CULLong) | ||
, integralSpec (Proxy :: Proxy CIntPtr) | ||
, integralSpec (Proxy :: Proxy CUIntPtr) | ||
, integralSpec (Proxy :: Proxy CIntMax) | ||
, integralSpec (Proxy :: Proxy CUIntMax) | ||
, integralSpec (Proxy :: Proxy Integer) | ||
, integralSpec (Proxy :: Proxy Natural) | ||
, runSpec | ||
, floatTests | ||
, byteStringSpec | ||
, SC.testProperty "uniformRangeWithinExcludedF" $ seeded Range.uniformRangeWithinExcludedF | ||
, SC.testProperty "uniformRangeWithinExcludedD" $ seeded Range.uniformRangeWithinExcludedD | ||
] | ||
|
||
floatTests :: TestTree | ||
floatTests = testGroup "(Float)" | ||
[ -- Check that https://github.com/haskell/random/issues/53 does not regress | ||
|
||
testCase "Subnormal generation not above upper bound" $ | ||
[] @?= filter (>4.0e-45) (take 100000 $ randomRs (0, 4.0e-45::Float) $ mkStdGen 0) | ||
|
||
, testCase "Subnormal generation includes upper bound" $ | ||
1.0e-45 `elem` take 100 (randomRs (0, 1.0e-45::Float) $ mkStdGen 0) @? | ||
"Does not contain 1.0e-45" | ||
] | ||
|
||
showsType :: forall t . Typeable t => Proxy t -> ShowS | ||
showsType px = showsTypeRep (typeRep px) | ||
|
||
byteStringSpec :: TestTree | ||
byteStringSpec = | ||
testGroup | ||
"ByteString" | ||
[ SC.testProperty "genShortByteString" $ \(seed, n8) -> | ||
let n = fromIntegral (n8 :: Word8) -- no need to generate huge collection of bytes | ||
in SBS.length (fst (seeded (genShortByteString n) seed)) == n | ||
, SC.testProperty "genByteString" $ \(seed, n8) -> | ||
let n = fromIntegral (n8 :: Word8) | ||
in SBS.toShort (fst (seeded (genByteString n) seed)) == | ||
fst (seeded (genShortByteString n) seed) | ||
] | ||
|
||
|
||
rangeSpec :: | ||
forall a. | ||
(SC.Serial IO a, Typeable a, Ord a, UniformRange a, Show a) | ||
=> Proxy a -> TestTree | ||
rangeSpec px = | ||
testGroup ("Range (" ++ showsType px ")") | ||
[ SC.testProperty "uniformR" $ seeded $ Range.uniformRangeWithin px | ||
] | ||
|
||
integralSpec :: | ||
forall a. | ||
(SC.Serial IO a, Typeable a, Ord a, UniformRange a, Show a) | ||
=> Proxy a -> TestTree | ||
integralSpec px = | ||
testGroup ("(" ++ showsType px ")") | ||
[ SC.testProperty "symmetric" $ seeded $ Range.symmetric px | ||
, SC.testProperty "bounded" $ seeded $ Range.bounded px | ||
, SC.testProperty "singleton" $ seeded $ Range.singleton px | ||
, rangeSpec px | ||
-- TODO: Add more tests | ||
] | ||
|
||
floatingSpec :: | ||
forall a. | ||
(SC.Serial IO a, Typeable a, Num a, Ord a, Random a, UniformRange a, Show a) | ||
=> Proxy a -> TestTree | ||
floatingSpec px = | ||
testGroup ("(" ++ showsType px ")") | ||
[ SC.testProperty "uniformR" $ seeded $ Range.uniformRangeWithin px | ||
-- TODO: Add more tests | ||
] | ||
|
||
runSpec :: TestTree | ||
runSpec = testGroup "runGenState_ and runPrimGenIO_" | ||
[ SC.testProperty "equal outputs" $ seeded $ \g -> monadic $ Run.runsEqual g ] | ||
|
||
-- | Create a StdGen instance from an Int and pass it to the given function. | ||
seeded :: (StdGen -> a) -> Int -> a | ||
seeded f = f . mkStdGen |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
module Spec.Range | ||
( symmetric | ||
, bounded | ||
, singleton | ||
, uniformRangeWithin | ||
, uniformRangeWithinExcludedF | ||
, uniformRangeWithinExcludedD | ||
) where | ||
|
||
import System.Random.Internal | ||
import System.Random.Stateful | ||
import Data.Proxy | ||
|
||
symmetric :: (RandomGen g, UniformRange a, Eq a) => Proxy a -> g -> (a, a) -> Bool | ||
symmetric _ g (l, r) = fst (uniformR (l, r) g) == fst (uniformR (r, l) g) | ||
|
||
bounded :: (RandomGen g, UniformRange a, Ord a) => Proxy a -> g -> (a, a) -> Bool | ||
bounded _ g (l, r) = bottom <= result && result <= top | ||
where | ||
bottom = min l r | ||
top = max l r | ||
result = fst (uniformR (l, r) g) | ||
|
||
singleton :: (RandomGen g, UniformRange a, Eq a) => Proxy a -> g -> a -> Bool | ||
singleton _ g x = result == x | ||
where | ||
result = fst (uniformR (x, x) g) | ||
|
||
uniformRangeWithin :: (RandomGen g, UniformRange a, Ord a) => Proxy a -> g -> (a, a) -> Bool | ||
uniformRangeWithin _ gen (l, r) = | ||
runStateGen_ gen $ \g -> | ||
(\result -> min l r <= result && result <= max l r) <$> uniformRM (l, r) g | ||
|
||
uniformRangeWithinExcludedF :: RandomGen g => g -> Bool | ||
uniformRangeWithinExcludedF gen = | ||
runStateGen_ gen $ \g -> | ||
(\result -> 0 < result && result <= 1) <$> uniformFloatPositive01M g | ||
|
||
uniformRangeWithinExcludedD :: RandomGen g => g -> Bool | ||
uniformRangeWithinExcludedD gen = | ||
runStateGen_ gen $ \g -> | ||
(\result -> 0 < result && result <= 1) <$> uniformDoublePositive01M g |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module Spec.Run (runsEqual) where | ||
|
||
import Data.Word (Word64) | ||
import System.Random.Stateful | ||
|
||
runsEqual :: RandomGen g => g -> IO Bool | ||
runsEqual g = do | ||
let pureResult = runStateGen_ g uniformM :: Word64 | ||
stResult = runSTGen_ g uniformM :: Word64 | ||
ioGenM <- newIOGenM g | ||
ioResult <- uniformM ioGenM | ||
atomicGenM <- newAtomicGenM g | ||
atomicResult <- uniformM atomicGenM | ||
return $ all (pureResult ==) [stResult, ioResult, atomicResult] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{-# LANGUAGE CPP #-} | ||
module Main where | ||
|
||
#if __GLASGOW_HASKELL__ >= 802 | ||
|
||
import Test.DocTest (doctest) | ||
|
||
main :: IO () | ||
main = doctest ["src"] | ||
|
||
#else | ||
|
||
-- TODO: fix doctest support | ||
main :: IO () | ||
main = putStrLn "\nDoctests are not supported for older ghc version\n" | ||
|
||
#endif |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.