From 84f2e6a88dba3eb50f01f95351312ac72aba6104 Mon Sep 17 00:00:00 2001 From: Ashley Bao Date: Wed, 11 Jan 2023 21:37:37 -0500 Subject: [PATCH] added docstrings more comments in genome, gp, selection, simplification, utils, variation --- src/propeller/genome.cljc | 2 +- src/propeller/gp.cljc | 8 ++++---- src/propeller/selection.cljc | 13 ++++++++++--- src/propeller/simplification.cljc | 4 +++- src/propeller/tools/math.cljc | 9 +++++++-- src/propeller/utils.cljc | 2 +- src/propeller/variation.cljc | 20 ++++++++++++++------ 7 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/propeller/genome.cljc b/src/propeller/genome.cljc index cd71c8c..e2485c5 100755 --- a/src/propeller/genome.cljc +++ b/src/propeller/genome.cljc @@ -3,7 +3,7 @@ [propeller.utils :as utils])) (defn make-random-plushy - "Creates and returns a new plushy." + "Creates and returns a new plushy made of random instructions and of a maximum size of max-initial-plushy-size." [instructions max-initial-plushy-size] (repeatedly (rand-int max-initial-plushy-size) diff --git a/src/propeller/gp.cljc b/src/propeller/gp.cljc index 808dbab..fcc1bb4 100644 --- a/src/propeller/gp.cljc +++ b/src/propeller/gp.cljc @@ -46,15 +46,15 @@ (loop [generation 0 population (mapper (fn [_] {:plushy (genome/make-random-plushy instructions max-initial-plushy-size)}) - (range population-size))] + (range population-size))] ;creates population of random plushys (let [evaluated-pop (sort-by :total-error (mapper (partial error-function argmap (:training-data argmap)) - population)) + population)) ;population sorted by :total-error best-individual (first evaluated-pop) argmap (if (= (:parent-selection argmap) :epsilon-lexicase) (assoc argmap :epsilons (selection/epsilon-list evaluated-pop)) - argmap)] + argmap)] ;adds :epsilons if using epsilon-lexicase (if (:custom-report argmap) ((:custom-report argmap) evaluated-pop generation argmap) (report evaluated-pop generation argmap)) @@ -75,6 +75,6 @@ (if (:elitism argmap) (conj (repeatedly (dec population-size) #(variation/new-individual evaluated-pop argmap)) - (first evaluated-pop)) + (first evaluated-pop)) ;elitism maintains the most-fit individual (repeatedly population-size #(variation/new-individual evaluated-pop argmap)))))))) diff --git a/src/propeller/selection.cljc b/src/propeller/selection.cljc index bc89788..f04579c 100755 --- a/src/propeller/selection.cljc +++ b/src/propeller/selection.cljc @@ -2,14 +2,18 @@ (:require [propeller.tools.math :as math-tools])) (defn tournament-selection - "Selects an individual from the population using a tournament." + "Selects an individual from the population using tournaments of + tournament-size by taking the individual in the tournament with the lowest :total-error. " [pop argmap] (let [tournament-size (:tournament-size argmap) tournament-set (take tournament-size (shuffle pop))] (apply min-key :total-error tournament-set))) (defn lexicase-selection - "Selects an individual from the population using lexicase selection." + "Selects an individual from the population using lexicase selection. + Lexicase parent selection filters the population by considering one random training case at a time, + eliminating any individuals with errors for the current case that are worse than the best error in the selection pool, + until a single individual remains." [pop argmap] (loop [survivors (map rand-nth (vals (group-by :errors pop))) cases (shuffle (range (count (:errors (first pop)))))] @@ -23,6 +27,7 @@ (rest cases)))))) (defn epsilon-list + "List of epsilons for each training case based on median absolute deviation of errors." [pop] (let [error-list (map :errors pop) length (count (:errors (first pop)))] @@ -35,7 +40,9 @@ (inc i)))))) (defn epsilon-lexicase-selection - "Selects an individual from the population using epsilon-lexicase selection." + "Selects an individual from the population using epsilon-lexicase selection. + Epsilon lexicase selection follows the same process as lexicase selection except, + for a test case, only individuals with an error outside of a predefined epsilon are filtered." [pop argmap] (let [epsilons (:epsilons argmap)] (loop [survivors pop diff --git a/src/propeller/simplification.cljc b/src/propeller/simplification.cljc index f896e38..2e37888 100644 --- a/src/propeller/simplification.cljc +++ b/src/propeller/simplification.cljc @@ -6,6 +6,7 @@ )) (defn choose-random-k + "Takes k random indices" [k indices] (take k (shuffle indices))) @@ -16,11 +17,12 @@ (keep-indexed #(when (not (some #{%1} sorted-indices)) %2) plushy))) (defn delete-k-random + "Deletes k random instructions from the plushy" [k plushy] (delete-at-indices (choose-random-k k (range (count plushy))) plushy)) (defn auto-simplify-plushy - "naive auto-simplification" + "simplifies plushy by deleting instructions that have no impact on errors. naive auto-simplification" [plushy error-function {:keys [simplification-steps training-data simplification-k simplification-verbose?] :as argmap}] (when simplification-verbose? (prn {:start-plushy-length (count plushy) :k simplification-k})) (let [initial-errors (:errors (error-function argmap training-data {:plushy plushy}))] diff --git a/src/propeller/tools/math.cljc b/src/propeller/tools/math.cljc index 6649cf7..7fd463e 100755 --- a/src/propeller/tools/math.cljc +++ b/src/propeller/tools/math.cljc @@ -6,14 +6,18 @@ (defonce E #?(:clj Math/E :cljs js/Math.PI)) -(defn mean [coll] +(defn mean + "Returns the mean." + [coll] (let [sum (apply + coll) count (count coll)] (if (pos? count) (/ sum (float count)) 0.0))) -(defn median [coll] +(defn median + "Returns the median." + [coll] (let [sorted (sort coll) cnt (count sorted) halfway (quot cnt 2.0)] @@ -25,6 +29,7 @@ (mean [bottom-val top-val]))))) (defn median-absolute-deviation + "Returns the median absolute deviation." [coll] (let [median-val (median coll)] (median (map #(Math/abs (- % median-val)) coll)))) diff --git a/src/propeller/utils.cljc b/src/propeller/utils.cljc index 5f0b231..47e1f95 100755 --- a/src/propeller/utils.cljc +++ b/src/propeller/utils.cljc @@ -21,7 +21,7 @@ lst)) (defn ensure-list - "Returns a non-lazy list if passed a seq argument. Othwrwise, returns a list + "Returns a non-lazy list if passed a seq argument. Otherwise, returns a list containing the argument." [thing] (if (seq? thing) diff --git a/src/propeller/variation.cljc b/src/propeller/variation.cljc index 51b0398..d630bda 100755 --- a/src/propeller/variation.cljc +++ b/src/propeller/variation.cljc @@ -3,7 +3,8 @@ [propeller.utils :as utils])) (defn crossover - "Crosses over two individuals using uniform crossover. Pads shorter one." + "Crosses over two individuals using uniform crossover, one Push instruction at a time. + Pads shorter one from the end of the list of instructions." [plushy-a plushy-b] (let [shorter (min-key count plushy-a plushy-b) longer (if (= shorter plushy-a) @@ -17,7 +18,8 @@ longer)))) (defn tail-aligned-crossover - "Crosses over two individuals using uniform crossover. Pads shorter one on the left." + "Crosses over two individuals using uniform crossover, one Push instruction at a time. + Pads shorter one from the beginning of the list of instructions." [plushy-a plushy-b] (let [shorter (min-key count plushy-a plushy-b) longer (if (= shorter plushy-a) @@ -31,7 +33,8 @@ longer)))) (defn diploid-crossover - "Crosses over two individuals using uniform crossover. Pads shorter one." + "Crosses over two individuals using uniform crossover with pairs of Push instructions. + Pads shorter one from the end of the list of instructions." [plushy-a plushy-b] (let [plushy-a (partition 2 plushy-a) plushy-b (partition 2 plushy-b) @@ -47,7 +50,8 @@ longer))))) (defn tail-aligned-diploid-crossover - "Crosses over two individuals using uniform crossover. Pads shorter one on the left." + "Crosses over two individuals using uniform crossover with pairs of Push instructions. + Pads shorter one from the beginning of the list of instructions." [plushy-a plushy-b] (let [plushy-a (partition 2 plushy-a) plushy-b (partition 2 plushy-b) @@ -156,7 +160,10 @@ (-> (:plushy (selection/select-parent pop argmap)) (uniform-addition (:instructions argmap) (:umad-rate argmap)) (uniform-deletion (:umad-rate argmap))) - ; + ; uniform mutation by addition and deletion is a uniform mutation operator which + ;first adds genes with some probability before or after every existing gene and then + ;deletes random genes from the resulting genome + :rumad (let [parent-genome (:plushy (selection/select-parent pop argmap)) after-addition (uniform-addition parent-genome @@ -166,7 +173,8 @@ (count parent-genome)) (count parent-genome))] (uniform-deletion after-addition effective-addition-rate)) - ; + ; Adds and deletes instructions in the parent genome with the same rate + :uniform-addition (-> (:plushy (selection/select-parent pop argmap)) (uniform-addition (:instructions argmap) (:umad-rate argmap)))