measurable

A simple shallowly-embedded DSL for dealing with measures.
Log | Files | Refs | README | LICENSE

commit 8212f5d8195180e784ae0cbe89a77b937dcc2e4b
parent 5243dee218fcb7507a9eb5749e91d58269746fe4
Author: Jared Tobin <jared@jtobin.ca>
Date:   Tue, 30 May 2017 22:30:02 +1200

General cleanup.

Diffstat:
MREADME.md | 5++---
Dcabal.config | 866-------------------------------------------------------------------------------
Dexamples/CRP.hs | 98-------------------------------------------------------------------------------
Mmeasurable.cabal | 48++++++++++++------------------------------------
Asrc/Measurable.hs | 5+++++
Msrc/Measurable/Core.hs | 522++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Dsrc/Measurable/Util.hs | 36------------------------------------
Mstack.yaml | 2+-
8 files changed, 380 insertions(+), 1202 deletions(-)

diff --git a/README.md b/README.md @@ -18,9 +18,8 @@ do-notation. Query measures by integrating meaurable functions against them. Extract moments, cumulative density functions, or probabilities. -Check out the module comments or *examples* folder for sample use. You can -also check out a few blog posts I wrote about the theoretical foundations and -implementation of the library here: +You can check out a few blog posts I wrote about the theoretical foundations +and implementation of the library here: * [Foundations of the Giry Monad][foun] * [Implementing the Giry Monad][impl] diff --git a/cabal.config b/cabal.config @@ -1,866 +0,0 @@ --- Stackage snapshot from: http://www.stackage.org/snapshot/lts-1.11 --- Please place this file next to your .cabal file as cabal.config --- To only use tested packages, uncomment the following line: --- remote-repo: stackage-lts-1.11:http://www.stackage.org/snapshot/lts-1.11 -constraints: abstract-deque ==0.3, - abstract-par ==0.3.3, - accelerate ==0.15.0.0, - ace ==0.6, - action-permutations ==0.0.0.1, - active ==0.1.0.18, - AC-Vector ==2.3.2, - ad ==4.2.1.1, - adjunctions ==4.2, - aeson ==0.8.0.2, - aeson-pretty ==0.7.2, - aeson-qq ==0.7.4, - aeson-utils ==0.2.2.1, - alarmclock ==0.2.0.5, - alex ==3.1.4, - amqp ==0.10.1, - ansi-terminal ==0.6.2.1, - ansi-wl-pprint ==0.6.7.1, - appar ==0.1.4, - approximate ==0.2.1.1, - arbtt ==0.8.1.4, - arithmoi ==0.4.1.1, - array installed, - arrow-list ==0.6.1.5, - asn1-data ==0.7.1, - asn1-encoding ==0.9.0, - asn1-parse ==0.9.0, - asn1-types ==0.3.0, - async ==2.0.2, - atto-lisp ==0.2.2, - attoparsec ==0.12.1.3, - attoparsec-conduit ==1.1.0, - attoparsec-enumerator ==0.3.3, - attoparsec-expr ==0.1.1.1, - authenticate ==1.3.2.11, - auto-update ==0.1.2.1, - aws ==0.11.2, - bake ==0.2, - bank-holidays-england ==0.1.0.2, - barecheck ==0.2.0.6, - base installed, - base16-bytestring ==0.1.1.6, - base64-bytestring ==1.0.0.1, - base-compat ==0.5.0, - base-prelude ==0.1.16, - base-unicode-symbols ==0.2.2.4, - basic-prelude ==0.3.11.1, - bifunctors ==4.2.1, - binary installed, - binary-conduit ==1.2.3, - binary-list ==1.0.1.0, - bindings-DSL ==1.0.22, - bioace ==0.0.1, - bioalign ==0.0.5, - biocore ==0.3.1, - biofasta ==0.0.3, - biofastq ==0.1, - biophd ==0.0.5, - biopsl ==0.4, - biosff ==0.3.7.1, - bits ==0.4, - BlastHTTP ==1.0.1, - blastxml ==0.3.2, - blaze-builder ==0.3.3.4, - blaze-builder-enumerator ==0.2.0.6, - blaze-html ==0.7.1.0, - blaze-markup ==0.6.3.0, - blaze-svg ==0.3.4.1, - blaze-textual ==0.2.0.9, - BlogLiterately ==0.7.1.7, - BlogLiterately-diagrams ==0.1.4.3, - bloodhound ==0.5.0.1, - bmp ==1.2.5.2, - Boolean ==0.2.3, - bool-extras ==0.4.0, - bound ==1.0.4, - BoundedChan ==1.0.3.0, - broadcast-chan ==0.1.0, - bson ==0.3.1, - bumper ==0.6.0.3, - byteable ==0.1.1, - bytedump ==1.0, - byteorder ==1.0.4, - bytes ==0.14.1.3, - bytestring installed, - bytestring-builder ==0.10.4.1.2, - bytestring-lexing ==0.4.3.2, - bytestring-mmap ==0.2.2, - bytestring-progress ==1.0.3, - bytestring-show ==0.3.5.6, - bytestring-trie ==0.2.4, - bzlib ==0.5.0.5, - bzlib-conduit ==0.2.1.3, - c2hs ==0.20.1, - Cabal installed, - cabal-install ==1.18.0.8, - cabal-src ==0.2.5, - cairo ==0.13.1.0, - case-insensitive ==1.2.0.4, - cases ==0.1.2, - cassava ==0.4.2.1, - cautious-file ==1.0.2, - cereal ==0.4.1.1, - cereal-conduit ==0.7.2.3, - certificate ==1.3.9, - charset ==0.3.7, - Chart ==1.3.3, - Chart-diagrams ==1.3.3, - ChasingBottoms ==1.3.0.11, - check-email ==1.0, - checkers ==0.4.1, - chell ==0.4.0.1, - chell-quickcheck ==0.2.4, - chunked-data ==0.1.0.1, - cipher-aes ==0.2.10, - cipher-blowfish ==0.0.3, - cipher-camellia ==0.0.2, - cipher-des ==0.0.6, - cipher-rc4 ==0.1.4, - circle-packing ==0.1.0.4, - classy-prelude ==0.10.5, - classy-prelude-conduit ==0.10.5, - classy-prelude-yesod ==0.10.5, - clientsession ==0.9.1.1, - clock ==0.4.1.3, - cmdargs ==0.10.12, - code-builder ==0.1.3, - colour ==2.3.3, - comonad ==4.2.3, - comonads-fd ==4.0, - comonad-transformers ==4.0, - compdata ==0.9, - compensated ==0.6.1, - composition ==1.0.1.0, - compressed ==3.10, - concatenative ==1.0.1, - concurrent-extra ==0.7.0.9, - concurrent-supply ==0.1.7, - cond ==0.4.1.1, - conduit ==1.2.4, - conduit-combinators ==0.3.0.6, - conduit-extra ==1.1.7.0, - configurator ==0.3.0.0, - connection ==0.2.4, - constraints ==0.4.1.3, - containers installed, - containers-unicode-symbols ==0.3.1.1, - contravariant ==1.2.2, - control-monad-free ==0.5.3, - control-monad-loop ==0.1, - convertible ==1.1.0.0, - cookie ==0.4.1.4, - courier ==0.1.0.15, - cpphs ==1.18.9, - cprng-aes ==0.6.1, - cpu ==0.1.2, - criterion ==1.0.2.0, - crypto-api ==0.13.2, - cryptocipher ==0.6.2, - crypto-cipher-tests ==0.0.11, - crypto-cipher-types ==0.0.9, - cryptohash ==0.11.6, - cryptohash-conduit ==0.1.1, - cryptohash-cryptoapi ==0.1.3, - crypto-numbers ==0.2.7, - crypto-pubkey ==0.2.8, - crypto-pubkey-types ==0.4.3, - crypto-random ==0.0.8, - crypto-random-api ==0.2.0, - css-text ==0.1.2.1, - csv ==0.1.2, - csv-conduit ==0.6.3, - curl ==1.3.8, - data-accessor ==0.2.2.6, - data-accessor-mtl ==0.2.0.4, - data-binary-ieee754 ==0.4.4, - data-default ==0.5.3, - data-default-class ==0.0.1, - data-default-instances-base ==0.0.1, - data-default-instances-containers ==0.0.1, - data-default-instances-dlist ==0.0.1, - data-default-instances-old-locale ==0.0.1, - data-inttrie ==0.1.0, - data-lens-light ==0.1.2.1, - data-memocombinators ==0.5.1, - data-reify ==0.6, - DAV ==1.0.3, - Decimal ==0.4.2, - deepseq installed, - deepseq-generics ==0.1.1.2, - derive ==2.5.21, - diagrams ==1.2, - diagrams-builder ==0.6.0.3, - diagrams-cairo ==1.2.0.6, - diagrams-contrib ==1.1.2.5, - diagrams-core ==1.2.0.5, - diagrams-haddock ==0.2.2.13, - diagrams-lib ==1.2.0.8, - diagrams-postscript ==1.1.0.4, - diagrams-svg ==1.1.0.4, - Diff ==0.3.0, - digest ==0.0.1.2, - digestive-functors ==0.7.1.4, - dimensional ==0.13.0.1, - directory installed, - directory-tree ==0.12.0, - direct-sqlite ==2.3.15, - distributed-process ==0.5.3, - distributed-process-async ==0.2.1, - distributed-process-client-server ==0.1.2, - distributed-process-execution ==0.1.1, - distributed-process-extras ==0.2.0, - distributed-process-simplelocalnet ==0.2.2.0, - distributed-process-supervisor ==0.1.2, - distributed-process-task ==0.1.1, - distributed-static ==0.3.1.0, - distributive ==0.4.4, - djinn-ghc ==0.0.2.3, - djinn-lib ==0.0.1.2, - dlist ==0.7.1, - dlist-instances ==0.1, - doctest ==0.9.13, - double-conversion ==2.0.1.0, - dual-tree ==0.2.0.5, - easy-file ==0.2.0, - either ==4.3.3.2, - elm-build-lib ==0.14.0.0, - elm-compiler ==0.14.1, - elm-core-sources ==1.0.0, - elm-package ==0.2.2, - email-validate ==2.0.1, - enclosed-exceptions ==1.0.1, - entropy ==0.3.6, - enumerator ==0.4.20, - eq ==4.0.3, - erf ==2.0.0.0, - errorcall-eq-instance ==0.1.0, - errors ==1.4.7, - ersatz ==0.2.6.1, - esqueleto ==2.1.2.1, - exceptions ==0.6.1, - exception-transformers ==0.3.0.4, - executable-path ==0.0.3, - extensible-exceptions ==0.1.1.4, - extra ==1.0.1, - failure ==0.2.0.3, - fast-logger ==2.2.3, - fay ==0.21.2.1, - fay-base ==0.19.4.2, - fay-builder ==0.2.0.3, - fay-dom ==0.5.0.1, - fay-jquery ==0.6.0.3, - fay-text ==0.3.2.2, - fay-uri ==0.2.0.0, - fb ==1.0.8, - fb-persistent ==0.3.4, - fclabels ==2.0.2.2, - FenwickTree ==0.1.2, - fgl ==5.5.0.1, - file-embed ==0.0.8.2, - file-location ==0.4.6, - filemanip ==0.3.6.3, - filepath installed, - fingertree ==0.1.0.1, - fixed ==0.2.1.1, - fixed-list ==0.1.5, - flexible-defaults ==0.0.1.1, - focus ==0.1.3, - foldl ==1.0.7, - FontyFruity ==0.4.1, - force-layout ==0.3.0.9, - foreign-store ==0.1, - foreign-var ==0.0.0.1, - formatting ==6.0.0, - fpco-api ==1.2.0.5, - free ==4.10.0.1, - freenect ==1.2, - frisby ==0.2, - fsnotify ==0.1.0.3, - fuzzcheck ==0.1.1, - gd ==3000.7.3, - generic-aeson ==0.2.0.2, - generic-deriving ==1.6.3, - GenericPretty ==1.2.1, - generics-sop ==0.1.1, - ghc-heap-view ==0.5.3, - ghcid ==0.3.4, - ghc-mod ==5.2.1.2, - ghc-mtl ==1.2.1.0, - ghc-paths ==0.1.0.9, - ghc-prim installed, - ghc-syb-utils ==0.2.3, - gio ==0.13.0.4, - git-embed ==0.1.0, - gl ==0.6.3, - glib ==0.13.1.0, - Glob ==0.7.5, - GLURaw ==1.4.0.2, - GLUT ==2.5.1.1, - graph-core ==0.2.1.0, - graphs ==0.5.0.1, - gravatar ==0.6, - groundhog ==0.7.0.2, - groundhog-mysql ==0.7.0.1, - groundhog-postgresql ==0.7.0.2, - groundhog-sqlite ==0.7.0.1, - groundhog-th ==0.7.0, - groupoids ==4.0, - groups ==0.4.0.0, - gtk ==0.13.4, - gtk2hs-buildtools ==0.13.0.3, - haddock-api ==2.15.0.2, - haddock-library ==1.1.1, - half ==0.2.0.1, - HandsomeSoup ==0.3.5, - happstack-server ==7.3.9, - happy ==1.19.5, - hashable ==1.2.3.1, - hashable-extras ==0.2.0.1, - hashmap ==1.3.0.1, - hashtables ==1.2.0.2, - haskeline installed, - haskell2010 installed, - haskell98 installed, - haskell-lexer ==1.0, - haskell-names ==0.4.1, - haskell-packages ==0.2.4.4, - haskell-src ==1.0.2.0, - haskell-src-exts ==1.16.0.1, - haskell-src-meta ==0.6.0.8, - hasql ==0.7.2, - hasql-backend ==0.4.0, - hasql-postgres ==0.10.2, - hastache ==0.6.1, - HaTeX ==3.16.0.0, - HaXml ==1.25.3, - haxr ==3000.10.3.1, - HCodecs ==0.5, - hdaemonize ==0.5.0.0, - hdevtools ==0.1.0.6, - heaps ==0.3.1, - hebrew-time ==0.1.1, - heist ==0.14.1, - here ==1.2.6, - heredoc ==0.2.0.0, - hflags ==0.4, - highlighting-kate ==0.5.11.1, - hinotify ==0.3.7, - hint ==0.4.2.2, - histogram-fill ==0.8.4.1, - hit ==0.6.3, - hjsmin ==0.1.4.7, - hledger ==0.24, - hledger-lib ==0.24, - hlibgit2 ==0.18.0.14, - hlint ==1.9.16, - hmatrix ==0.16.1.4, - hmatrix-gsl ==0.16.0.3, - hoauth2 ==0.4.3, - holy-project ==0.1.1.1, - hoogle ==4.2.38, - hoopl installed, - hOpenPGP ==1.11, - hostname ==1.0, - hostname-validate ==1.0.0, - hourglass ==0.2.8, - hpc installed, - hPDB ==1.2.0.2, - hPDB-examples ==1.2.0.1, - hs-bibutils ==5.5, - hscolour ==1.20.3, - hse-cpp ==0.1, - hslogger ==1.2.8, - hslua ==0.3.13, - hspec ==2.1.4, - hspec2 ==0.6.1, - hspec-core ==2.1.4, - hspec-discover ==2.1.4, - hspec-expectations ==0.6.1.1, - hspec-meta ==2.0.0, - hspec-wai ==0.6.3, - hspec-wai-json ==0.6.0, - HStringTemplate ==0.7.3, - hsyslog ==2.0, - HTF ==0.12.2.3, - html ==1.0.1.2, - html-conduit ==1.1.1.1, - HTTP ==4000.2.19, - http-client ==0.4.8, - http-client-tls ==0.2.2, - http-conduit ==2.1.5, - http-date ==0.0.5, - http-reverse-proxy ==0.4.1.2, - http-types ==0.8.6, - HUnit ==1.2.5.2, - hweblib ==0.6.3, - hxt ==9.3.1.15, - hxt-charproperties ==9.2.0.1, - hxt-http ==9.1.5.2, - hxt-pickle-utils ==0.1.0.2, - hxt-regex-xmlschema ==9.2.0.2, - hxt-relaxng ==9.1.5.5, - hxt-unicode ==9.0.2.4, - hybrid-vectors ==0.1.2.1, - hyphenation ==0.4.2, - idna ==0.3.0, - ieee754 ==0.7.6, - IfElse ==0.85, - imagesize-conduit ==1.0.0.4, - immortal ==0.2, - incremental-parser ==0.2.3.4, - indents ==0.3.3, - ini ==0.3.1, - integer-gmp installed, - integration ==0.2.1, - interpolate ==0.1.0, - interpolatedstring-perl6 ==0.9.0, - intervals ==0.7.1, - io-choice ==0.0.5, - io-manager ==0.1.0.2, - io-memoize ==1.1.1.0, - iproute ==1.3.1, - iterable ==3.0, - ixset ==1.0.6, - js-flot ==0.8.3, - js-jquery ==1.11.2, - json-autotype ==0.2.5.4, - json-schema ==0.7.3.1, - JuicyPixels ==3.2.3, - JuicyPixels-repa ==0.7, - kan-extensions ==4.2.1, - kdt ==0.2.2, - keter ==1.3.8, - keys ==3.10.1, - kure ==2.16.6, - language-c ==0.4.7, - language-ecmascript ==0.16.2, - language-glsl ==0.1.1, - language-haskell-extract ==0.2.4, - language-java ==0.2.7, - language-javascript ==0.5.13.3, - lazy-csv ==0.5, - lca ==0.2.4, - lens ==4.6.0.1, - lens-aeson ==1.0.0.3, - lens-family-th ==0.4.1.0, - lhs2tex ==1.18.1, - libgit ==0.3.0, - libnotify ==0.1.1.0, - lifted-async ==0.2.0.2, - lifted-base ==0.2.3.6, - linear ==1.15.5, - linear-accelerate ==0.2, - list-t ==0.4.3, - loch-th ==0.2.1, - log-domain ==0.9.3, - logfloat ==0.12.1, - logict ==0.6.0.2, - loop ==0.2.0, - lucid ==2.5, - lzma-conduit ==1.1.3, - machines ==0.4.1, - mandrill ==0.1.1.0, - map-syntax ==0.2, - markdown ==0.1.13.1, - markdown-unlit ==0.2.0.1, - math-functions ==0.1.5.2, - matrix ==0.3.4.2, - MaybeT ==0.1.2, - MemoTrie ==0.6.2, - mersenne-random-pure64 ==0.2.0.4, - messagepack ==0.3.0, - messagepack-rpc ==0.1.0.3, - mime-mail ==0.4.8.1, - mime-mail-ses ==0.3.2.2, - mime-types ==0.1.0.5, - missing-foreign ==0.1.1, - MissingH ==1.3.0.1, - mmap ==0.5.9, - mmorph ==1.0.4, - MonadCatchIO-transformers ==0.3.1.3, - monad-control ==0.3.3.1, - monad-coroutine ==0.8.0.1, - monadcryptorandom ==0.6.1, - monad-extras ==0.5.9, - monadic-arrays ==0.2.1.3, - monad-journal ==0.6.0.2, - monad-logger ==0.3.13.1, - monad-loops ==0.4.2.1, - monad-par ==0.3.4.7, - monad-parallel ==0.7.1.4, - monad-par-extras ==0.3.3, - monad-primitive ==0.1, - monad-products ==4.0.0.1, - MonadPrompt ==1.0.0.5, - MonadRandom ==0.3.0.1, - monad-st ==0.2.4, - monads-tf ==0.1.0.2, - mongoDB ==2.0.3, - monoid-extras ==0.3.3.5, - monoid-subclasses ==0.3.6.2, - mono-traversable ==0.7.0, - mtl ==2.1.3.1, - mtlparse ==0.1.4.0, - mtl-prelude ==1.0.3, - multimap ==1.2.1, - multipart ==0.1.2, - MusicBrainz ==0.2.3, - mutable-containers ==0.2.1.2, - mwc-random ==0.13.3.0, - mysql ==0.1.1.7, - mysql-simple ==0.2.2.4, - nanospec ==0.2.0, - nats ==1, - neat-interpolation ==0.2.2, - nettle ==0.1.0, - network ==2.6.0.2, - network-conduit-tls ==1.1.0.2, - network-info ==0.2.0.5, - network-multicast ==0.0.11, - network-simple ==0.4.0.4, - network-transport ==0.4.1.0, - network-transport-tcp ==0.4.1, - network-transport-tests ==0.2.2.0, - network-uri ==2.6.0.1, - newtype ==0.2, - nsis ==0.2.4, - numbers ==3000.2.0.1, - numeric-extras ==0.0.3, - NumInstances ==1.4, - numtype ==1.1, - Octree ==0.5.4.2, - old-locale installed, - old-time installed, - OneTuple ==0.2.1, - opaleye ==0.3.1, - OpenGL ==2.9.2.0, - OpenGLRaw ==1.5.0.1, - openpgp-asciiarmor ==0.1, - operational ==0.2.3.2, - options ==1.2.1.1, - optparse-applicative ==0.11.0.2, - osdkeys ==0.0, - pandoc ==1.13.2, - pandoc-citeproc ==0.6, - pandoc-types ==1.12.4.1, - pango ==0.13.0.5, - parallel ==3.2.0.6, - parallel-io ==0.3.3, - parseargs ==0.1.5.2, - parsec ==3.1.8, - parsers ==0.12.1.1, - partial-handler ==0.1.0, - path-pieces ==0.1.5, - patience ==0.1.1, - pcre-light ==0.4.0.3, - pdfinfo ==1.5.2, - pem ==0.2.2, - persistent ==2.1.1.7, - persistent-mongoDB ==2.1.2.1, - persistent-mysql ==2.1.2.1, - persistent-postgresql ==2.1.2.2, - persistent-sqlite ==2.1.1.2, - persistent-template ==2.1.0.1, - phantom-state ==0.2.0.2, - pipes ==4.1.4, - pipes-concurrency ==2.0.3, - pipes-parse ==3.0.2, - placeholders ==0.1, - pointed ==4.2, - polyparse ==1.10, - pool-conduit ==0.1.2.3, - postgresql-binary ==0.5.1, - postgresql-libpq ==0.9.0.2, - postgresql-simple ==0.4.10.0, - pqueue ==1.2.1, - prefix-units ==0.1.0.2, - prelude-extras ==0.4, - present ==2.2, - pretty installed, - prettyclass ==1.0.0.0, - pretty-class ==1.0.1.1, - pretty-show ==1.6.8.2, - primes ==0.2.1.0, - primitive ==0.5.4.0, - process installed, - process-conduit ==1.2.0.1, - process-extras ==0.2.0, - product-profunctors ==0.6, - profunctor-extras ==4.0, - profunctors ==4.3.2, - project-template ==0.1.4.2, - publicsuffixlist ==0.1, - punycode ==2.0, - pure-io ==0.2.1, - pureMD5 ==2.1.2.1, - pwstore-fast ==2.4.4, - quandl-api ==0.2.0.0, - QuasiText ==0.1.2.5, - QuickCheck ==2.7.6, - quickcheck-assertions ==0.1.1, - quickcheck-instances ==0.3.10, - quickcheck-io ==0.1.1, - quickcheck-unicode ==1.0.0.0, - quickpull ==0.4.0.0, - rainbow ==0.20.0.4, - rainbow-tests ==0.20.0.4, - random ==1.0.1.1, - random-fu ==0.2.6.2, - random-shuffle ==0.0.4, - random-source ==0.3.0.6, - rank1dynamic ==0.2.0.1, - Rasterific ==0.4.2, - raw-strings-qq ==1.0.2, - ReadArgs ==1.2.2, - reducers ==3.10.3.1, - reflection ==1.5.1.1, - regex-applicative ==0.3.1, - regex-base ==0.93.2, - regex-compat ==0.95.1, - regex-pcre-builtin ==0.94.4.8.8.35, - regex-posix ==0.95.2, - regexpr ==0.5.4, - regex-tdfa ==1.2.0, - regex-tdfa-rc ==1.1.8.3, - regular ==0.3.4.4, - regular-xmlpickler ==0.2, - rematch ==0.2.0.0, - repa ==3.3.1.2, - repa-algorithms ==3.3.1.2, - repa-devil ==0.3.2.2, - repa-io ==3.3.1.2, - reroute ==0.2.2.1, - resource-pool ==0.2.3.2, - resourcet ==1.1.4.1, - rest-client ==0.4.0.5, - rest-core ==0.33.1.2, - rest-gen ==0.16.1.8, - rest-happstack ==0.2.10.4, - rest-snap ==0.1.17.14, - rest-stringmap ==0.2.0.3, - rest-types ==1.11.1.1, - rest-wai ==0.1.0.4, - rev-state ==0.1, - rfc5051 ==0.1.0.3, - runmemo ==1.0.0.1, - rvar ==0.2.0.2, - safe ==0.3.8, - safecopy ==0.8.4, - scientific ==0.3.3.7, - scotty ==0.9.0, - scrobble ==0.2.1.1, - securemem ==0.1.7, - semigroupoid-extras ==4.0, - semigroupoids ==4.2, - semigroups ==0.16.2.2, - sendfile ==0.7.9, - seqloc ==0.6.1.1, - setenv ==0.1.1.3, - SHA ==1.6.4.1, - shake ==0.14.3, - shake-language-c ==0.6.4, - shakespeare ==2.0.4.1, - shakespeare-i18n ==1.1.0, - shakespeare-text ==1.1.0, - shell-conduit ==4.5.2, - shelly ==1.5.7, - silently ==1.2.4.1, - simple-reflect ==0.3.2, - simple-sendfile ==0.2.18, - singletons ==1.0, - siphash ==1.0.3, - skein ==1.0.9.2, - slave-thread ==0.1.5, - smallcheck ==1.1.1, - smtLib ==1.0.7, - snap ==0.13.3.2, - snap-core ==0.9.6.4, - snaplet-fay ==0.3.3.10, - snap-server ==0.9.4.6, - socks ==0.5.4, - sodium ==0.11.0.3, - sourcemap ==0.1.3.0, - speculation ==1.5.0.1, - sphinx ==0.6.0.1, - split ==0.2.2, - Spock ==0.7.7.0, - Spock-digestive ==0.1.0.0, - Spock-worker ==0.2.1.3, - spoon ==0.3.1, - sqlite-simple ==0.4.8.0, - stackage ==0.3.1, - stateref ==0.3, - statestack ==0.2.0.3, - statistics ==0.13.2.1, - statistics-linreg ==0.3, - stm ==2.4.4, - stm-chans ==3.0.0.2, - stm-conduit ==2.5.4, - stm-containers ==0.2.8, - stm-stats ==0.2.0.0, - storable-complex ==0.2.2, - storable-endian ==0.2.5, - streaming-commons ==0.1.10.0, - streams ==3.2, - strict ==0.3.2, - stringable ==0.1.3, - stringbuilder ==0.5.0, - stringprep ==1.0.0, - stringsearch ==0.3.6.5, - stylish-haskell ==0.5.11.1, - SVGFonts ==1.4.0.3, - syb ==0.4.4, - syb-with-class ==0.6.1.5, - system-canonicalpath ==0.2.3.0, - system-fileio ==0.3.16.1, - system-filepath ==0.4.13.2, - system-posix-redirect ==1.1.0.1, - tabular ==0.2.2.7, - tagged ==0.7.3, - tagshare ==0.0, - tagsoup ==0.13.3, - tagstream-conduit ==0.5.5.3, - tar ==0.4.1.0, - tardis ==0.3.0.0, - tasty ==0.10.1, - tasty-ant-xml ==1.0.1, - tasty-golden ==2.2.2.4, - tasty-hunit ==0.9.1, - tasty-kat ==0.0.3, - tasty-quickcheck ==0.8.3.2, - tasty-smallcheck ==0.8.0.1, - tasty-th ==0.1.3, - template-haskell installed, - temporary ==1.2.0.3, - temporary-rc ==1.2.0.3, - terminal-progress-bar ==0.0.1.4, - terminal-size ==0.3.0, - terminfo installed, - test-framework ==0.8.1.1, - test-framework-hunit ==0.3.0.1, - test-framework-quickcheck2 ==0.3.0.3, - test-framework-th ==0.2.4, - testing-feat ==0.4.0.2, - testpack ==2.1.3.0, - texmath ==0.8.0.1, - text ==1.2.0.4, - text-binary ==0.1.0, - text-format ==0.3.1.1, - text-icu ==0.7.0.1, - tf-random ==0.5, - th-desugar ==1.4.2.1, - th-expand-syns ==0.3.0.5, - th-extras ==0.0.0.2, - th-lift ==0.7.2, - th-orphans ==0.8.3, - threads ==0.5.1.3, - th-reify-many ==0.1.3, - thyme ==0.3.5.5, - time installed, - time-compat ==0.1.0.3, - time-lens ==0.4.0.1, - timezone-olson ==0.1.6, - timezone-series ==0.1.4, - tls ==1.2.16, - tls-debug ==0.3.4, - tostring ==0.2.1.1, - transformers installed, - transformers-base ==0.4.4, - transformers-compat ==0.3.3.3, - traverse-with-class ==0.2.0.3, - tree-view ==0.4, - tuple ==0.3.0.2, - type-eq ==0.4.2, - type-list ==0.0.0.1, - udbus ==0.2.1, - unbounded-delays ==0.1.0.9, - union-find ==0.2, - uniplate ==1.6.12, - unix installed, - unix-compat ==0.4.1.4, - unix-time ==0.3.5, - unordered-containers ==0.2.5.1, - uri-encode ==1.5.0.4, - url ==2.1.3, - utf8-light ==0.4.2, - utf8-string ==0.3.8, - uuid ==1.3.8, - vault ==0.3.0.4, - vector ==0.10.12.2, - vector-algorithms ==0.6.0.3, - vector-binary-instances ==0.2.1.0, - vector-instances ==3.3.0.1, - vector-space ==0.8.7, - vector-space-points ==0.2.1, - vector-th-unbox ==0.2.1.2, - vhd ==0.2.2, - void ==0.7, - wai ==3.0.2.3, - wai-app-static ==3.0.0.6, - wai-conduit ==3.0.0.2, - wai-eventsource ==3.0.0, - wai-extra ==3.0.4.5, - wai-logger ==2.2.3, - wai-middleware-static ==0.6.0.1, - wai-websockets ==3.0.0.5, - warp ==3.0.9.3, - warp-tls ==3.0.2, - webdriver ==0.6.1, - web-fpco ==0.1.1.0, - websockets ==0.9.3.0, - wizards ==1.0.1, - wl-pprint ==1.1, - wl-pprint-extras ==3.5.0.4, - wl-pprint-terminfo ==3.7.1.3, - wl-pprint-text ==1.1.0.3, - word8 ==0.1.2, - wordpass ==1.0.0.2, - X11 ==1.6.1.2, - x509 ==1.5.0.1, - x509-store ==1.5.0, - x509-system ==1.5.0, - x509-validation ==1.5.1, - xenstore ==0.1.1, - xhtml installed, - xml ==1.3.14, - xml-conduit ==1.2.3.3, - xmlgen ==0.6.2.1, - xml-hamlet ==0.4.0.10, - xmlhtml ==0.2.3.4, - xml-types ==0.3.4, - xss-sanitize ==0.3.5.5, - yackage ==0.7.0.7, - yaml ==0.8.10.1, - Yampa ==0.9.6, - YampaSynth ==0.2, - yesod ==1.4.1.4, - yesod-auth ==1.4.3.1, - yesod-auth-deskcom ==1.4.0, - yesod-auth-fb ==1.6.6, - yesod-auth-hashdb ==1.4.1.2, - yesod-auth-oauth2 ==0.0.12, - yesod-bin ==1.4.4, - yesod-core ==1.4.8.1, - yesod-eventsource ==1.4.0.1, - yesod-fay ==0.7.1, - yesod-fb ==0.3.4, - yesod-form ==1.4.4, - yesod-gitrepo ==0.1.1.0, - yesod-newsfeed ==1.4.0.1, - yesod-persistent ==1.4.0.2, - yesod-sitemap ==1.4.0.1, - yesod-static ==1.4.0.4, - yesod-test ==1.4.3.1, - yesod-text-markdown ==0.1.7, - yesod-websockets ==0.2.1.1, - zeromq4-haskell ==0.6.3, - zip-archive ==0.2.3.7, - zlib ==0.5.4.2, - zlib-bindings ==0.1.1.5, - zlib-enum ==0.2.3.1, - zlib-lens ==0.1.1.2 diff --git a/examples/CRP.hs b/examples/CRP.hs @@ -1,98 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} - --- | An example defining measures for various finite realizations of a Chinese --- Restaurant Process. - -import Control.Applicative -import Control.Lens -import Control.Monad.Trans -import Data.IntMap.Strict (IntMap) -import qualified Data.IntMap.Strict as IntMap -import Measurable.Core - -data Table = Table { - _number :: {-# UNPACK #-} !Int - , _people :: {-# UNPACK #-} !Int - } deriving (Eq, Show) - -instance Ord Table where - t1 < t2 = _people t1 < _people t2 - t1 <= t2 = _people t1 <= _people t2 - -makeLenses ''Table - --- | Mass function for a given table. It's dependent on the state of the --- restaurant via @n@ and @newestTable@. -tableMass :: (Fractional a, Integral b) => b -> a -> Table -> Table -> a -tableMass n a newestTable table - | table^.number == newestTable^.number = a / (fromIntegral n + a) - | otherwise = fromIntegral (table^.people) / (fromIntegral n + a) - --- | A measure defined over tables. -tableMeasure - :: (Integral b, Applicative m, Monad m, Traversable t) - => b - -> Double - -> Table - -> t Table - -> MeasureT m Table -tableMeasure n a newestTable = - fromDensityCountingT (tableMass n a newestTable) - --- | A probability measure over restaurants, represented by IntMaps. -restaurantMeasure - :: (Monad m, Applicative m) - => Double - -> IntMap Table - -> MeasureT m (IntMap Table) -restaurantMeasure a restaurant = do - let numCustomers = sumOf (traverse.people) restaurant - numTables = lengthOf traverse restaurant - nextTableNum = succ numTables - possibleTable = Table nextTableNum 1 - possibleRestaurant = - IntMap.insert nextTableNum possibleTable restaurant - - table <- tableMeasure numCustomers a - possibleTable possibleRestaurant - - let newTable - | table^.number == possibleTable^.number = table - | otherwise = table&people %~ succ - - return (IntMap.insert (newTable^.number) newTable restaurant) - --- | A measure for a finite realization of a CRP measure with a given number of --- customers and concentration parameter. -chineseRestaurantProcess - :: (Enum a, Eq a, Monad m, Applicative m, Num a) - => a - -> Double - -> MeasureT m (IntMap Table) -chineseRestaurantProcess n a = go n IntMap.empty where - go 0 restaurant = return restaurant - go j restaurant = restaurantMeasure a restaurant >>= go (pred j) - -main :: IO () -main = do - let numTables = fromIntegral . lengthOf traverse - tinyRestaurant = chineseRestaurantProcess 2 1 - smallRestaurant = chineseRestaurantProcess 3 1 - bigRestaurant = chineseRestaurantProcess 9 1 - bigRestaurantAntisocial = chineseRestaurantProcess 9 3 - - meanTinyRestaurant <- integrate numTables tinyRestaurant - meanSmallRestaurant <- integrate numTables smallRestaurant - meanBigRestaurant <- integrate numTables bigRestaurant - meanBigRestaurantAntisocial <- integrate numTables bigRestaurantAntisocial - - let numCustomers = fromIntegral . sumOf (traverse.people) - - differentQuestion <- integrate numCustomers bigRestaurantAntisocial - - print meanTinyRestaurant - print meanSmallRestaurant - print meanBigRestaurant - print meanBigRestaurantAntisocial - print differentQuestion - diff --git a/measurable.cabal b/measurable.cabal @@ -1,8 +1,7 @@ name: measurable -version: 1.0.0.1 +version: 1.0.0 license: BSD3 license-file: LICENSE -copyright: (c) Jared Tobin 2013 - 2015. author: Jared Tobin maintainer: jared@jtobin.ca stability: Experimental @@ -10,25 +9,26 @@ category: Math homepage: http://github.com/jtobin/measurable bug-reports: http://github.com/jtobin/measurable/issues build-type: Simple -cabal-version: >=1.18 +cabal-version: >= 1.18 synopsis: A shallowly-embedded DSL for basic measure wrangling. description: @measurable@ is a simple shallowly-embedded DSL for dealing with measures. - + . It adds a @Measure@ synonym for a standard continuation type with a restricted output type and no @callCC@ implementation. - + . You can construct measures from samples, mass/density functions, or even sampling functions. - + . Construct image measures by @fmap@-ing measurable functions over them, or create new measures from existing ones by seamless measure arithmetic provided by a simple @Num@ instance. Create measures from graphs of other measures - using the @Monad@ instance and do-notation. - + using the @Monad@ instance and do-notation. The @Applicative@ instance + gives you product measure. + . Query measures by integrating meaurable functions against them. Extract moments, cumulative density functions, or probabilities. - + . Caveat: while fun to play with, and rewarding to see how measures fit together, measure operations as nested integrals are exponentially complex. Don't expect them to scale very far! @@ -41,16 +41,12 @@ library hs-source-dirs: src default-language: Haskell2010 exposed-modules: - Measurable.Core + Measurable + , Measurable.Core , Measurable.Measures - , Measurable.Util - - other-extensions: - BangPatterns - FlexibleInstances build-depends: - base >= 4.7 && < 4.8 + base , foldl , integration , math-functions @@ -58,23 +54,3 @@ library , statistics , transformers -Test-suite measurable-examples - type: exitcode-stdio-1.0 - hs-source-dirs: src, examples - main-is: CRP.hs - default-language: Haskell2010 - ghc-options: - -threaded -rtsopts - build-depends: - base >= 4.7 && < 4.8 - , containers - , foldl - , integration - , lens - , measurable - , mtl - , mwc-random - , primitive - , statistics - , transformers - diff --git a/src/Measurable.hs b/src/Measurable.hs @@ -0,0 +1,5 @@ + +module Measurable where + +import Measurable.Core +import Measurable.Measures diff --git a/src/Measurable/Core.hs b/src/Measurable/Core.hs @@ -1,112 +1,92 @@ {-# OPTIONS_GHC -Wall #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} {-# OPTIONS_GHC -fno-warn-type-defaults #-} -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE FlexibleInstances #-} module Measurable.Core where import Control.Applicative -import Control.Monad -import Control.Monad.Trans -import Data.Foldable (Foldable) -import qualified Data.Foldable as Foldable -import Data.Functor.Identity -import Data.Traversable -import Measurable.Util +import Control.Foldl (Fold) +import qualified Control.Foldl as Foldl +import Data.List (foldl') import Numeric.Integration.TanhSinh --- | A hand-rolled continuation type. Exactly like the standard one you'd find --- in @Control.Monad.Trans.Cont@, but without the supporting functions like --- @callCC@, etc. included in that module. -newtype ContT r m a = ContT { runContT :: (a -> m r) -> m r } - -type Cont r = ContT r Identity - -runCont :: Cont r a -> (a -> r) -> r -runCont m k = runIdentity $ runContT m (Identity . k) - -cont :: ((a -> r) -> r) -> Cont r a -cont f = ContT $ \c -> Identity $ f (runIdentity . c) - -- | A measure can be represented by nothing more than a continuation with a -- restricted output type corresponding to the reals. -- -- A @Functor@ instance implements pushforward or image measures - merely -- @fmap@ a measurable function over a measure to create one. -- --- An @Applicative@ instance adds measure convolution, subtraction, and --- multiplication by enabling a @Num@ instance via 'liftA2' and an implicit --- marginalizing effect. A @Monad@ instance lumps the ability to create --- measures from graphs of measures on top of that. -type Measure a = Cont Double a -type MeasureT m a = ContT Double m a +-- An @Applicative@ instance adds product measure, and in turn measure +-- convolution, subtraction, and multiplication by enabling a @Num@ instance. +-- +-- A @Monad@ instance lumps the ability to create measures from graphs of +-- measures on top of that. +newtype Measure a = Measure ((a -> Double) -> Double) -instance Functor (ContT r m) where - fmap f m = ContT $ \c -> runContT m (c . f) +instance Functor Measure where + fmap f nu = Measure $ \g -> + integrate (g . f) nu -instance Applicative (ContT r m) where - pure x = ContT ($ x) - f <*> v = ContT $ \c -> - runContT f $ \g -> - runContT v (c . g) +instance Applicative Measure where + pure x = Measure (\f -> f x) + Measure h <*> Measure g = Measure $ \f -> + h (\k -> g (f . k)) -instance Monad (ContT r m) where - return x = ContT ($ x) - m >>= k = ContT $ \c -> - runContT m $ \x -> - runContT (k x) c +instance Monad Measure where + return x = Measure (\f -> f x) + rho >>= g = Measure $ \f -> + integrate (\nu -> integrate f (g nu)) rho -instance MonadTrans (ContT r) where - lift m = ContT (m >>=) +instance Num a => Num (Measure a) where + (+) = liftA2 (+) + (-) = liftA2 (-) + (*) = liftA2 (*) + abs = fmap abs + signum = fmap signum + fromInteger = pure . fromInteger -- | The 'integrate' function is just 'runCont' with its arguments reversed -- in order to resemble the conventional mathematical notation, in which one -- integrates a measurable function against a measure. -- --- >>> let mu = fromSamples [-1, 0, 1] +-- >>> let mu = fromSample [-1, 0, 1] -- >>> expectation mu -- 0.0 -- >>> variance mu -- 0.6666666666666666 integrate :: (a -> Double) -> Measure a -> Double -integrate = flip runCont +integrate f (Measure nu) = nu f -integrateT :: Applicative m => (a -> Double) -> MeasureT m a -> m Double -integrateT f = (`runContT` (pure . f)) +-- | The expectation of a measure is typically understood to be its expected +-- value, which is found by integrating it against the identity function. +expectation :: Measure Double -> Double +expectation = integrate id -instance (Applicative m, Num a) => Num (ContT Double m a) where - (+) = liftA2 (+) - (-) = liftA2 (-) - (*) = liftA2 (*) - abs = fmap id - signum = fmap signum - fromInteger = pure . fromInteger +-- | The variance of a measure, as per the usual formula +-- @var X = E^2 X - EX^2@. +variance :: Measure Double -> Double +variance mu = integrate (^ 2) mu - expectation mu ^ 2 + +-- | Calculates the volume of a 'Measure' over its entire space. Trivially 1 +-- for any probability measure. +-- +-- >>> let mu = fromSample [1..10] +-- >>> volume mu +-- 1.0 +volume :: Measure a -> Double +volume = integrate $ const 1 -- | Create a 'Measure' from a probability mass function and its support, -- provided as a foldable container. -- -- The requirement to supply the entire support is restrictive but necessary; --- for approximations, consider using 'fromSamples' or --- 'fromSamplingFunction'. +-- for approximations, consider using 'fromSample'. -- -- >>> let mu = fromMassFunction (binomialPmf 10 0.2) [0..10] -- >>> integrate fromIntegral mu -- 2.0 -fromMassFunction - :: (Functor f, Foldable f) - => (a -> Double) - -> f a - -> Measure a -fromMassFunction f support = cont $ \g -> - Foldable.sum $ (g /* f) <$> support - -fromMassFunctionT :: (Applicative m, Traversable t) - => (a -> Double) - -> t a - -> MeasureT m a -fromMassFunctionT f support = ContT $ \g -> - fmap Foldable.sum . traverse (g //* (pure . f)) $ support +fromMassFunction :: Foldable f => (a -> Double) -> f a -> Measure a +fromMassFunction f support = Measure $ \g -> + foldl' (\acc x -> acc + f x * g x) 0 support -- | Create a 'Measure' from a probability density function. -- @@ -120,135 +100,71 @@ fromMassFunctionT f support = ContT $ \g -> -- >>> variance mu -- 1.0000000000000002 fromDensityFunction :: (Double -> Double) -> Measure Double -fromDensityFunction d = cont $ \f -> quadratureTanhSinh $ f /* d where - quadratureTanhSinh = result . last . everywhere trap +fromDensityFunction d = Measure $ \f -> + quadratureTanhSinh (\x -> f x * d x) + where + quadratureTanhSinh = result . last . everywhere trap -- | Create a measure from a collection of observations. -- -- Useful for creating general purpose empirical measures. -- --- >>> let mu = fromSamples [(1, 2), (3, 4)] +-- >>> let mu = fromSample [(1, 2), (3, 4)] -- >>> integrate (uncurry (+)) mu -- 5.0 -fromSamples :: Foldable f => f a -> Measure a -fromSamples = cont . flip weightedAverage - -fromSamplesT - :: (Applicative m, Traversable f) - => f a - -> MeasureT m a -fromSamplesT = ContT . flip weightedAverageM - --- | Create a measure from a sampling function. Runs the sampling function --- the provided number of times and runs 'fromSamples' on the result. -fromSamplingFunction - :: (Monad m, Applicative m) - => (t -> m b) - -> Int - -> t - -> MeasureT m b -fromSamplingFunction f n g = (lift $ replicateM n (f g)) >>= fromSamplesT - --- | A simple alias for @fmap@. -push :: (a -> b) -> Measure a -> Measure b -push = fmap - -pushT :: Monad m => (a -> b) -> MeasureT m a -> MeasureT m b -pushT = fmap +fromSample :: Foldable f => f a -> Measure a +fromSample = Measure . flip weightedAverage where + weightedAverage :: (Foldable f, Fractional r) => (a -> r) -> f a -> r + weightedAverage f = Foldl.fold (weightedAverageFold f) --- | The expectation of a measure is typically understood to be its expected --- value, which is found by integrating it against the identity function. -expectation :: Measure Double -> Double -expectation = integrate id + weightedAverageFold :: Fractional r => (a -> r) -> Fold a r + weightedAverageFold f = Foldl.premap f averageFold -expectationT :: Applicative m => MeasureT m Double -> m Double -expectationT = integrateT id - --- | The variance of a measure, as per the usual formula --- @var X = E^2 X - EX^2@. -variance :: Measure Double -> Double -variance mu = integrate (^ 2) mu - expectation mu ^ 2 - -varianceT :: Applicative m => MeasureT m Double -> m Double -varianceT mu = liftA2 (-) (integrateT (^ 2) mu) ((^ 2) <$> expectationT mu) + averageFold :: Fractional a => Fold a a + averageFold = (/) <$> Foldl.sum <*> Foldl.genericLength -- | The @nth@ raw moment of a 'Measure'. rawMoment :: Int -> Measure Double -> Double rawMoment n = integrate (^ n) -rawMomentT :: (Applicative m, Monad m) => Int -> MeasureT m Double -> m Double -rawMomentT n = integrateT (^ n) - --- | All raw moments of a 'Measure'. -rawMoments :: Measure Double -> [Double] -rawMoments mu = (`rawMoment` mu) <$> [1..] - -rawMomentsT :: (Applicative m, Monad m) => MeasureT m Double -> Int -> m [Double] -rawMomentsT mu n = traverse (`rawMomentT` mu) $ take n [1..] - -- | The @nth@ central moment of a 'Measure'. centralMoment :: Int -> Measure Double -> Double -centralMoment n mu = integrate (\x -> (x - rm) ^ n) $ mu - where rm = rawMoment 1 mu - -centralMomentT :: (Applicative m, Monad m) => Int -> MeasureT m Double -> m Double -centralMomentT n mu = integrateT (^ n) $ do - rm <- lift $ rawMomentT 1 mu - (subtract rm) <$> mu - --- | All central moments of a 'Measure'. -centralMoments :: Measure Double -> [Double] -centralMoments mu = (`centralMoment` mu) <$> [1..] - -centralMomentsT :: (Applicative m, Monad m) => MeasureT m Double -> Int -> m [Double] -centralMomentsT mu n = traverse (`centralMomentT` mu) $ take n [1..] +centralMoment n mu = integrate (\x -> (x - rm) ^ n) mu where + rm = rawMoment 1 mu -- | The moment generating function corresponding to a 'Measure'. -- --- >>> let mu = fromSamples [1..10] --- >>> let mgfMu = momentGeneratingFunction mu +-- >>> let mu = fromSample [1..10] +-- >>> let mgfMu = mgf mu -- >>> fmap mgfMu [0, 0.5, 1] -- [1.0,37.4649671547254,3484.377384533132] -momentGeneratingFunction :: Measure Double -> Double -> Double -momentGeneratingFunction mu t = integrate (exp . (* t)) mu +mgf :: Measure Double -> Double -> Double +mgf mu t = integrate (\x -> exp (t * x)) mu -- | The cumulant generating function corresponding to a 'Measure'. -- --- >>> let mu = fromSamples [1..10] --- >>> let cgfMu = cumulantGeneratingFunction mu +-- >>> let mu = fromSample [1..10] +-- >>> let cgfMu = cgf mu -- >>> fmap cgfMu [0, 0.5, 1] -- [0.0,3.6234062871236543,8.156044651432666] -cumulantGeneratingFunction :: Measure Double -> Double -> Double -cumulantGeneratingFunction mu = log . momentGeneratingFunction mu - --- | Calculates the volume of a 'Measure' over its entire space. Trivially 1 --- for any probability measure. --- --- >>> let mu = fromSamples [1..10] --- >>> volume mu --- 1.0 -volume :: Measure a -> Double -volume = integrate $ const 1 - -volumeT :: Applicative m => MeasureT m a -> m Double -volumeT = integrateT $ const 1 +cgf :: Measure Double -> Double -> Double +cgf mu = log . mgf mu -- | The cumulative distribution function corresponding to a 'Measure' -- --- >>> let mu = fromSamples [1..10] +-- >>> let mu = fromSample [1..10] -- >>> let cdfMu = cdf mu -- >>> fmap cdfMu [0..10] -- [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0] cdf :: Measure Double -> Double -> Double -cdf mu x = expectation $ negativeInfinity `to` x <$> mu +cdf nu x = integrate (negativeInfinity `to` x) nu where + negativeInfinity = negate (1 / 0) -cdfT :: Applicative m => MeasureT m Double -> Double -> m Double -cdfT mu x = expectationT $ negativeInfinity `to` x <$> mu -- | A helpful utility for calculating the volume of a region in a measure -- space. -- --- >>> let mu = fromSamples [1..10] +-- >>> let mu = fromSample [1..10] -- >>> integrate (2 `to` 8) mu -- 0.7 to :: (Num a, Ord a) => a -> a -> a -> a @@ -259,7 +175,7 @@ to a b x -- | An analogue of 'to' for measures defined over non-ordered domains. -- -- >>> data Group = A | B | C deriving Eq --- >>> let mu = fromSamples [A, A, A, B, A, B, C] +-- >>> let mu = fromSample [A, A, A, B, A, B, C] -- >>> integrate (containing [B]) mu -- 0.2857142857142857 -- >>> integrate (containing [A,C]) mu @@ -271,3 +187,285 @@ containing xs x | x `elem` xs = 1 | otherwise = 0 + + + + + + + + + + + + + + + + + + + + + + +-- -- | A hand-rolled continuation type. Exactly like the standard one you'd find +-- -- in @Control.Monad.Trans.Cont@, but without the supporting functions like +-- -- @callCC@, etc. included in that module. +-- newtype ContT r m a = ContT { runContT :: (a -> m r) -> m r } +-- +-- type Cont r = ContT r Identity +-- +-- -- | A measure can be represented by nothing more than a continuation with a +-- -- restricted output type corresponding to the reals. +-- -- +-- -- A @Functor@ instance implements pushforward or image measures - merely +-- -- @fmap@ a measurable function over a measure to create one. +-- -- +-- -- An @Applicative@ instance adds measure convolution, subtraction, and +-- -- multiplication by enabling a @Num@ instance via 'liftA2' and an implicit +-- -- marginalizing effect. A @Monad@ instance lumps the ability to create +-- -- measures from graphs of measures on top of that. +-- type MeasureT m a = ContT Double m a +-- type Measure a = Cont Double a +-- +-- runCont :: Cont r a -> (a -> r) -> r +-- runCont m k = runIdentity $ +-- runContT m (\x -> Identity (k x)) +-- +-- cont :: ((a -> r) -> r) -> Cont r a +-- cont f = ContT $ \c -> +-- Identity (f (\x -> runIdentity (c x))) +-- +-- -- | The 'integrate' function is just 'runCont' with its arguments reversed +-- -- in order to resemble the conventional mathematical notation, in which one +-- -- integrates a measurable function against a measure. +-- -- +-- -- >>> let mu = fromSamples [-1, 0, 1] +-- -- >>> expectation mu +-- -- 0.0 +-- -- >>> variance mu +-- -- 0.6666666666666666 +-- integrate :: (a -> Double) -> Measure a -> Double +-- integrate = flip runCont +-- +-- integrateT :: Applicative m => (a -> Double) -> MeasureT m a -> m Double +-- integrateT f m = runContT m (\x -> pure (f x)) +-- +-- -- FIXME (jtobin): +-- -- Write these in terms of integrate / integrateT. +-- instance Functor (ContT r m) where +-- fmap f m = ContT $ \c -> +-- runContT m (\x -> c (f x)) +-- +-- instance Applicative (ContT r m) where +-- pure x = ContT $ \f -> f x +-- f <*> v = ContT $ \c -> +-- runContT f $ \g -> +-- runContT v (c . g) +-- +-- instance Monad (ContT r m) where +-- return x = ContT ($ x) +-- m >>= k = ContT $ \c -> +-- runContT m $ \x -> +-- runContT (k x) c +-- +-- instance MonadTrans (ContT r) where +-- lift m = ContT (m >>=) +-- +-- instance Num a => Num (ContT Double m a) where +-- (+) = liftA2 (+) +-- (-) = liftA2 (-) +-- (*) = liftA2 (*) +-- abs = fmap id +-- signum = fmap signum +-- fromInteger = pure . fromInteger +-- +-- -- | Create a 'Measure' from a probability mass function and its support, +-- -- provided as a foldable container. +-- -- +-- -- The requirement to supply the entire support is restrictive but necessary; +-- -- for approximations, consider using 'fromSamples' or +-- -- 'fromSamplingFunction'. +-- -- +-- -- >>> let mu = fromMassFunction (binomialPmf 10 0.2) [0..10] +-- -- >>> integrate fromIntegral mu +-- -- 2.0 +-- fromMassFunction +-- :: (Functor f, Foldable f) +-- => (a -> Double) +-- -> f a +-- -> Measure a +-- fromMassFunction f support = cont $ \g -> +-- Foldable.sum $ (g /* f) <$> support +-- +-- fromMassFunctionT :: (Applicative m, Traversable t) +-- => (a -> Double) +-- -> t a +-- -> MeasureT m a +-- fromMassFunctionT f support = ContT $ \g -> +-- fmap Foldable.sum . traverse (g //* (pure . f)) $ support +-- +-- -- | Create a 'Measure' from a probability density function. +-- -- +-- -- Note that queries on measures constructed with @fromDensityFunction@ are +-- -- subject to numerical error due to the underlying dependency on quadrature! +-- -- +-- -- >>> let f x = 1 / (sqrt (2 * pi)) * exp (- (x ^ 2) / 2) +-- -- >>> let mu = fromDensityFunction f +-- -- >>> expectation mu +-- -- 0.0 +-- -- >>> variance mu +-- -- 1.0000000000000002 +-- fromDensityFunction :: (Double -> Double) -> Measure Double +-- fromDensityFunction d = cont $ \f -> quadratureTanhSinh $ f /* d where +-- quadratureTanhSinh = result . last . everywhere trap +-- +-- -- | Create a measure from a collection of observations. +-- -- +-- -- Useful for creating general purpose empirical measures. +-- -- +-- -- >>> let mu = fromSamples [(1, 2), (3, 4)] +-- -- >>> integrate (uncurry (+)) mu +-- -- 5.0 +-- fromSamples :: Foldable f => f a -> Measure a +-- fromSamples = cont . flip weightedAverage +-- +-- fromSamplesT +-- :: (Applicative m, Traversable f) +-- => f a +-- -> MeasureT m a +-- fromSamplesT = ContT . flip weightedAverageM +-- +-- -- | Create a measure from a sampling function. Runs the sampling function +-- -- the provided number of times and runs 'fromSamples' on the result. +-- fromSamplingFunction +-- :: Monad m +-- => (t -> m b) +-- -> Int +-- -> t +-- -> MeasureT m b +-- fromSamplingFunction f n g = (lift $ replicateM n (f g)) >>= fromSamplesT +-- +-- -- | A simple alias for @fmap@. +-- push :: (a -> b) -> Measure a -> Measure b +-- push = fmap +-- +-- pushT :: (a -> b) -> MeasureT m a -> MeasureT m b +-- pushT = fmap +-- +-- -- | The expectation of a measure is typically understood to be its expected +-- -- value, which is found by integrating it against the identity function. +-- expectation :: Measure Double -> Double +-- expectation = integrate id +-- +-- expectationT :: Applicative m => MeasureT m Double -> m Double +-- expectationT = integrateT id +-- +-- -- | The variance of a measure, as per the usual formula +-- -- @var X = E^2 X - EX^2@. +-- variance :: Measure Double -> Double +-- variance mu = integrate (^ 2) mu - expectation mu ^ 2 +-- +-- varianceT :: Applicative m => MeasureT m Double -> m Double +-- varianceT mu = liftA2 (-) (integrateT (^ 2) mu) ((^ 2) <$> expectationT mu) +-- +-- -- | The @nth@ raw moment of a 'Measure'. +-- rawMoment :: Int -> Measure Double -> Double +-- rawMoment n = integrate (^ n) +-- +-- rawMomentT :: Monad m => Int -> MeasureT m Double -> m Double +-- rawMomentT n = integrateT (^ n) +-- +-- -- | All raw moments of a 'Measure'. +-- rawMoments :: Measure Double -> [Double] +-- rawMoments mu = (`rawMoment` mu) <$> [1..] +-- +-- rawMomentsT :: Monad m => MeasureT m Double -> Int -> m [Double] +-- rawMomentsT mu n = traverse (`rawMomentT` mu) $ take n [1..] +-- +-- -- | The @nth@ central moment of a 'Measure'. +-- centralMoment :: Int -> Measure Double -> Double +-- centralMoment n mu = integrate (\x -> (x - rm) ^ n) $ mu +-- where rm = rawMoment 1 mu +-- +-- centralMomentT :: Monad m => Int -> MeasureT m Double -> m Double +-- centralMomentT n mu = integrateT (^ n) $ do +-- rm <- lift $ rawMomentT 1 mu +-- (subtract rm) <$> mu +-- +-- -- | All central moments of a 'Measure'. +-- centralMoments :: Measure Double -> [Double] +-- centralMoments mu = (`centralMoment` mu) <$> [1..] +-- +-- centralMomentsT :: Monad m => MeasureT m Double -> Int -> m [Double] +-- centralMomentsT mu n = traverse (`centralMomentT` mu) $ take n [1..] +-- +-- -- | The moment generating function corresponding to a 'Measure'. +-- -- +-- -- >>> let mu = fromSamples [1..10] +-- -- >>> let mgfMu = momentGeneratingFunction mu +-- -- >>> fmap mgfMu [0, 0.5, 1] +-- -- [1.0,37.4649671547254,3484.377384533132] +-- momentGeneratingFunction :: Measure Double -> Double -> Double +-- momentGeneratingFunction mu t = integrate (exp . (* t)) mu +-- +-- -- | The cumulant generating function corresponding to a 'Measure'. +-- -- +-- -- >>> let mu = fromSamples [1..10] +-- -- >>> let cgfMu = cumulantGeneratingFunction mu +-- -- >>> fmap cgfMu [0, 0.5, 1] +-- -- [0.0,3.6234062871236543,8.156044651432666] +-- cumulantGeneratingFunction :: Measure Double -> Double -> Double +-- cumulantGeneratingFunction mu = log . momentGeneratingFunction mu +-- +-- -- | Calculates the volume of a 'Measure' over its entire space. Trivially 1 +-- -- for any probability measure. +-- -- +-- -- >>> let mu = fromSamples [1..10] +-- -- >>> volume mu +-- -- 1.0 +-- volume :: Measure a -> Double +-- volume = integrate $ const 1 +-- +-- volumeT :: Applicative m => MeasureT m a -> m Double +-- volumeT = integrateT $ const 1 +-- +-- -- | The cumulative distribution function corresponding to a 'Measure' +-- -- +-- -- >>> let mu = fromSamples [1..10] +-- -- >>> let cdfMu = cdf mu +-- -- >>> fmap cdfMu [0..10] +-- -- [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0] +-- cdf :: Measure Double -> Double -> Double +-- cdf mu x = expectation $ negativeInfinity `to` x <$> mu +-- +-- cdfT :: Applicative m => MeasureT m Double -> Double -> m Double +-- cdfT mu x = expectationT $ negativeInfinity `to` x <$> mu +-- +-- -- | A helpful utility for calculating the volume of a region in a measure +-- -- space. +-- -- +-- -- >>> let mu = fromSamples [1..10] +-- -- >>> integrate (2 `to` 8) mu +-- -- 0.7 +-- to :: (Num a, Ord a) => a -> a -> a -> a +-- to a b x +-- | x >= a && x <= b = 1 +-- | otherwise = 0 +-- +-- -- | An analogue of 'to' for measures defined over non-ordered domains. +-- -- +-- -- >>> data Group = A | B | C deriving Eq +-- -- >>> let mu = fromSamples [A, A, A, B, A, B, C] +-- -- >>> integrate (containing [B]) mu +-- -- 0.2857142857142857 +-- -- >>> integrate (containing [A,C]) mu +-- -- 0.7142857142857143 +-- -- >>> integrate (containing [A,B,C]) mu +-- -- 1.0 +-- containing :: (Num a, Eq b) => [b] -> b -> a +-- containing xs x +-- | x `elem` xs = 1 +-- | otherwise = 0 +-- diff --git a/src/Measurable/Util.hs b/src/Measurable/Util.hs @@ -1,36 +0,0 @@ - -module Measurable.Util where - -import Control.Applicative -import Control.Foldl -import qualified Control.Foldl as Foldl -import Data.Foldable (Foldable) -import Data.Traversable - -negativeInfinity :: Fractional a => a -negativeInfinity = negate $ 1 / 0 - -weightedAverage :: (Foldable f, Fractional r) => (a -> r) -> f a -> r -weightedAverage f = Foldl.fold (weightedAverageFold f) - -weightedAverageM - :: (Traversable t, Applicative f, Fractional r) - => (a -> f r) - -> t a - -> f r -weightedAverageM f = fmap (Foldl.fold averageFold) . traverse f - -weightedAverageFold :: Fractional r => (a -> r) -> Fold a r -weightedAverageFold f = Foldl.premap f averageFold - -averageFold :: Fractional a => Fold a a -averageFold = (/) <$> Foldl.sum <*> Foldl.genericLength - --- | Lifted multiplication. -(/*) :: (Num c, Applicative f) => f c -> f c -> f c -(/*) = liftA2 (*) - --- | Doubly-lifted multiplication. -(//*) :: (Num c, Applicative f, Applicative g) => f (g c) -> f (g c) -> f (g c) -(//*) = liftA2 (/*) - diff --git a/stack.yaml b/stack.yaml @@ -2,4 +2,4 @@ flags: {} packages: - '.' extra-deps: [] -resolver: lts-2.21 +resolver: lts-8.15