Skip to content

Instantly share code, notes, and snippets.

@KingCode
Last active July 1, 2020 00:57
Show Gist options
  • Save KingCode/5ed247d4353e5d5652d58c4fd68e3594 to your computer and use it in GitHub Desktop.
Save KingCode/5ed247d4353e5d5652d58c4fd68e3594 to your computer and use it in GitHub Desktop.
Properties test for Functional-TV challenge #384
;; see
;; https://gist.github.com/ericnormand/81722b80fc7d0b2972fda68652489f65
(ns my-ns-test
(:require [my-ns :as sut]
[clojure.test.check.properties :as prop]
[clojure.test.check.generators :as gen]
[clojure.test.check.clojure-test :refer [defspec]]))
(let [alias-str "sut"
sym (symbol (str alias-str "/parallel?"))]
(def ||? (resolve sym)))
(defn line [a b c] [a b c])
(defn y [x [a b c :as line]]
(-> c (- (* a x)) (/ b)))
(defn vertical-distance [x line-1 line-2]
(- (y x line-2) (y x line-1)))
(defn vertical? [[_ b _ :as line]]
(= 0 b))
(defn not-vertical? [[_ b _ :as line]]
(not= 0 b))
(def gen-smallint-nozero (gen/such-that #(not= 0 %) gen/small-integer))
;; [0,0,c] is not a line
(def gen-line (gen/frequency [[1 (gen/tuple gen-smallint-nozero
gen/small-integer
gen/small-integer)],
[1 (gen/tuple gen/small-integer
gen-smallint-nozero
gen/small-integer)]]))
(def gen-line-diagonal (gen/tuple gen-smallint-nozero
gen-smallint-nozero
gen/small-integer))
(defn z0->pos [x & excluded]
(if (= 0 x)
(rand-nth (remove (set excluded)
(range 1 100)))
x))
(defn ->vertical [[a b c]]
;; ensure (not= 0 a b)
[(z0->pos a), 0, c])
(defn ->non-vertical [[a b c]]
[a , (z0->pos b), c])
(defn ->horizontal [[a b c]]
[0, (z0->pos b), c])
(defn same? [[a1 b1 c1 :as line1] [a2 b2 c2 :as line2]]
(cond
(= 0 a1 a2)
(or (= 0 c1 c2) (= (* b1 c2) (* b2 c1)))
(= 0 b1 b2)
(or (= 0 c1 c2) (= (* a1 c2) (* a2 c1)))
(or (zero? b1) (zero? b2))
(= (* c1 a2) (* c2 a1))
(or (zero? a1) (zero? a2))
(= (* c1 b2) (* c2 b1))
:else
(and (= (* a1 b2) (* a2 b1))
(= (y 1 line1) (y 1 line2)))))
(def gen-vertical-line (gen/fmap ->vertical gen-line))
(def gen-line-pair (gen/tuple gen-line gen-line))
(defn gen-distinct
([g]
(gen-distinct #(apply not= %) g))
([pred g]
(gen/such-that pred g)))
(defn gen-line-pair-distinct
([] (gen-line-pair-distinct gen-line-pair))
([g]
(gen-distinct (fn [[line1 line2]]
(not (same? line1 line2)))
g)))
(defn distinct-pair? [pair]
(not (apply same? pair)))
(defn gen-line-pair-n-vertical [n]
(let [fs (take 2 (concat (repeat n ->vertical)
(repeat 2 ->non-vertical)))]
(gen-line-pair-distinct (gen/fmap
(fn [pair]
(mapv #(% %2) fs pair))
(gen-line-pair-distinct
gen-line-pair)))))
(def gen-line-pair-horizontals
(gen-line-pair-distinct (gen/fmap (fn [[[_ b1 c1] [_ b2 c2]]]
(let [b1 (z0->pos b1)]
[[0, (z0->pos b1), c1]
[0, (z0->pos b2 b1), c2]]))
(gen-line-pair-distinct))))
(defn rand-nth-nozero [low hi]
(rand-nth (remove zero? (range low hi))))
(defn pos-nth [upper]
(rand-nth (range 1 upper)))
(defn invert [[a b c :as line]]
[(- a) b c])
(defn gen-pair-diagonals|| [limit]
(gen-line-pair-distinct
(gen/fmap (fn [[a b c :as line]]
(let [spice (pos-nth limit)]
[[a b c] [(* spice a), (* spice b), (+ c spice)]]))
gen-line-diagonal)))
(defmacro implies [pred-form then-form]
`(if ~pred-form ~then-form true))
(defspec detects-parallel-lines 100
(prop/for-all [[line1 line2 :as pair]
(gen/frequency [[6 (gen-line-pair-distinct
(gen-pair-diagonals|| 22))]
[3 (gen-line-pair-distinct
gen-line-pair-horizontals)]
[3 (gen-line-pair-n-vertical 2)]])]
(||? line1 line2)))
(defspec detects-non-parallel-lines 100
(prop/for-all [[line1 line2 :as pair]
(gen/frequency [[3 (gen-line-pair-n-vertical 1)]
[3 (gen/fmap (fn [line]
[line (invert line)])
(gen/such-that not-vertical?
gen-line))]
[1 (gen/fmap (fn [line]
[line line])
gen-line)]])]
(not (||? line1 line2))))
(defspec non-vertical-||s-points-sharing-x-coord-have-same-vertical-distance
100
(prop/for-all [[line1 line2 :as pair]
(gen/frequency [[3 (gen-pair-diagonals|| 7)],
[1 gen-line-pair-horizontals]])
xs (gen/set gen/small-integer {:min-elements 2
:max-tries 1000})]
(let [no-vert? (not-any? vertical? pair)]
(implies (and no-vert? (||? line1 line2))
(->> xs
(map #(vertical-distance % line1 line2))
(apply =))))))
(defspec both-or-none-vertical-if-|| 100
(prop/for-all [[line1 line2 :as pair]
(gen/frequency [[2 (gen-line-pair-n-vertical 2)]
[2 (gen-line-pair-n-vertical 1)]
[3 (gen-pair-diagonals|| 10)]])]
(implies (||? line1 line2)
(or (every? vertical? pair)
(not-any? vertical? pair)))))
(defspec not-parallel-to-itself 100
(prop/for-all [[line1 line2]
(gen/frequency [[1 (gen/fmap (fn [line]
[line line])
gen-line)]
[9 (gen/fmap (fn [line]
(let [fact (rand-nth-nozero -20 20)]
[line,
(mapv #(* fact %) line)]))
gen-line)]])]
(not (||? line1 line2))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment