204 lines
7 KiB
Clojure
204 lines
7 KiB
Clojure
(ns clojure.math.test-combinatorics
|
|
(:require [clojure.math.combinatorics :refer
|
|
[subsets combinations selections permutations cartesian-product
|
|
partitions nth-permutation permutation-index drop-permutations
|
|
permuted-combinations
|
|
count-permutations count-combinations count-subsets
|
|
nth-subset nth-combination]]
|
|
[clojure.test :refer [deftest is are testing run-tests]]))
|
|
|
|
(deftest test-permuted-combinations
|
|
(are [x y] (= x y)
|
|
(permuted-combinations [1 2 3] 2) '([1 2] [2 1] [1 3] [3 1] [2 3] [3 2])
|
|
(permuted-combinations [1 2 2] 2) '([1 2] [2 1] [2 2])))
|
|
|
|
(deftest test-combinations
|
|
(are [x y] (= x y)
|
|
(combinations [1 2 3] 2) '((1 2) (1 3) (2 3))))
|
|
|
|
(defn old-subsets [l]
|
|
(map (partial map deref) (subsets (map atom l))))
|
|
|
|
(deftest test-subsets
|
|
(are [x y] (= x y)
|
|
(subsets []) '(())
|
|
(subsets [1 2 3]) '(() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))
|
|
(subsets [3 2 1]) '(() (3) (2) (1) (3 2) (3 1) (2 1) (3 2 1))
|
|
(subsets [1 2 3 4]) '(() (1) (2) (3) (4) (1 2) (1 3) (1 4) (2 3) (2 4) (3 4) (1 2 3) (1 2 4) (1 3 4) (2 3 4) (1 2 3 4))
|
|
(subsets [1 1 2]) (subsets [1 2 1])
|
|
(subsets [1 3 2 3]) (subsets [1 3 3 2]))
|
|
(are [x] (and (= (subsets x) (distinct (old-subsets x)))
|
|
(= (count (subsets x)) (count-subsets x)))
|
|
[]
|
|
[1 2 3 4]
|
|
[1 1 2 2 2 3]
|
|
[1 1 1 2 2 3]
|
|
[1 1 1 1 1]
|
|
[1 2 2 3 3 3]
|
|
[1 1 2 2 3 3]
|
|
[1 1 1 2 2 2]
|
|
[1 2 2 2 3 3]
|
|
[1 1 1 1 2 2]
|
|
[1 2 3 3 4 4]
|
|
[1 1 2 3 3 4]))
|
|
|
|
(deftest test-nth-combination
|
|
(are [x]
|
|
(every?
|
|
(fn [t]
|
|
(and (= (count-combinations x t) (count (combinations x t)))
|
|
(let [c (count-combinations x t)]
|
|
(= (for [i (range c)] (nth-combination x t i))
|
|
(combinations x t)))))
|
|
(range (inc (count x))))
|
|
[1 2 3 4]
|
|
[]
|
|
[1 2 2 3 3 3]
|
|
[1 1 1 2 2 3]
|
|
[1 2 2 2 3 3]
|
|
[1 1 1 2 3 3]
|
|
[1 1 2 3 3 3]
|
|
[1 2 3 1 2 1]
|
|
[\a \b \c]
|
|
[\a \b \c \a \b \c]
|
|
))
|
|
|
|
(deftest test-nth-subset
|
|
(are [x]
|
|
(let [c (count-subsets x)]
|
|
(= (for [i (range c)] (nth-subset x i))
|
|
(subsets x)))
|
|
[1 2 3 4]
|
|
[]
|
|
[1 2 2 3 3 3]
|
|
[1 1 1 2 2 3]
|
|
[1 2 2 2 3 3]
|
|
[1 1 1 2 3 3]
|
|
[1 1 2 3 3 3]
|
|
[1 2 3 1 2 1]
|
|
[\a \b \c]
|
|
[\a \b \c \a \b \c]))
|
|
|
|
(deftest test-cartesian-product
|
|
(are [x y] (= x y)
|
|
(cartesian-product [1 2] [3 4]) '((1 3) (1 4) (2 3) (2 4))))
|
|
|
|
(deftest test-selections
|
|
(are [x y] (= x y)
|
|
(selections [1 2] 3) '((1 1 1) (1 1 2) (1 2 1) (1 2 2) (2 1 1) (2 1 2) (2 2 1) (2 2 2))))
|
|
|
|
(def lex-permutations @#'clojure.math.combinatorics/lex-permutations)
|
|
|
|
(deftest test-permutations
|
|
(are [x y] (= x y)
|
|
(permutations [1 2 3]) '((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1))
|
|
(permutations [2 3 1]) '((2 3 1) (2 1 3) (3 2 1) (3 1 2) (1 2 3) (1 3 2))
|
|
(permutations [1 1 2]) (lex-permutations [1 1 2])
|
|
(permutations [:a :b]) [[:a :b] [:b :a]]
|
|
(permutations [2 1 1]) [[2 1 1] [1 2 1] [1 1 2]]))
|
|
|
|
(deftest test-lex-permutations
|
|
(are [x y] (= x y)
|
|
(lex-permutations [1 1 2]) '([1 1 2] [1 2 1] [2 1 1])))
|
|
|
|
(def sorted-numbers? @#'clojure.math.combinatorics/sorted-numbers?)
|
|
|
|
(deftest test-sorted-numbers?
|
|
(are [x y] (= x y)
|
|
(sorted-numbers? [1 2 3]) true
|
|
(sorted-numbers? [1 1 2]) true
|
|
(sorted-numbers? []) true
|
|
(sorted-numbers? [1 4 2]) false
|
|
(sorted-numbers? [1 :a 2]) false))
|
|
|
|
(def factorial-numbers @#'clojure.math.combinatorics/factorial-numbers)
|
|
|
|
(deftest test-factorial-numbers
|
|
(are [x y] (= (factorial-numbers x) y)
|
|
463 [3 4 1 0 1 0]
|
|
0 []
|
|
1 [1 0]
|
|
2 [1 0 0]))
|
|
|
|
(def nth-permutation-distinct @#'clojure.math.combinatorics/nth-permutation-distinct)
|
|
|
|
(deftest test-nth-permutation-distinct
|
|
(let [perms (permutations (range 4))]
|
|
(doseq [i (range 24)]
|
|
(is (= (nth perms i) (nth-permutation-distinct (range 4) i))))))
|
|
|
|
(def nth-permutation-duplicates @#'clojure.math.combinatorics/nth-permutation-duplicates)
|
|
|
|
(deftest test-nth-permutation-duplicates
|
|
(let [perms (permutations [1 1 2 2 2 3])]
|
|
(doseq [i (range 60)]
|
|
(is (= (nth perms i) (nth-permutation-duplicates [1 1 2 2 2 3] i))))))
|
|
|
|
(deftest test-count-permutations
|
|
(are [x] (= (count-permutations x) (count (permutations x)))
|
|
(range 4)
|
|
[1 1 2]
|
|
[1 1 2 2]
|
|
[1 1 1 2 2 3]))
|
|
|
|
(deftest test-nth-permutation
|
|
(let [sortedDistinctNumbers (range 4)
|
|
sortedDuplicateNumbers [1 1 1 2 3 3]
|
|
distinctChars [\a \b \c \d]
|
|
duplicates [\a \a \b \c \c]
|
|
duplicates2 [1 3 1 2 1 2]]
|
|
(doseq [collection [sortedDistinctNumbers
|
|
sortedDuplicateNumbers
|
|
distinctChars
|
|
duplicates
|
|
duplicates2],
|
|
:let [perms (permutations collection)
|
|
c (count perms)]
|
|
n (range c)]
|
|
(is (= (nth perms n) (nth-permutation collection n)))
|
|
(is (= c (count-permutations collection))))))
|
|
|
|
(deftest test-drop-permutations
|
|
(doseq [x [[1 2 3]
|
|
[1 1 2]
|
|
[\a \b \c]
|
|
[\a \a \b \c \c]
|
|
[1 3 1 2 1 2]]
|
|
:let [c (count-permutations x)]
|
|
i (range c)]
|
|
(is (= (drop-permutations x i) (drop i (permutations x))))))
|
|
|
|
(deftest test-permutation-index
|
|
(let [sortedDistinctNumbers (range 4)
|
|
sortedDuplicateNumbers [1 1 1 2 3 3]
|
|
distinctChars [\a \b \c \d]
|
|
duplicates [\a \a \b \c \c]
|
|
duplicates2 [1 3 1 2 1 2]]
|
|
(doseq [collection [sortedDistinctNumbers
|
|
sortedDuplicateNumbers
|
|
distinctChars
|
|
duplicates
|
|
duplicates2],
|
|
perm (permutations collection)]
|
|
(is (= (nth-permutation (sort collection) (permutation-index perm))
|
|
perm)))))
|
|
|
|
(deftest test-partitions
|
|
(do (are [x y] (= x y)
|
|
(partitions [1 2 3]) '(([1 2 3]) ([1 2] [3]) ([1 3] [2]) ([1] [2 3]) ([1] [2] [3]))
|
|
(partitions [1 2]) '(([1 2]) ([1] [2]))
|
|
(partitions [1]) '(([1]))
|
|
(partitions []) '(())
|
|
(partitions nil) '(())
|
|
(partitions [1 1 1]) '(([1 1 1]) ([1 1] [1]) ([1] [1] [1]))
|
|
(partitions [1 1 2]) '(([1 1 2]) ([1 1] [2]) ([1 2] [1]) ([1] [1] [2])))
|
|
(doseq [num-items (range 0 4)
|
|
lo (range -1 (+ 2 num-items))
|
|
hi (range -1 (+ 2 num-items))]
|
|
(is (= (partitions (range num-items) :min lo :max hi)
|
|
(filter #(<= lo (count %) hi) (partitions (range num-items)))))) ; tests partitions-H
|
|
(doseq [num-items (range 2 4)
|
|
lo (range -1 (+ 2 num-items))
|
|
hi (range -1 (+ 2 num-items))]
|
|
(is (= (partitions (cons 0 (range (dec num-items))) :min lo :max hi)
|
|
(filter #(<= lo (count %) hi) (partitions (cons 0 (range (dec num-items)))))))))) ; tests partitions-M
|