Merge pull request #2 from mcgirjau/master

Add normal distribution, calculus, and basic math
This commit is contained in:
Lee Spector 2020-06-17 22:01:24 -04:00 committed by GitHub
commit dd7698b86d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 191 additions and 0 deletions

33
src/tools/calculus.cljc Normal file
View File

@ -0,0 +1,33 @@
(ns tools.calculus)
(defonce ^:const dx 0.0001)
(defn deriv
"Returns the derivative of f evaluated at c. If called with only one argument,
it returns the derivative function."
([f c]
((deriv f) c))
([f]
(fn [x]
(/ (- (f (+ x dx)) (f x)) dx))))
(defn integrate
"Returns the definite integral of f over [a, b] using Simpson's method.
If called with only one argument (the function), returns the indefinite
integral, which takes as input a value x and (optionally) a constant c."
([f]
(fn this
([x] (this x 0))
([x c] (+ (integrate f 0 x) c))))
([f a b]
(let [n (/ 1 dx)
h (/ (- b a) n)]
(loop [i 1
sum1 (f (+ a (/ h 2)))
sum2 0]
(if (< i n)
(recur (inc i)
(+ sum1 (f (+ a (* h i) (/ h 2))))
(+ sum2 (f (+ a (* h i)))))
(* (/ h 6) (+ (f a) (f b) (* 4 sum1) (* 2 sum2))))))))

View File

@ -0,0 +1,59 @@
(ns tools.distributions
(:require [tools.math :as math])
(:require [tools.calculus :as calculus]))
;; -----------------------------------------------------------------------------
;; NORMAL
;; -----------------------------------------------------------------------------
(defn- box-muller
"Given two uniformly distributed random variables (from 0 to 1), returns a
Standard Normal variable computed using the Box-Muller Transform."
[u1 u2]
(* (math/sqrt (* -2 (math/log u1)))
(math/cos (* 2 math/PI u2))))
(defn- normal-pdf
"Given a mean and standard deviation, returns the corresponding Normal
Probability Distribution Function."
[mu sigma]
(fn [x]
(* (/ 1 (* sigma (math/sqrt (* 2 math/PI))))
(math/exp (- (/ (math/pow (/ (- x mu) sigma) 2) 2))))))
(defn rand-norm
"Generates n Normally-distributed random variables with given mean and
standard deviation. If no parameters are provided, defaults to a
single random observation from a Standard Normal distribution.
Accepts an argument map with optional keys :n, :mu, and :sigma."
[{:keys [n mu sigma]
:or {n 1, mu 0, sigma 1}}]
(repeatedly n #(box-muller (rand 1) (rand 1))))
(defn pdf-norm
"Returns the value of the Normal Probability Distribution Function at a
particular value x. If no distributional parameters are provided, defaults to
the Standard Normal PDF.
Accepts an argument map with keys :x, and optionally :mu and :sigma."
[{:keys [x mu sigma]
:or {mu 0, sigma 1}}]
((normal-pdf mu sigma) x))
(defn cdf-norm
"Parameters: {:keys [x mu sigma]}
Returns the value of the Normal Cumulative Distribution Function at a
particular value x. If no distributional parameters are provided, defaults to
the Standard Normal CDF.
Accepts an argument map with keys :x, and optionally :mu and :sigma."
[{:keys [x mu sigma]
:or {mu 0, sigma 1}}]
(calculus/integrate (normal-pdf mu sigma) (- mu (* 6 sigma)) x))
(defn quant-norm
"For a given probability p, returns the corresponding value of the quantile
function (i.e. the inverse Cumulative Distribution Function). If no
distributional parameters are provided, defaults to Standard Normal quantiles.
Accepts an argument map with keys :p, and optionally :mu and :sigma."
[{:keys [p mu sigma]
:or {mu 0, sigma 1}}]
()) ; unfinished...

99
src/tools/math.cljc Normal file
View File

@ -0,0 +1,99 @@
(ns tools.math)
(defonce PI #?(:clj Math/PI
:cljs js/Math.PI))
(defonce E #?(:clj Math/E
:cljs js/Math.PI))
(defn abs
"Returns the absolute value of a number."
[x]
(if (neg? x) (- x) x))
(defn approx= [x y epsilon]
"Returns true if the absolute difference between x and y is less than or
equal to some specified error level, epsilon."
(<= (abs (- y x)) epsilon))
(defn ceil
"Returns the smallest integer greater than or equal to x."
[x]
#?(:clj (Math/ceil x)
:cljs (js/Math.ceil x)))
(defn cos
"Returns the cosine of an angle (specified in radians)."
[x]
#?(:clj (Math/cos x)
:cljs (js/Math.cos x)))
(defn exp
"Returns Euler's number (approx. 2.71) raised to the given power."
[x]
#?(:clj (Math/exp x)
:cljs (js/Math.exp x)))
(defn floor
"Returns the largest integer less than or equal to x."
[x]
#?(:clj (Math/floor x)
:cljs (js/Math.floor x)))
(defn log
"Returns the logarithm of x with the given base. If called with only one
argument, returns the natural logarithm (base e) of the given value."
([x base]
(/ (log x) (log base)))
([x]
#?(:clj (Math/log x)
:cljs (js/Math.log x))))
(defn pow
"Returns the value obtained by raising the first argument to the power of
the second argument."
[x n]
#?(:clj (Math/pow x n)
:cljs (js/Math.pow x n)))
(defn root
"Returns the root of x with base n."
[x n]
(pow x (/ 1 n)))
(defn round
"Returns the value of x rounded to the nearest integer."
[x]
#?(:clj (Math/round x)
:cljs (js/Math.round x)))
(defn sign
"Returns the 1 if the argument is positive, -1 if the argument is negative,
and 0 if the argument is zero."
[x]
(cond (< x 0) -1
(> x 0) 1
:else 0))
(defn sin
"Returns the sine of an angle (specified in radians)."
[x]
#?(:clj (Math/sin x)
:cljs (js/Math.sin x)))
(defn sqrt
"Returns the square root of the given value."
[x]
#?(:clj (Math/sqrt x)
:cljs (js/Math.sqrt x)))
(defn square
"Returns the square of the given value."
[x]
(* x x))
(defn tan
"Returns the tangent of an angle (specified in radians)."
[x]
#?(:clj (Math/tan x)
:cljs (js/Math.tan x)))