Skip to content

Instantly share code, notes, and snippets.

@whilo
Created June 6, 2018 12:23
Show Gist options
  • Save whilo/03ebf7328b2abbf9090ca9294398970f to your computer and use it in GitHub Desktop.
Save whilo/03ebf7328b2abbf9090ca9294398970f to your computer and use it in GitHub Desktop.
Klipse Anglican experiment.
(ns anglican.runtime$macros
"Runtime library"
(:require [clojure.string :as str]
[clojure.core.matrix :as m]
[clojure.core.matrix.linear :as ml]
[anglican.runtime :refer [distribution]]
#?(:cljs [goog.string.format]))
)
(defn- cljs-env?
"Take the &env from a macro, and tell whether we are expanding into cljs."
[env]
(boolean (:ns env)))
(defmacro if-cljs
"Return then if we are generating cljs code and else for Clojure code.
https://groups.google.com/d/msg/clojurescript/iBY5HaQda4A/w1lAQi9_AwsJ"
[then else]
(if (cljs-env? &env) then else))
(defn format
"Similar to Java String's format function for cljs."
[s & args]
(goog.string.format s (into-array args)))
(defprotocol distribution
"random distribution"
(sample* [this]
"draws a sample from the distribution")
(observe* [this value]
"return the probability [density] of the value"))
(defmacro defdist
"defines distribution"
[name & args]
(let [[docstring parameters & args]
(if (string? (first args))
args
`(~(format "%s distribution" name) ~@args))
[bindings & methods]
(if (vector? (first args))
args
`[[] ~@args])
record-name (symbol (format "%s-distribution" name))
variables (take-nth 2 bindings)]
`(do
(declare ~name)
(defrecord ~record-name [~@parameters ~@variables]
;; TODO
; Object
; (toString [~'this]
; (str (list '~(qualify name) ~@parameters)))
anglican.runtime$macros$distribution
~@methods)
(defn ~name ~docstring ~parameters
(let ~bindings
(~(symbol (format "->%s" record-name))
~@parameters ~@variables)))
(if-cljs
(extend-protocol cljs.core/IPrintWithWriter
~record-name
(cljs.core/-pr-writer [o# writer# opts#]
(cljs.core/-write writer# (str o#))))
;; TODO macro hygene?
(defmethod print-method ~record-name
[~'o ~'m]
(print-simple (str ~'o) ~'m))))))
(do
;; bootstrap the uniform distribution
;; was imported from Apache Commons
(defrecord uniform-continuous-distribution [min max]
anglican.runtime$macros/distribution
(sample* [this]
(let [len (- max min)]
(+ min (* len (rand)))))
(observe* [this value]
(if (<= min value max)
(log (/ 1 (- max min)))
js/Number.NEGATIVE_INFINITY)))
(defn uniform-continuous
"Uniform continuous distribution"
[min max]
(->uniform-continuous-distribution min max))
(extend-protocol cljs.core/IPrintWithWriter
uniform-continuous-distribution
(cljs.core/-pr-writer
[o writer opts]
(cljs.core/-write writer (str (type o))))))
(sample* (uniform-continuous 0 3))
(anglican.runtime$macros/defdist bernoulli
"Bernoulli distribution"
[p] [dist (uniform-continuous 0.0 1.0)]
(sample* [this] (if (< (sample* dist) p) 1 0))
(observe* [this value]
(log (case value
1 p
0 (- 1. p)
0.))))
(sample* (bernoulli 0.8))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment