; your code goes here
(in-package :cl-user)
(defpackage :simulated-annealing
(:use :cl))
(in-package :simulated-annealing)
(defclass solution ()
((queens :initarg :queens :accessor solution-queens)
(energy :initarg :energy :initform 0 :accessor solution-energy)
(size :initarg :size :accessor solution-size)))
(defparameter default-size 5)
(defun make-solution (&optional (size default-size))
(loop
with solution = (make-instance 'solution
:size size
:queens (loop for i from 0 below size collect i))
repeat size
do (tweak-solution solution)
finally (return solution)))
(defun tweak-solution (solution)
(loop
with size = (solution-size solution)
with queens = (solution-queens solution)
with x = (random size)
for y = (random size)
while (= x y)
finally (rotatef (nth x queens)
(nth y queens))))
(defun print-solution (solution &optional (stream *standard-output*))
(loop
with size = (solution-size solution)
for queen in (solution-queens solution)
do (loop for y from 0 below size
do (format stream "~a " (if (= y queen) "Q" ".")))
(terpri stream)))
(defun compute-energy (solution)
(flet ((make-board ()
(loop
with size = (solution-size solution)
with board = (make-array (list size size) :initial-element 0)
for x from 0 below size
for y in (solution-queens solution)
do (setf (aref board x y) 1)
finally (return board))))
(loop
with board = (make-board)
with size = (solution-size solution)
with conflicts = 0
with diags = '((-1 -1) (1 1) (-1 1) (1 -1))
for x from 0 below size
for y in (solution-queens solution)
do (loop for delta in diags
do (loop
with tempx = x
with tempy = y
do
(incf tempx (first delta))
(incf tempy (second delta))
until (or (< tempx 0)
(< tempy 0)
(>= tempx size)
(>= tempy size))
do (incf conflicts (aref board tempx tempy))))
finally (setf (slot-value solution 'energy) conflicts))))
(defun copy-solution (solution)
(let ((copy (make-instance 'solution :size (solution-size solution)) ))
(with-slots (queens energy) copy
(setf queens (copy-list (solution-queens solution)))
(setf energy (solution-energy solution)))
copy))
(defun main ()
(let ((current (make-solution))
(working nil)
(best (make-instance 'solution :energy 100)))
(compute-energy current)
(setf working (copy-solution current))
(loop
with alpha = 0.99
with final-temperature = 0.5
with steps-per-change = 100
for temperature = 30.0 then (* temperature alpha)
while (> temperature final-temperature)
do
(loop for i from 0 below steps-per-change
with use-new = nil
do
(tweak-solution working)
(compute-energy working)
(if (<= (solution-energy working) (solution-energy best))
(setf use-new t)
(let ((test (random 1.0))
(delta (- (solution-energy working)
(solution-energy current))))
(when (> (exp (/ (- delta) temperature)) test)
(setf use-new t))))
(if use-new
(progn
(setf use-new nil)
(setf current (copy-solution working))
(when (< (solution-energy current)
(solution-energy best))
(setf best (copy-solution current))))
(setf working (copy-solution current)))))
(print-solution best)))
(main)