nekomata / selfmod /gen-loop.lisp
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/nekomata
3b70664 verified
Raw
History Blame Contribute Delete
2.43 kB
(defpackage #:nekod.selfmod
(:use #:cl #:nekod)
(:export
#:generation-loop
#:mutate-spec
#:evolve
#:fitness
#:*generation*
#:*population*))
(in-package #:nekod.selfmod)
;; Generation loop: rewrite container definitions based on telemetry
(defvar *generation* 0)
(defvar *population* nil) ; list of container-specs
(defun mutate-spec (spec mutation-rate)
"Randomly mutate a container spec for evolutionary optimization."
(when (< (random 1.0) mutation-rate)
(let ((new-spec (copy-structure spec)))
;; Mutate restart policy
(setf (container-spec-restart-policy new-spec)
(nth (random 3) '(:always :on-failure :never)))
new-spec)))
(defun fitness (spec telemetry)
"Score a container spec based on runtime telemetry.
High uptime + low cpu + low memory = high fitness."
(declare (ignore spec))
(let ((uptime (getf telemetry :uptime 0.0))
(cpu (getf telemetry :cpu 0.5))
(memory (getf telemetry :memory 0.5)))
(- (* 0.6 uptime)
(* 0.2 cpu)
(* 0.2 memory))))
(defun evolve (population telemetry &optional (mutation-rate 0.1))
"One generation of evolutionary optimization.
Returns new population: survivors + mutants."
(incf *generation*)
(let* ((scored (mapcar (lambda (s) (cons s (fitness s telemetry))) population))
(sorted (sort scored #'> :key #'cdr))
(survivors (mapcar #'car (subseq sorted 0 (ceiling (length sorted) 2))))
(mutants (remove nil (mapcar (lambda (s) (mutate-spec s mutation-rate)) survivors))))
(append survivors mutants)))
(defun generation-loop (population telemetry-fn
&key (generations 10) (mutation-rate 0.1) (verbose t))
"Run N generations of evolutionary container optimization.
POPULATION: initial list of container-specs
TELEMETRY-FN: called each generation, returns plist (:uptime f :cpu f :memory f)
Returns the final optimized population."
(loop repeat generations
for pop = population then (evolve pop telemetry mutation-rate)
for telemetry = (funcall telemetry-fn)
do (when verbose
(format t "Gen ~a: ~a containers, best fitness ~,3f~%"
*generation*
(length pop)
(if pop (fitness (first pop) telemetry) 0.0)))
finally (return pop)))