# HG changeset patch # User Steve Losh # Date 1333834383 14400 # Node ID 3c3a3292e0db6cc8b085377bd5816fd8ae269d6b Initial commit. diff -r 000000000000 -r 3c3a3292e0db .gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.gitignore Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,10 @@ +/target +/lib +/classes +/checkouts +pom.xml +*.jar +*.class +.lein-deps-sum +.lein-failures +.lein-plugins diff -r 000000000000 -r 3c3a3292e0db .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,12 @@ +syntax:glob +target/ +lib/ +classes/ +checkouts/ +pom.xml +docs/build/ +*.jar +*.class +.lein-deps-sum +.lein-failures +.lein-plugins diff -r 000000000000 -r 3c3a3292e0db README.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.markdown Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,44 @@ +roul +==== + +Roul (from "roulette") is a tiny Clojure library for working with random numbers +more easily. + +For example: + + (require '[roul.random :as rr]) + + ; Get a random integer between 0 and 10 + (rand-int 10) ; Default Clojure + (rr/rand-int 10) ; Roul + + ; Get a random integer between 10 and 20 + (+ 10 (rand-int 10)) ; Default Clojure + (rr/rand-int 10 20) ; Roul + + ; Get a random element from a weighted collection + + ; Returns coffee roughly 80% of the time, tea 15%, and soda 5%. + (rr/rand-nth-weighted {:coffee 0.80 :tea 0.15 :soda 0.05}) + + ; Returns cats roughly twice as often as boots. + (rr/rand-nth-weighted [[:boots 14] [:cats 28]]) + +Installation +------------ + +You need Leiningen 2 to use this. Sorry. + + [roul "0.1.0"] + +Usage +----- + +Read the [documentation](http://sjl.bitbucket.org/roul/). + +License +------- + +Copyright © 2012 Steve Losh and Contributors + +MIT/X11 Licensed diff -r 000000000000 -r 3c3a3292e0db docs/footer.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/footer.markdown Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,18 @@ +Created by [Steve Losh](http://stevelosh.com). +Docs made with [d](http://sjl.bitbucket.org/d/). + +
Rochester Made + + diff -r 000000000000 -r 3c3a3292e0db docs/index.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/index.markdown Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,11 @@ +Roul (from "roulette") is a tiny Clojure library that makes working with random +numbers more convenient. + +It's still in the early stages of development, but if you can think of something +useful that should be in it feel free to open a feature request on the issue +tracker! + +* License: MIT/X11 +* Mercurial: +* Git: +* Issues: diff -r 000000000000 -r 3c3a3292e0db docs/installation.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/installation.markdown Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,10 @@ +Installation +============ + +Roul requires Leiningen 2. Sorry. + +Add the following to your `project.clj`: + + [roul "0.1.0"] + +Run `lein deps` and you're all set. diff -r 000000000000 -r 3c3a3292e0db docs/publish.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/publish.sh Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +rm -rf ./build +~/lib/virtualenvs/d/bin/d +hg -R ~/src/sjl.bitbucket.org pull -u +rsync --delete -a ./build/ ~/src/sjl.bitbucket.org/roul +hg -R ~/src/sjl.bitbucket.org commit -Am 'roul: Update site.' +hg -R ~/src/sjl.bitbucket.org push + diff -r 000000000000 -r 3c3a3292e0db docs/title --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/title Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,1 @@ +Roul diff -r 000000000000 -r 3c3a3292e0db docs/usage.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/usage.markdown Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,79 @@ +Usage +===== + +Roul currently contains a few functions in one namespace. It'll expand in the +future, but for now that's all it is. + +[TOC] + +roul.random +----------- + +The `roul.random` namespace contains wrappers around some of Clojure's built-in +random functions to make them more user friendly, as well as some uniqe +functions of its own. + +The recommended way is to `require` this namespace into your own instead of +overwriting Clojure's builtins: + + :::clojure + (ns foo.core + (:require [roul.random :as rr])) + + ; or + + (require '[roul.random :as rr]) + +### rand + + :::clojure + (rand) ; return a float in [0, 1) + (rand end) ; return a float in [0, end) + (rand start end) ; return a float in [start, end) + +A wrapper around the built-in `rand`. Returns a random floating point number +between `start` (inclusive) and `end` (exclusive). + +If not given, `start` defaults to `0` and `end` defaults to `1`. + +### rand-int + + :::clojure + (rand-int end) ; return an int in [0, end) + (rand-int start end) ; return an int in [start, end) + +A wrapper around the built-in `rand-int`. Returns a random integer between +`start` (inclusive) and `end` (exclusive). + +If not given, `start` defaults to `0`. + +### rand-nth + + :::clojure + (rand-nth coll) ; return a random element of coll + +A wrapper around the built-in `rand-nth`. Returns a random element of the given +collection. + +This is a transparent wrapper around the builtin, included only for +completeness. Unlike the other wrappers no new functionality has been added +(yet). + +### rand-nth-weighted + + :::clojure + (rand-nth-weighted coll) ; return a random element of coll + +Returns a random element of a weighted collection. + +A weighted collection can be any seq of `[choice, weight]` elements. The +weights can be arbitrary numbers -- they do not need to add up to anything +specific. + + :::clojure + ; Returns coffee roughly 80% of the time, tea 15%, and soda 5%. + (rr/rand-nth-weighted {:coffee 0.80, :tea 0.15, :soda 0.05}) + + ; Returns cats roughly twice as often as boots. + (rr/rand-nth-weighted [[:boots 14] + [:cats 28]]) diff -r 000000000000 -r 3c3a3292e0db project.clj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project.clj Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,8 @@ +(defproject roul "0.1.0" + :license {:name "MIT/X11"} + :dependencies [[org.clojure/clojure "1.3.0"]] + :plugins [[sjl/lein2-generative "0.1.4.2"]] + :generative-path "test/" + :url "http://sjl.bitbicket.org/roul/" + :min-lein-version "2.0.0" + :description "A library that wraps and extends Clojure's random number generators.") diff -r 000000000000 -r 3c3a3292e0db src/roul/random.clj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/roul/random.clj Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,45 @@ +(ns roul.random + (:refer-clojure :exclude [rand-int rand rand-nth])) + + +(defn rand + "Return a random float between start (inclusive) and end (exclusive). + + start defaults to 0 + end defaults to 1" + ([] (clojure.core/rand)) + ([end] (clojure.core/rand end)) + ([start end] (+ start (clojure.core/rand (- end start))))) + +(defn rand-int + "Return a random int between start (inclusive) and end (exclusive). + + start defaults to 0" + ([end] (clojure.core/rand-int end)) + ([start end] (+ start (clojure.core/rand-int (- end start))))) + +(defn rand-nth + "Return a random element of the collection. Delegates to the built-in + rand-nth for now." + [coll] + (clojure.core/rand-nth coll)) + +(defn rand-nth-weighted + "Return a random element from the weighted collection. + + A weighted collection can be any seq of [choice, weight] elements. The + weights can be arbitrary numbers -- they do not need to add up to anything + specific. + + Examples: + + (rand-nth-weighted [[:a 0.50] [:b 0.20] [:c 0.30]]) + (rand-nth-weighted {:a 10 :b 200})" + [coll] + (let [total (reduce + (map second coll))] + (loop [i (rand total) + [[choice weight] & remaining] (seq coll)] + (if (>= weight i) + choice + (recur (- i weight) remaining))))) + diff -r 000000000000 -r 3c3a3292e0db test/roul/random_test.clj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/roul/random_test.clj Sat Apr 07 17:33:03 2012 -0400 @@ -0,0 +1,50 @@ +(ns roul.random_test + (:use clojure.test) + (:require [clojure.test.generative.generators :as gen]) + (:use [clojure.test.generative :only [defspec]]) + (:require [roul.random :as rr])) + + +(defn abs [i] + (if (< i 0) + (- i) + i)) + + +(defn random-smallish-int [] + (gen/uniform -2000 2000)) + +(defspec abs-is-never-negative + abs + [^{:tag `random-smallish-int} n] + (assert (not (neg? %)))) + + +(defn all-within [actual expected tolerance] + (letfn [(is-bad [[i p]] + (<= (abs (- p (expected i))) + tolerance))] + (empty? (remove identity (map is-bad actual))))) + +(defn percentquencies [data] + (let [freqs (frequencies data) + total (reduce + (map second freqs))] + (into {} (map (juxt first #(-> % second (/ total) float)) + freqs)))) + + +(defn random-data [] (gen/vec gen/int)) +(defspec percentquencies-are-sane + percentquencies + [^{:tag `random-data} data] + (assert (= (set (keys %)) (set data)))) + + +(deftest test-rand-nth-weighted + (testing "Values should be selected approximately according to their weights." + (dotimes [_ 10] + (let [data (repeatedly 10000 #(rr/rand-nth-weighted {:a 0.5 :b 0.2 :c 0.3}))] + (is (all-within (percentquencies data) {:a 0.5 :b 0.2 :c 0.3} 0.05)))) + (dotimes [_ 10] + (let [data (repeatedly 10000 #(rr/rand-nth-weighted {:a 100 :b 900}))] + (is (all-within (percentquencies data) {:a 0.10 :b 0.9} 0.05))))))