Skip to content

Commit

Permalink
Refactored the evolve method, extracted the common part into a function
Browse files Browse the repository at this point in the history
and removed the unused function parameters for sequence generation
functon case
  • Loading branch information
btezergil-atlassian committed Jan 28, 2024
1 parent ee2ed7c commit e79d5f8
Showing 1 changed file with 31 additions and 16 deletions.
47 changes: 31 additions & 16 deletions src/nature/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
[nature.population-operators :as po]
[nature.monitors :as monitors]))

(defn evolution-loop
"Evolution loop that is used commonly by sequence generator function and random generation from allele set."
[initial-population generations population-size binary-operators unary-operators options]
(let [solutions (max 1 (:solutions options))
carry-over (max 1 (:carry-over options))
monitors (:monitors options)]
(loop [population initial-population
current-generation 0]
(when monitors (monitors/apply-monitors monitors population current-generation))
(if (>= current-generation generations)
(take solutions (sort-by :fitness-score #(> %1 %2) population))
(recur (po/advance-generation population population-size binary-operators unary-operators {:carry-over carry-over}) (inc current-generation))))))

(defn evolve
"Create and evolve a population under the specified conditions until a termination criteria is reached
`allele-set` is a collection of legal genome values
Expand All @@ -13,26 +26,28 @@
`binary-operators` is a collection of partial functions accepting and returning 1 or more individuals
`unary-operators` is a collection of partial functions accepting and returning exactly 1 individual
`options` an optional map of pre-specified keywords to values that further tune the behavior of nature.
Current examples follow:
`:carry-over` an integer representing the top n individuals to be carried over between each generation. Default is 1
`:solutions` an integer representing the top n individuals to return after evolution completes. Default is 1
`:monitors` a sequence of functions, assumed to be side-effectful, to be executed against `population` and `current-genration` for run-time stats. Default is nil"
Current examples follow:
`:carry-over` an integer representing the top n individuals to be carried over between each generation. Default is 1
`:solutions` an integer representing the top n individuals to return after evolution completes. Default is 1
`:monitors` a sequence of functions, assumed to be side-effectful, to be executed against `population` and `current-genration` for run-time stats. Default is nil"
([allele-set genome-length population-size generations fitness-function binary-operators unary-operators]
(evolve allele-set genome-length population-size generations fitness-function binary-operators unary-operators {:solutions 1, :carry-over 1}))

([allele-set genome-length population-size generations fitness-function binary-operators unary-operators options] ;; TODO - Curry the genetic operators one more level, so the fitness-function can be pressed in
{:pre [(and (every? coll? [allele-set binary-operators unary-operators])
(every? int? [genome-length population-size generations])
(fn? fitness-function))]}
(let [solutions (max 1 (:solutions options))
carry-over (max 1 (:carry-over options))
monitors (:monitors options)
sequence-generator-function (:generator options)]
(loop [population (if (some? sequence-generator-function)
(io/build-population population-size sequence-generator-function fitness-function)
(io/build-population population-size allele-set genome-length fitness-function))
current-generation 0]
(when monitors (monitors/apply-monitors monitors population current-generation))
(if (>= current-generation generations)
(take solutions (sort-by :fitness-score #(> %1 %2) population))
(recur (po/advance-generation population population-size binary-operators unary-operators {:carry-over carry-over}) (inc current-generation)))))))
(evolution-loop (io/build-population population-size allele-set genome-length fitness-function) population-size generations binary-operators unary-operators options)))

(defn evolve-with-sequence-generator
"Same with evolve method, but takes a sequence generator function instead of an allele set and genome length.
This method uses the sequence generator function to generate sequences for the initial population."
([generator-function population-size generations fitness-function binary-operators unary-operators]
(evolve-with-sequence-generator generator-function population-size generations fitness-function binary-operators unary-operators {:solutions 1, :carry-over 1}))

([generator-function population-size generations fitness-function binary-operators unary-operators options]
{:pre [(and (every? coll? [binary-operators unary-operators])
(every? int? [population-size generations])
(every? fn? [generator-function fitness-function]))]}
(evolution-loop (io/build-population population-size generator-function fitness-function) population-size generations binary-operators unary-operators options)))

0 comments on commit e79d5f8

Please sign in to comment.