diff --git a/src/propeller/genome.cljc b/src/propeller/genome.cljc index 114f9e1..8d9d98b 100755 --- a/src/propeller/genome.cljc +++ b/src/propeller/genome.cljc @@ -7,16 +7,14 @@ They hold the genetic material for an `individual`. In the initial population, w (defn make-random-plushy "Creates and returns a new plushy made of random instructions." - [{:keys [instructions max-initial-plushy-size bmx? bmx-gap-probability]}] - (if bmx? - (repeatedly - (rand-int max-initial-plushy-size) - #(if (< (rand) bmx-gap-probability) - :gap - (utils/random-instruction instructions))) - (repeatedly - (rand-int max-initial-plushy-size) - #(utils/random-instruction instructions)))) + [{:keys [instructions max-initial-plushy-size bmx? bmx-gene-length-limit]}] + (let [plushy (repeatedly (rand-int max-initial-plushy-size) + #(utils/random-instruction instructions))] + (if bmx? + (-> plushy + (utils/fill-empty-genes instructions) + (utils/enforce-gene-length-limit bmx-gene-length-limit)) + plushy))) (defn plushy->push-internal [plushy argmap] diff --git a/src/propeller/problems/boolean/mul3.cljc b/src/propeller/problems/boolean/mul3.cljc index c46d9f4..5605f43 100644 --- a/src/propeller/problems/boolean/mul3.cljc +++ b/src/propeller/problems/boolean/mul3.cljc @@ -313,7 +313,7 @@ :single-thread-mode false :bmx? true :bmx-exchange-rate 0.5 - :bmx-gap-probability 0.1 + :bmx-gene-length-limit 10 :bmx-gap-change-probability 0.01 :bmx-complementary? true} (apply hash-map (map #(if (string? %) (read-string %) %) args))))) diff --git a/src/propeller/session.cljc b/src/propeller/session.cljc index 9632388..732a838 100755 --- a/src/propeller/session.cljc +++ b/src/propeller/session.cljc @@ -57,7 +57,9 @@ #_(genome/plushy->push (genome/make-random-plushy {:instructions (instructions/get-stack-instructions #{:float :integer :exec :boolean}) - :bmx-gap-probability 20})) + :max-initial-plushy-size 100 + :bmx? true + :bmx-gene-length-limit 10})) ;; One way of running a genetic programming problem defined in the project ;; is to require the problem's namespace and then call `gp/gp` using the diff --git a/src/propeller/utils.cljc b/src/propeller/utils.cljc index 0988d82..cce6b62 100755 --- a/src/propeller/utils.cljc +++ b/src/propeller/utils.cljc @@ -209,3 +209,25 @@ (random-instruction instructions) gene)) (extract-genes plushy))))) + +(defn break-up + "A utility function for bmx-related genetic operators. Returns the provided + :gap-free plushy with gaps randomly inserted to ensure that no gene is longer + than the provided limit." + [gene limit] + (if (> (count gene) limit) + (let [i (inc (rand-int (dec (count gene))))] + (concat (break-up (take i gene) limit) + [:gap] + (break-up (drop i gene) limit))) + gene)) + +(defn enforce-gene-length-limit + "A utility function for bmx-related genetic operators. Returns the provided + plushy with any over-length genes broken into non-empty pieces, recursively + until all genes obey the limit." + [plushy limit] + (flatten (interpose :gap + (mapv (fn [gene] + (break-up gene limit)) + (extract-genes plushy))))) diff --git a/src/propeller/variation.cljc b/src/propeller/variation.cljc index 33851d5..1a6da17 100644 --- a/src/propeller/variation.cljc +++ b/src/propeller/variation.cljc @@ -244,7 +244,8 @@ The function `new-individual` returns a new individual produced by selection and (-> (bmx plushy1 plushy2 bmx-exchange-rate max-distance argmap) (uniform-gap-addition gap-change-prob) (uniform-gap-deletion gap-change-prob) - (utils/fill-empty-genes (:instructions argmap)))) + (utils/fill-empty-genes (:instructions argmap)) + (utils/enforce-gene-length-limit (:bmx-gene-length-limit argmap)))) ; :umad ;; uniform mutation by addition and deletion, see uniform-deletion for the ;; adjustment that makes this size neutral on average @@ -276,7 +277,8 @@ The function `new-individual` returns a new individual produced by selection and (uniform-gap-deletion gap-change-prob) (uniform-addition (:instructions argmap) umad-rate) (uniform-deletion umad-rate) - (utils/fill-empty-genes (:instructions argmap)))) + (utils/fill-empty-genes (:instructions argmap)) + (utils/enforce-gene-length-limit (:bmx-gene-length-limit argmap)))) ; :rumad ;; responsive UMAD, uses a deletion rate computed from the actual ;; number of additions made