       ;; is to just sort and select from the pool.
       (< new-size archive-size) (take archive-size (sort-by :spea2-fitness < scored-pool))
       ;; and finally, if we've got too many non-dominated individuals then some of them are for the chop
-      (> new-size archive-size) (simple-archive-thinner goals new-elites archive-size))))
+      (> new-size archive-size) (thin-archive goals new-elites comparison-depth archive-size))))
 
 
 ;; * algebolic.evolution.core configuration *


;; * Archive construction functions *

(defn- remove-one-item-simple
  [goals tree-and-archive]
  (let [tree (:tree tree-and-archive)
        oversized-archive (:archive tree-and-archive)
        measured-archive (map #(assoc % :spea2-distance
                                        (kth-nearest-distance tree 2 (coords-from-individual goals %)))
                              oversized-archive)
        sorted-archive (sort-by :spea2-distance < measured-archive)]
    {:archive (rest sorted-archive)
     :tree    (kdtree/delete tree (coords-from-individual goals (first sorted-archive)))}))

(defn simple-archive-thinner
  "SPEA2 has a fairly complicated prescription for thinning out the archive if it's oversized. It specifies
  that one should look for the individual who has the least distance to its nearest neighbour. If this doesn't
  yield a unique individual, then we should rank on distance to the second nearest neighbour, recursing until
  the tie is broken. We remove this individual from the population and repeat until we have thinned the archive
  to the desired size.

  We implement a simplified version of this algorithm (and it's unknown how this affects the performance, as I
  haven't compared it with the full SPEA2 thinner). We do the same as the SPEA2 prescription, except if
  individuals are tied on nearest neighbour distance then we break the tie arbitrarily, rather than on second
  nearest neighbour etc."
  [goals oversized-archive target-size]
  (let [coords (map (partial coords-from-individual goals) oversized-archive)
        tree (kdtree/build-tree coords)
        thinned-tree-and-archive (nth (iterate
                                        (partial remove-one-item-simple goals)
                                        {:tree tree :archive oversized-archive})
                                      (- (count oversized-archive) target-size))]
    (:archive thinned-tree-and-archive)))

(defn make-new-archive
  "Implements the core step of the SPEA2 algorithm which is constructing a new archive of elite
  individuals from the old archive and a population of new individuals."
  [goals archive-size population old-archive]
  (let [pool (into population old-archive)
        scored-pool (calculate-fitnesses goals pool)
        ;; individuals that are non-dominated will have a fitness less than 1
        new-elites (filter #(< (:spea2-fitness %) 1.0) scored-pool)
        new-size (count new-elites)
        _ (println "New archive raw size: " new-size)
        ]
    ;; there are three cases here: either the new archive is exactly the right size, too big, or too small
    (cond

(ns algebolic.algorithms.spea2
  "An implementation of the SPEA2 algorithm of Zitzler et al. Well, almost. There's a very slight
  difference in way the archive is constructed. Using my technique you can replicate SPEA2 exactly, but
  it runs slowly. You can approximate the behaviour of SPEA2 and have it run pretty fast. I've tested
  the approximation on a few problems and it doesn't seem to make any real difference. See the archive
  thinner functions for details of the difference.

  This code is currently limited to two objectives, but the API is arranged so that should be easy to
  generalise if needed."
