Bending bits...

Bytes and Words...

Simple GA in Clojure

Based on the implementation presented by Lee Spector.

(defn new-individual
                  "Function used for creating a new individual"
                  [genome-length]
                  {:genome (vec (repeatedly genome-length #(rand-int 2))) :fitness 0}
                  )
            (defn fitness-function 
                [genome, target]
                (Math/abs (- (reduce + genome) target))
            )

            (defn calculate-fitness
              [population, target]
              (letfn [(fitness-function-helper 
                  [individual, target]
                  (assoc individual :fitness (fitness-function (individual :genome) target))
              )]
                      (map (fn [individual] (#(fitness-function-helper individual target))) population)
              )

          )
          (defn get-best-individual [population]
                        (letfn [(better [i1 i2]
                                                (< (i1 :fitness) (i2 :fitness))
                                        )]
                                (first (sort better population))
                        )
        )
        (defn crossover
              [first-individual, second-individual, crossover-rate, target]
              (let [new-genome (mapv (fn [i1,i2] (let [crossover-probability (rand)]
                                              (cond
                                                  (<= crossover-probability crossover-rate) i1
                                                  :else i2
                                              )
                                          )
                                  ) 
                  (first-individual :genome) (second-individual :genome)
                      )]
                  {:genome new-genome :fitness (fitness-function new-genome target)}
              )

      )
      (defn mate-individuals [population, population-size, crossover-rate, target, tournament-size]
            (letfn [(tournament-selection [population, population-size, tournament-size, target]
                                    (loop [steps 0 new-population ()]
                                            (if (< steps tournament-size)
                                                    (recur (inc steps) (conj new-population (nth population ((comp rand-int -) population-size 2))))
                                                    (get-best-individual (calculate-fitness new-population target))
                                            )
                                    )
                    )]
                                    (loop [steps 0 new-population ()]
                                            (if (< steps population-size)
                                                    (let [i1 (tournament-selection population population-size tournament-size target)]
                                                            (let [i2 (tournament-selection population population-size tournament-size target)]
                                                                    (let [offs (crossover i1 i2 crossover-rate target)]
                                                                            (recur (inc steps) (conj new-population offs))
                                                                    )
                                                            )
                                                    )
                                                    new-population
                                            )
                                    )
            )
    )
    (defn mutate-population [population, population-size, genome-length, target]

                          (letfn [(mutate [individual, genome-length, target]
                                          (let [new-genome (assoc (individual :genome) (rand-int genome-length) (rand-int 2))]
                  {:genome new-genome :fitness (fitness-function new-genome target)}
                          )
                                  )]
                                  (loop [steps 0 new-population ()]
          (if (< steps population-size)
                  (recur (inc steps) (conj new-population (mutate (nth population steps) genome-length target)))
                  new-population
          )

      )

                          )


  )
  (defn evolve [population-size, genome-length, target, number-of-generations, crossover-rate, tournament-size]
(loop [generation 0 population (calculate-fitness (repeatedly population-size #(new-individual genome-length)) target) best {}]
        (if (and (< generation number-of-generations) (not= 0 (best :fitness)))


                                (let [offsprings (mate-individuals population population-size crossover-rate target tournament-size)]
                                        (let [new-population (mutate-population offsprings population-size genome-length target)]
                                                (let [best-individual (get-best-individual new-population)]
                                                        (do
                                                                (printf "Generation %s -> best individual %s%n" generation best-individual)

                                                                (recur (inc generation) new-population best-individual)
                                                        )
                                                )
                                        )

                                )
                                best
        )

)
)

(println (evolve 100 100 1 100 0.3 10))