-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path152-latin-square-slicing.clj
113 lines (98 loc) · 3.48 KB
/
152-latin-square-slicing.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
;; I used to start from the end. Let's define the core predicate for the task.
(defn row-columns [x]
(concat x (apply map list x)))
(defn latin? [x]
(every?
#(and
(= (set %) (set (flatten x)))
(apply = (vals (frequencies %))))
(row-columns x))
)
;; utilitary function
;; [a [b c] ... ] -> [[a b ... ] [a c ...]]
(defn unzip-seq [c]
(reduce
(fn [c e]
(reduce
#(concat % (map (fn [p] (conj p %2)) c))
[] e))
[[]] c))
;; generate all possible alignments for x
;; [[:a :b :c] [:f]] -> [[0 0] [0 1] [0 2]]
(defn alignments [x]
(let [width (last (sort (map count x)))]
(vec (unzip-seq (map #(range (inc (- width (count %)))) x)))))
;; sort of get-in which works for aligned seq
(defn profile [s] (mapv #(set (keys %)) s))
(defn s-map [a x]
(mapv #(zipmap (range % (+ % (count %2))) %2) a x))
;; let's seek in the deep on every (but last) levels
;; for each row we have seq of sets Ai with property
;; Ai+1 belongs to Ai for every i
(defn mining [s]
(map
(fn [r] (reductions (fn [a b] (set (filter a b))) r))
(drop-last (take-while seq (iterate next (profile s))))))
;; utilitary function, takes an arbitrary matrix 'm' and produces
;; square matrices of length '(count m)' by horizontal sliding
(defn h-slice [m]
(let [n (count m)]
(if (< (count (last m)) n) []
(concat [(map #(take n %) m)] (h-slice (map next m))))))
;; use mining data to generate rectangular maps
(defn gen-maps-r [s]
(for [ m (mapv vector (iterate next s) (mining s))
[i c] (map list (range 1 (count (m 1))) (next (m 1)))
:while (> (count c) i)]
(map #(replace % %2) (m 0) (take (inc i) (repeat c)))))
;; what a nice word 'lift'
(defn lift-data [m s]
(map #(replace (s %) (m %)) (range (count m))))
(fn [x]
(letfn [
(row-columns [x] (concat x (apply map list x)))
(latin? [x]
(every?
#(and
(= (set %) (set (flatten x)))
(apply = (vals (frequencies %))))
(row-columns x)))
(unzip-seq [c]
(reduce
(fn [c e]
(reduce
#(concat % (map (fn [p] (conj p %2)) c))
[] e))
[[]] c))
(alignments [x]
(let [width (last (sort (map count x)))]
(vec (unzip-seq (map #(range (inc (- width (count %)))) x)))))
(profile [s] (mapv #(set (keys %)) s))
(s-map [a x]
(mapv #(zipmap (range % (+ % (count %2))) %2) a x))
(mining [s]
(map
(fn [r] (reductions (fn [a b] (set (filter a b))) r))
(drop-last (take-while seq (iterate next (profile s))))))
(h-slice [m]
(let [n (count m)]
(if (< (count (last m)) n) []
(concat [(map #(take n %) m)] (h-slice (map next m))))))
(gen-maps [s]
(for [ m (mapv vector (iterate next s) (mining s))
[i c] (map list (range 1 (count (m 1))) (next (m 1)))
:while (> (count c) i)]
(map #(replace % %2) (m 0) (take (inc i) (repeat c)))))
(lift-data [m s]
(map #(replace (s %) (m %)) (range (count m))))
]
(->> x
(alignments)
(map #(s-map % x))
(mapcat #(->> %
(gen-maps)
(mapcat h-slice)
(filter latin?)))
(distinct)
(map count)
(frequencies))))