commit 5ac9d3d8812d3d8de878ab78d10d94a667045ca4
parent f1d3241a83c33fa50056af7eb628696a2f8d46d9
Author: Jared Tobin <jared@jtobin.ca>
Date: Thu, 2 Apr 2015 18:48:58 +1000
Merge pull request #1 from jtobin/jt-cleanup
Misc cleanup.
Diffstat:
7 files changed, 1277 insertions(+), 216 deletions(-)
diff --git a/README.md b/README.md
@@ -1,5 +1,25 @@
measurable
----------
-An experimental embedded DSL for creating, manipulating, and using measures.
+*measurable* is a simple shallowly-embedded DSL for dealing with measures.
+
+It uses 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 measure convolution and friends
+provided by a simple `Num` instance enabled by an `Applicative` instance.
+Create measures from graphs of other measures using the `Monad` instance and
+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.
+
+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!
+
diff --git a/cabal.config b/cabal.config
@@ -0,0 +1,866 @@
+-- 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
@@ -0,0 +1,98 @@
+{-# 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
@@ -2,7 +2,7 @@ name: measurable
version: 1.0.0.0
license: BSD3
license-file: LICENSE
-copyright: (c) Jared Tobin 2013 - 2014.
+copyright: (c) Jared Tobin 2013 - 2015.
author: Jared Tobin
maintainer: jared@jtobin.ca
stability: Experimental
@@ -10,28 +10,70 @@ category: Math
homepage: http://github.com/jtobin/measurable
bug-reports: http://github.com/jtobin/measurable/issues
build-type: Simple
-cabal-version: >=1.10
-synopsis: Basic measure wrangling.
+cabal-version: >=1.18
+synopsis: A shallowly-embedded DSL for basic measure wrangling.
description:
- Various types, instances, and combinators that make it easy to play with
- measures.
+ @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.
+
+ 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!
source-repository head
type: git
location: git://github.com/jtobin/measurable.git
library
- exposed-modules: Measurable.Core
hs-source-dirs: src
default-language: Haskell2010
+ exposed-modules:
+ Measurable.Core
+ , Measurable.Measures
+ , Measurable.Util
other-extensions:
BangPatterns
FlexibleInstances
build-depends:
- base >= 4.6
- , integration >= 0.2
- , mtl >= 2.1.2
- , transformers >= 0.3
+ base >= 4.7 && < 4.8
+ , foldl
+ , integration
+ , mtl
+ , 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/Core.hs b/src/Measurable/Core.hs
@@ -4,315 +4,265 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleInstances #-}
--- |
---
--- The /measurable/ library provides basic facilities for defining,
--- manipulating, and - where possible - evaluating measures.
---
--- Measure theory is the foundation of formal probability. And while measures
--- are useful for proofs and theoretical work, they're not a particularly
--- efficient way to get anything done in the real world. That said, a solid
--- mental model of probability in terms of abstract volumes and ratios is a
--- valuable (and difficult) thing to achieve, and /measurable/ can help to
--- achieve it.
---
--- Measures are represented in their dual form as integrals. That is, a
--- measure is represented as an /integration procedure/ that, when provided
--- with a measurable function, evaluates an integral against a measure.
--- Everything corresponds exactly to the more low-level definition of measures
--- being set functions defined on sigma-algebras and all that, but in a fashion
--- that is much more amenable to representation on a computer. Since they are
--- /procedures/ that need a function to complete them, measures are naturally
--- represented by continuations.
---
--- As continuations, measures are instances of the @Functor@ class; fmapping a
--- function over a measure transforms that measure's support while leaving its
--- density structure unchanged. @fmap@ corresponds to the thing that's
--- variably called a pushforward, distribution, or image measure; it adapts a
--- measure from one measureable space to another.
---
--- <image here>
---
--- Measures are also instances of @Monad@. 'return' wraps a value up as a
--- Dirac measure, and 'bind' is an integrating operator that marginalizes
--- existing measures by blending them into others.
---
--- Measures have to be created from something; /measurable/ offers four
--- functions to build them:
---
--- * 'fromPoints', for a discrete collection of points
---
--- * 'fromDensityCounting', for a density with respect to counting measure
--- (i.e. a mass function)
---
--- * 'fromDensityLebesgue', for a density with espect to Lebesgue measure
---
--- * 'fromSamplingFunction', for a sampling function that uniquely
--- characterizes a measure.
---
--- Addtionally, there are two important ways to query measures:
---
--- * 'integrate' integrates a measurable function against a measure
---
--- * 'expectation' integrates the identity function against a measure
---
--- * 'cdf' returns a cumulative distribution function for a measure space
---
--- Other queries (volume, variance, higher moments) are also available, but are
--- moreso included as curiosities.
---
--- Measures are not only implemented as stand-alone probabilistic objects, but
--- as a monad transformers as well. This allows measure semantics to be
--- layered on top of any existing monad.
-
module Measurable.Core where
-import Control.Arrow
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 hiding (mapM)
+import Data.Traversable
+import Measurable.Util
import Numeric.Integration.TanhSinh
--- | We don't want to allow nonlinear things like callCC, so we roll our own
--- Continuation type that doesn't allow that sort of thing.
+-- | 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))
+runCont m k = runIdentity $ runContT m (Identity . k)
cont :: ((a -> r) -> r) -> Cont r a
-cont f = ContT (\c -> Identity (f (runIdentity . c)))
+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
instance Functor (ContT r m) where
fmap f m = ContT $ \c -> runContT m (c . f)
instance Applicative (ContT r m) where
- pure x = ContT ($ x)
- f <*> v = ContT $ \c -> runContT f $ \g -> runContT v (c . g)
+ pure x = ContT ($ 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)
+ return x = ContT ($ x)
+ m >>= k = ContT $ \c ->
+ runContT m $ \x ->
+ runContT (k x) c
instance MonadTrans (ContT r) where
lift m = ContT (m >>=)
--- | A measure is represented as a continuation with output restricted to the
--- reals. Measures are *integration programs* that, when supplied with a
--- measurable function, integrate that function against some measure.
-type Measure a = Cont Double a
-type MeasureT m a = ContT Double m a
-
--- | A more domain-specific alias for runCont. This follows the traditional
--- mathematical form; integrate a function against a measure.
+-- | 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
+-- >>> expectation mu
+-- 1.0
integrate :: (a -> Double) -> Measure a -> Double
integrate = flip runCont
-integrateT :: Monad m => (a -> Double) -> MeasureT m a -> m Double
-integrateT f = (`runContT` (return . f))
+integrateT :: Applicative m => (a -> Double) -> MeasureT m a -> m Double
+integrateT f = (`runContT` (pure . f))
--- | Things like convolution are trivially expressed by lifted arithmetic
--- operators. Probability measures in particular - where things like
--- \infty - \infty are not an issue - form a ring.
---
--- Note that the complexity of integration over a sum, difference, or product
--- of 'n' measures in this situation, each encoding 'm' elements, is O(m^n)
--- in this implementation. Operations on independent measures can
--- theoretically be implemented with drastically lower complexity, possibly
--- by using some cleverness with Arrows.
-instance (Monad m, Num a) => Num (ContT Double m a) where
+instance (Applicative m, Num a) => Num (ContT Double m a) where
(+) = liftA2 (+)
(-) = liftA2 (-)
(*) = liftA2 (*)
- abs = id
- signum = const 1
- fromInteger = return . fromInteger
+ abs = fmap id
+ signum = fmap signum
+ fromInteger = pure . fromInteger
--- | Creates a measure from a density w/respect to counting measure.
-fromDensityCounting
- :: (Functor f, Foldable f)
- => (a -> Double)
- -> f a
- -> Measure a
-fromDensityCounting f support = cont $ \g ->
- Foldable.sum $ (g /* f) <$> support
+-- | 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 :: Foldable f => (a -> Double) -> f a -> Measure a
+fromMassFunction f support = cont $ \g -> weightedAverage (g /* f) support
-fromDensityCountingT
- :: (Applicative m, Monad m, Traversable t)
+fromMassFunctionT :: (Applicative m, Traversable t)
=> (a -> Double)
-> t a
-> MeasureT m a
-fromDensityCountingT p support = ContT $ \f ->
- fmap Foldable.sum . traverse (f //* pLifted) $ support
- where
- pLifted = return . p
+fromMassFunctionT f support = ContT $ \g ->
+ fmap Foldable.sum . traverse (g //* (pure . f)) $ support
--- | Create a measure from a density w/respect to Lebesgue measure.
+-- | Create a 'Measure' from a probability density function.
--
--- NOTE The quality of this implementation depends entirely on the underlying
--- quadrature routine. This is included moreso for interest's sake and
--- isn't particularly accurate.
-fromDensityLebesgue :: (Double -> Double) -> Measure Double
-fromDensityLebesgue d = cont $ \f -> quadratureTanhSinh $ f /* d where
+-- 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 fixed collection of points.
-fromPoints :: (Functor f, Foldable f) => f a -> Measure a
-fromPoints = cont . flip weightedAverage
-
-fromPointsT
- :: (Applicative m, Monad m, Traversable f)
+-- | 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
-fromPointsT = ContT . flip weightedAverageM
+fromSamplesT = ContT . flip weightedAverageM
--- | Create a measure from a sampling function. Needs access to a random
--- number supply monad, so only a monad transformer version is available.
+-- | 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)) >>= fromPointsT
+fromSamplingFunction f n g = (lift $ replicateM n (f g)) >>= fromSamplesT
--- | Synonyms for fmap.
+-- | 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
--- | Expectation is integration against the identity function.
+-- | 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
+expectation = integrate id
-expectationT :: Monad m => MeasureT m Double -> m Double
+expectationT :: Applicative m => MeasureT m Double -> m Double
expectationT = integrateT id
--- | Variance is obtained by the usual identity.
+-- | 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 :: Monad m => MeasureT m Double -> m Double
-varianceT mu = liftM2 (-) (integrateT (^ 2) mu) (liftM (^ 2) (expectationT mu))
-
--- | Convenience function for returning the expectation & variance as a pair.
-meanVariance :: Measure Double -> (Double, Double)
-meanVariance = expectation &&& variance
+varianceT :: Applicative m => MeasureT m Double -> m Double
+varianceT mu = liftA2 (-) (integrateT (^ 2) mu) ((^ 2) <$> expectationT mu)
-meanVarianceT
- :: (Applicative m, Monad m)
- => MeasureT m Double
- -> m (Double, Double)
-meanVarianceT mu = (,) <$> expectationT mu <*> varianceT mu
-
--- | The nth raw moment of a measure.
+-- | 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 :: (Applicative m, Monad m) => Int -> MeasureT m Double -> m Double
rawMomentT n = integrateT (^ n)
--- | All raw moments of a measure.
+-- | All raw moments of a 'Measure'.
rawMoments :: Measure Double -> [Double]
-rawMoments mu = map (`rawMoment` mu) [1..]
+rawMoments mu = (`rawMoment` mu) <$> [1..]
-rawMomentsT :: Monad m => MeasureT m Double -> Int -> m [Double]
-rawMomentsT mu n = mapM (`rawMomentT` mu) (take n [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.
+-- | 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 :: (Applicative m, Monad m) => Int -> MeasureT m Double -> m Double
centralMomentT n mu = integrateT (^ n) $ do
rm <- lift $ rawMomentT 1 mu
- (\x -> x - rm) <$> mu
+ (subtract rm) <$> mu
--- | All central moments.
+-- | All central moments of a 'Measure'.
centralMoments :: Measure Double -> [Double]
-centralMoments mu = map (`centralMoment` mu) [1..]
+centralMoments mu = (`centralMoment` mu) <$> [1..]
-centralMomentsT :: Monad m => MeasureT m Double -> Int -> m [Double]
-centralMomentsT mu n = mapM (`centralMomentT` mu) (take n [1..])
+centralMomentsT :: (Applicative m, Monad m) => MeasureT m Double -> Int -> m [Double]
+centralMomentsT mu n = traverse (`centralMomentT` mu) $ take n [1..]
--- | The moment generating function for a measure.
+-- | 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) . id) mu
+momentGeneratingFunction mu t = integrate (exp . (* t)) mu
--- | The cumulant generating function for a measure.
+-- | 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
+cumulantGeneratingFunction mu = log . momentGeneratingFunction mu
--- | Apply a measure to the underlying space. In particular, this is trivially
--- 1 for any probability measure.
+-- | 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)
+volume = integrate $ const 1
-volumeT :: Monad m => MeasureT m a -> m Double
-volumeT = integrateT (const 1)
+volumeT :: Applicative m => MeasureT m a -> m Double
+volumeT = integrateT $ const 1
--- | Cumulative distribution function.
+-- | 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 :: Monad m => MeasureT m Double -> Double -> m Double
+cdfT :: Applicative m => MeasureT m Double -> Double -> m Double
cdfT mu x = expectationT $ negativeInfinity `to` x <$> mu
--- | Indicator function for the interval a <= x <= b. Useful for integrating
--- from a to b.
+-- | 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
--- | Integrate over a discrete, possibly unordered set.
+-- | 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
+containing xs x
| x `elem` xs = 1
| otherwise = 0
--- | End of the line.
-negativeInfinity :: Fractional a => a
-negativeInfinity = negate (1 / 0)
-
--- | Simple average.
-average :: (Fractional a, Foldable f) => f a -> a
-average xs = fst $ Foldable.foldl'
- (\(!m, !n) x -> (m + (x - m) / fromIntegral (n + 1), n + 1)) (0, 0) xs
-{-# INLINE average #-}
-
--- | Weighted average.
-weightedAverage
- :: (Functor f, Foldable f, Fractional c)
- => (a -> c)
- -> f a
- -> c
-weightedAverage f = average . fmap f
-{-# INLINE weightedAverage #-}
-
--- | Monadic weighted average.
-weightedAverageM
- :: (Fractional c, Traversable f, Monad m, Applicative m)
- => (a -> m c)
- -> f a
- -> m c
-weightedAverageM f = liftM average . traverse f
-{-# INLINE weightedAverageM #-}
-
--- | 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/src/Measurable/Measures.hs b/src/Measurable/Measures.hs
@@ -0,0 +1,49 @@
+
+module Measurable.Measures where
+
+import Measurable.Core
+import Statistics.Distribution
+import qualified Statistics.Distribution.Beta as Statistics
+import qualified Statistics.Distribution.Binomial as Statistics
+import qualified Statistics.Distribution.ChiSquared as Statistics
+import qualified Statistics.Distribution.Gamma as Statistics
+import qualified Statistics.Distribution.Exponential as Statistics
+import qualified Statistics.Distribution.Normal as Statistics
+
+standard :: Measure Double
+standard = fromDensityFunction pdf where
+ pdf = density Statistics.standard
+
+normal :: Double -> Double -> Measure Double
+normal m s = fromDensityFunction pdf where
+ pdf = density $ Statistics.normalDistr m s
+
+logNormal :: Double -> Double -> Measure Double
+logNormal m s = fmap exp (normal m s)
+
+exponential :: Double -> Measure Double
+exponential r = fromDensityFunction pdf where
+ pdf = density $ Statistics.exponential r
+
+gamma :: Double -> Double -> Measure Double
+gamma a b = fromDensityFunction pdf where
+ pdf = density $ Statistics.gammaDistr a b
+
+inverseGamma :: Double -> Double -> Measure Double
+inverseGamma a b = fmap recip (gamma a b)
+
+chiSquare :: Int -> Measure Double
+chiSquare k = fromDensityFunction pdf where
+ pdf = density $ Statistics.chiSquared k
+
+beta :: Double -> Double -> Measure Double
+beta a b = fromDensityFunction pdf where
+ pdf = density $ Statistics.betaDistr a b
+
+binomial :: Int -> Double -> Measure Int
+binomial n p = fromMassFunction pmf [0..n] where
+ pmf = probability $ Statistics.binomial n p
+
+bernoulli :: Double -> Measure Int
+bernoulli = binomial 1
+
diff --git a/src/Measurable/Util.hs b/src/Measurable/Util.hs
@@ -0,0 +1,36 @@
+
+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 (/*)
+