Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
24 changes: 13 additions & 11 deletions src/darwin/algorithms/spea2.clj
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@

(defn coords-from-individual
"Get the individuals coordinates in objective space as a vector."
[[k1 k2] i]
[(k1 i) (k2 i)])
[ks i]
(mapv (fn [k]
(k i))
ks))

(defn- calculate-density
[distance]
Expand All @@ -72,15 +74,15 @@
"Calculate the 'densities' for each individual in a population. The density is defined as 1 / (distance to
kth-nearest neighbour + 2). k is taken as the sqrt of the population size. Assocs the densities into the
individuals."
[[k1 k2] population]
[ks population]
(let [k (Math/sqrt (count population))
;; we extract the coordinates of each individual in objective space and build a kd-tree from them
;; so we can efficiently find the nearest neighbours.
coords (map (partial coords-from-individual [k1 k2]) population)
coords (map (partial coords-from-individual ks) population)
tree (kdtree/build-tree coords)]
(map #(assoc % :spea2-density
(calculate-density
(kth-nearest-distance tree k (coords-from-individual [k1 k2] %))))
(calculate-density
(kth-nearest-distance tree k (coords-from-individual ks %))))
population)))

(defn calculate-fitnesses
Expand Down Expand Up @@ -108,7 +110,7 @@
(let [tree (:tree tree-and-archive)
oversized-archive (:archive tree-and-archive)
measured-archive (map #(assoc % :spea2-distances
(k-nearest-distances tree comparison-depth (coords-from-individual goals %)))
(k-nearest-distances tree comparison-depth (coords-from-individual goals %)))
oversized-archive)
;; this next step relies on the sort being done lexicographically on the distance arrays.
;; That `sort-by` does this isn't mentioned in the docstring, but is explicitly stated
Expand All @@ -134,8 +136,8 @@
(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 goals comparison-depth)
{:tree tree :archive oversized-archive})
(partial remove-one-item goals comparison-depth)
{:tree tree :archive oversized-archive})
(- (count oversized-archive) target-size))]
(:archive thinned-tree-and-archive)))

Expand Down Expand Up @@ -202,8 +204,8 @@
:or {comparison-depth 5
deduplicate false}} config]
{:elite-selector (fn [rabble elite]
(make-new-archive goals deduplicate comparison-depth archive-size rabble elite))
(make-new-archive goals deduplicate comparison-depth archive-size rabble elite))
:mating-pool-selector (fn [_ elite] elite)
:reproduction-config {:selector (partial selection/tournament-selector 2 :spea2-fitness)
:unary-ops unary-ops
:binary-ops binary-ops}}))
:binary-ops binary-ops}}))
30 changes: 17 additions & 13 deletions src/darwin/evolution/pareto.clj
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,36 @@
(defn dominates
"Does i1 Pareto-dominate i2, as judged by the values associated with the given keys, k1 and k2.
Lower scores are considered better."
[[k1 k2] i1 i2]
(or (and (<= (k1 i1) (k1 i2)) (< (k2 i1) (k2 i2)))
(and (<= (k2 i1) (k2 i2)) (< (k1 i1) (k1 i2)))))
[ks i1 i2]
(and (every? (fn [k]
(<= (k i1) (k i2)))
ks)
(some (fn [k]
(< (k i1) (k i2)))
ks)))

(defn dominated-set
"Returns the individuals that i dominates wrt k1 and k2. Note that it doesn't return a set, rather a
list (which I guess is a multiset) but `dominated-multiset` is too much of a mouthful."
[[k1 k2] individuals i]
(filter #(dominates [k1 k2] i %) individuals))
[ks individuals i]
(filter #(dominates ks i %) individuals))

(defn dominator-set
"Returns the individuals that dominate i wrt k1 and k2. As above, it doesn't return a set."
[[k1 k2] individuals i]
(filter #(dominates [k1 k2] % i) individuals))
[ks individuals i]
(filter #(dominates ks % i) individuals))

(defn dominated-count
"Count how many individuals i dominates wrt to k1 and k2."
[[k1 k2] individuals i]
(count (dominated-set [k1 k2] individuals i)))
[ks individuals i]
(count (dominated-set ks individuals i)))

(defn- individual-dominated?
"Is an individual i dominated by any of the given individuals wrt the keys k1 and k2?"
[[k1 k2] individuals i]
(reduce #(or %1 %2) (map #(dominates [k1 k2] % i) individuals)))
[ks individuals i]
(reduce #(or %1 %2) (map #(dominates ks % i) individuals)))

(defn non-dominated-individuals
"Returns the individuals that are non-dominated with respect to k1 and k2."
[[k1 k2] individuals]
(filter #(not (individual-dominated? [k1 k2] individuals %)) individuals))
[ks individuals]
(filter #(not (individual-dominated? ks individuals %)) individuals))