 
 (defn iterate-cycle [coll x]
   (reductions #(%2 %1) x (cycle coll)))
+
+(defn unique [coll key-fun]
+  (letfn [(step [acc x]
+                (let [[seen _] acc
+                      key (key-fun x)]
+                  (if (seen key)
+                    [seen false]
+                    [(conj seen key) x])))]
+         (filter identity (map second (reductions step [#{} false] coll)))))
 
 (defn walk [ds D & idxs]
   (reduce #(.op ds %2 %1) D idxs))

    (doseq [D (keys tmp2oct)]
      (if (not (.definesV tmp 1 2 D))
        (.redefineV tmp 1 2 D (.v ds 1 2 (tmp2oct D)))))
    (-> tmp .dual .minimal .canonical)))

(def octa-sets (filter #(-> %1 max-curvature .isNegative not)
                       (lazy-seq (new CombineTiles octagon))))

        :when (-> dsym .curvature2D .isZero)]
    dsym))

(def azul-syms
  (let [raw (for [ds octa-syms o2t boundary-mappings] (on-template ds o2t))]
    (for [ds (unique raw #(-> %1 .minimal .invariant))]
      (-> ds .dual .minimal .canonical))))

(defn -main []
  (do
