diff --git a/src/clojush/args.clj b/src/clojush/args.clj index 05d8b7fb6..f4279f768 100644 --- a/src/clojush/args.clj +++ b/src/clojush/args.clj @@ -205,6 +205,10 @@ ;; If :silent is used as an epigenetic-marker, this is the probability of random ;; instructions having :silent be true. + :track-instruction-maps false + ;; If true, each Plush instruction map will have a UUID attached to it. If the + ;; gene has a "parent gene", it will also have the UUID of its parent. + ;;---------------------------------------- ;; Arguments related to parent selection ;;---------------------------------------- diff --git a/src/clojush/pushgp/breed.clj b/src/clojush/pushgp/breed.clj index 019e8ceeb..a4ff4433b 100644 --- a/src/clojush/pushgp/breed.clj +++ b/src/clojush/pushgp/breed.clj @@ -90,23 +90,41 @@ rand-gen argmap)))) +(defn update-instruction-map-uuids + "Takes an individual and updates the UUIDs on every instruction-map in its + :genome, except for the ones which are a random insertion." + [individual] + (update individual :genome + (fn [genome] + (mapv (fn [instruction-map] + (if (:random-insertion instruction-map) + (dissoc instruction-map :random-insertion) + (assoc instruction-map + :parent-uuid (:uuid instruction-map) + :uuid (java.util.UUID/randomUUID)))) + genome)))) + (defn perform-genetic-operator "Takes a single genetic operator keyword or a sequence of operator keywords, and performs them to create a new individual. Uses recursive helper function even with a single operator by putting that operator in a vector." [operator population location rand-gen - {:keys [max-points] :as argmap}] + {:keys [max-points + track-instruction-maps] :as argmap}] (let [first-parent (select population location argmap) operator-vector (if (sequential? operator) operator (vector operator)) child (perform-genetic-operator-list operator-vector (assoc first-parent :parent-uuids (vector (:uuid first-parent))) population location rand-gen argmap)] - (if (> (count (:genome child)) - (/ max-points 4)) ; Check if too big - (revert-too-big-child first-parent child argmap) - (assoc child - :genetic-operators operator - )))) + (cond-> + (assoc child :genetic-operators operator) + + (> (count (:genome child)) + (/ max-points 4)) + (as-> c (revert-too-big-child first-parent c argmap)) + + track-instruction-maps + (update-instruction-map-uuids)))) (defn breed "Returns an individual bred from the given population using the given parameters." diff --git a/src/clojush/pushgp/pushgp.clj b/src/clojush/pushgp/pushgp.clj index 71369730e..83255c94e 100644 --- a/src/clojush/pushgp/pushgp.clj +++ b/src/clojush/pushgp/pushgp.clj @@ -19,6 +19,15 @@ (repl/pst except 10000) (System/exit 0)) +(defn strip-random-insertion-flags + "The :random-insertion flag is added to all elements of the + genome when generated. It is used to signal that an + instruction-map was generated randomly in the run (as opposed + to being mutated from a parent). The individuals in generation + 0 are a special case and should not have this flag present." + [genome] + (map #(dissoc % :random-insertion) genome)) + (defn make-pop-agents "Makes the population of agents containing the initial random individuals in the population. Argument is a push argmap" @@ -27,9 +36,10 @@ :as argmap}] (let [population-agents (repeatedly population-size #(make-individual - :genome (random-plush-genome max-genome-size-in-initial-program + :genome (strip-random-insertion-flags + (random-plush-genome max-genome-size-in-initial-program atom-generators - argmap) + argmap)) :genetic-operators :random))] (mapv #(if use-single-thread (atom %) diff --git a/src/clojush/pushgp/report.clj b/src/clojush/pushgp/report.clj index bee8708b2..5c993dfe8 100644 --- a/src/clojush/pushgp/report.clj +++ b/src/clojush/pushgp/report.clj @@ -41,6 +41,9 @@ (println (name param) "=" (random/seed-to-string val)) (println (name param) "=" val)))) +(defn print-genome [individual] + (pr-str (not-lazy (map #(dissoc % :uuid :parent-uuid) (:genome individual))))) + (defn behavioral-diversity "Returns the behavioral diversity of the population, as described by David Jackson in 'Promoting phenotypic diversity in genetic programming'. It is @@ -199,7 +202,7 @@ count-zero-by-case (map #(apply + %) (apply mapv vector pop-zero-by-case))] (println "--- Lexicse Program with Most Elite Cases Statistics ---") - (println "Lexicase best genome:" (pr-str (not-lazy (:genome lex-best)))) + (println "Lexicase best genome:" (print-genome lex-best)) (println "Lexicase best program:" (pr-str (not-lazy (:program lex-best)))) (when (> report-simplifications 0) (println "Lexicase best partial simplification:" @@ -217,7 +220,7 @@ (println "Lexicase best size:" (count-points (:program lex-best))) (printf "Percent parens: %.3f\n" (double (/ (count-parens (:program lex-best)) (count-points (:program lex-best))))) ;Number of (open) parens / points (println "--- Lexicse Program with Most Zero Cases Statistics ---") - (println "Zero cases best genome:" (pr-str (not-lazy (:genome most-zero-cases-best)))) + (println "Zero cases best genome:" (print-genome most-zero-cases-best)) (println "Zero cases best program:" (pr-str (not-lazy (:program most-zero-cases-best)))) (when (> report-simplifications 0) (println "Zero cases best partial simplification:" @@ -248,7 +251,7 @@ [population {:keys [print-errors meta-error-categories]}] (let [ifs-best (apply min-key :weighted-error population)] (println "--- Program with Best Implicit Fitness Sharing Error Statistics ---") - (println "IFS best genome:" (pr-str (not-lazy (:genome ifs-best)))) + (println "IFS best genome:" (print-genome ifs-best)) (println "IFS best program:" (pr-str (not-lazy (:program ifs-best)))) (when print-errors (println "IFS best errors:" (not-lazy (:errors ifs-best)))) (when (and print-errors (not (empty? meta-error-categories))) @@ -312,7 +315,7 @@ (when (some #{parent-selection} #{:lexicase :elitegroup-lexicase :leaky-lexicase}) (lexicase-report population argmap)) (when (= total-error-method :ifs) (implicit-fitness-sharing-report population argmap)) (println (format "--- Best Program (%s) Statistics ---" (str "based on " (name err-fn)))) - (println "Best genome:" (pr-str (not-lazy (:genome best)))) + (println "Best genome:" (print-genome best)) (println "Best program:" (pr-str (not-lazy (:program best)))) (when (> report-simplifications 0) (println "Partial simplification:" diff --git a/src/clojush/random.clj b/src/clojush/random.clj index ef48ca82e..e33d7c2ed 100644 --- a/src/clojush/random.clj +++ b/src/clojush/random.clj @@ -43,14 +43,17 @@ "Returns a random instruction map given the atom-generators and the required epigenetic-markers." ([atom-generators] - (random-plush-instruction-map atom-generators {})) - ([atom-generators {:keys [epigenetic-markers - close-parens-probabilities - silent-instruction-probability] - :or {epigenetic-markers [] - close-parens-probabilities [0.772 0.206 0.021 0.001] - silent-instruction-probability 0}}] - (let [markers (conj epigenetic-markers :instruction)] + (random-plush-instruction-map atom-generators {})) + ([atom-generators {:keys [epigenetic-markers + close-parens-probabilities + silent-instruction-probability + track-instruction-maps] + :or {epigenetic-markers [] + close-parens-probabilities [0.772 0.206 0.021 0.001] + silent-instruction-probability 0}}] + (let [markers (cond-> + (conj epigenetic-markers :instruction) + track-instruction-maps (conj :uuid :random-insertion))] (zipmap markers (map (fn [marker] (case marker @@ -65,6 +68,8 @@ :silent (if (< (lrand) silent-instruction-probability) true false) + :random-insertion true + :uuid (java.util.UUID/randomUUID) )) markers)))))