{{ message }}

Instantly share code, notes, and snippets.

# ericnormand/00 quartile properties.md

Last active Jul 29, 2019

property-based tests of quartiles

Now that we have implementations of quartiles, how do we know it works? What properties would you want the quartiles values to obey?

Here are a few properties to implement:

1. The median (q2) should be between the smallest and largest numbers.
2. q0 <= q1 <= q2 <= q3 <= q4

These are invariants that we can guarantee. But invariants are just one way to create properties. We can also do a metamorphic test:

1. Generate a random list l1.
2. Calculate the quartiles l1q.
3. Add a number to the list l1 that is greater than the max, call it l2.
4. Calculate the quartiles l2q.

The values in l2q should be greater than or equal to the corresponding values in l1q.

Implement these three properties. That's the challenge this week.

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (tc/quick-check 100 (prop/for-all [nums (gen/not-empty (gen/vector gen/large-integer))] (let [qs (quartiles nums) {:keys [q2]} qs] (<= (apply min nums) q2 (apply max nums))))) (tc/quick-check 100 (prop/for-all [nums (gen/not-empty (gen/vector gen/large-integer))] (let [qs (quartiles nums) {:keys [q0 q1 q2 q3 q4]} qs] (<= q0 q1 q2 q3 q4)))) (tc/quick-check 100 (prop/for-all [num1s (gen/not-empty (gen/vector gen/large-integer)) diff gen/nat] (let [q1s (quartiles num1s) num2s (conj num1s (+ diff (apply max num1s))) q2s (quartiles num2s)] (every? (fn [k] (<= (get q1s k) (get q2s k))) (keys q1s)))))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 (ns scratchpad.pftv.336 (:require [clojure.test :refer [deftest is testing run-tests]] [scratchpad.pftv.335 :refer [median quartiles]] [clojure.test.check :as tc] [clojure.test.check.generators :as gen] [clojure.test.check.properties :as prop] [clojure.test.check.clojure-test :refer [defspec]])) ;; The median (q2) should be between the first and last numbers. (def prop-median-between-first-and-last (prop/for-all [v (gen/not-empty (gen/vector gen/small-integer))] (let [[q0 q1 q2 q3 q4] (quartiles v)] (<= (apply min v) q2 (apply max v))))) (defspec median-between-first-and-last 100 ;; number of iterations prop-median-between-first-and-last) ;; q0 <= q1 <= q2 <= q3 <= q4 (def prop-quartiles-are-sorted ;; need a vec with at least size 2 (prop/for-all [v (gen/vector gen/small-integer 2 25)] (let [q (quartiles v)] (apply <= q)))) ;; or (= q (sort q)) (defspec quartiles-are-sorted 100 prop-quartiles-are-sorted) ;; Metamorphic test: ;; ;; These are invariants that we can guarantee. But invariants ;; are just one way to create properties. We can also do a metamorphic test: ;; ;; 1. Generate a random list l1. ;; 2. Calculate the quartiles l1q. ;; 3. Add a number to the list l1 that is greater than the max, call it l2. ;; 4. Calculate the quartiles l2q. ;; ;; The values in l2q should be greater than or equal to the corresponding values ;; in l1q. (def prop-metamorphic-test (prop/for-all [l1 (gen/vector gen/small-integer 2 25) a (gen/fmap inc gen/nat)] (let [b (+ a (apply max l1)) ;; make sure b is larger than q4 of l1 l2 (conj l1 b) l1q (quartiles l1) l2q (quartiles l2)] (every? identity (map >= l2q l1q))))) (defspec metamorphic-test 100 prop-metamorphic-test) ;; for debugging problems (comment (tc/quick-check 100 prop-median-between-first-and-last) (tc/quick-check 100 prop-quartiles-are-sorted) (tc/quick-check 100 prop-metamorphic-test))