@@ -46,19 +46,23 @@ package time {
4646 */
4747object SimulatedAnnealingSearch {
4848
49- type Schedule = TimeStep => Double
49+ sealed trait TemperatureResult
50+ final case class Temperature private [SimulatedAnnealingSearch ] (double : Double ) extends TemperatureResult
51+ case object OverTimeStepLimit extends TemperatureResult
52+
53+ type Schedule = TimeStep => TemperatureResult
5054
5155 object BasicSchedule {
5256
5357 val k : Int = 20
5458 val lam : Double = 0.045
5559 val limit : Int = 100
5660
57- val schedule : Schedule = { t : TimeStep => // time steps 1 to infinity (Integer.Max)
61+ val schedule : Schedule = { t : TimeStep =>
5862 if (t.value < limit) {
59- k * math.exp((- 1 ) * lam * t.value)
63+ Temperature ( k * math.exp((- 1 ) * lam * t.value) )
6064 } else {
61- 0.0
65+ OverTimeStepLimit
6266 }
6367 }
6468 }
@@ -68,20 +72,11 @@ object SimulatedAnnealingSearch {
6872 def apply (stateToValue : State => Double , problem : Problem ): Try [State ] =
6973 apply(stateToValue, problem, BasicSchedule .schedule)
7074
71- def apply (stateToValue : State => Double , problem : Problem , sched : Schedule ): Try [State ] = {
75+ def apply (stateToValue : State => Double , problem : Problem , schedule : Schedule ): Try [State ] = {
7276 val random = new Random ()
7377
7478 def makeNode (state : State ): StateValueNode = StateValueNode (state, stateToValue(state))
7579
76- def schedule (t : TimeStep ): Try [Double ] = {
77- val T = sched(t)
78- if (T < 0.0d ) {
79- Failure (new IllegalArgumentException (" Configured schedule returns negative temperatures: t=" + t + " , T=" + T )) // TODO: seems like smart constructor of Temperature type
80- } else {
81- Success (T )
82- }
83- }
84-
8580 def randomlySelectSuccessor (current : StateValueNode ): StateValueNode = {
8681 // Default successor to current, so that in the case we reach a dead-end
8782 // state i.e. one without reversible actions we will return something.
@@ -101,13 +96,13 @@ object SimulatedAnnealingSearch {
10196
10297 def recurse (current : StateValueNode , t : TimeStep ): Try [State ] = {
10398 import time .TimeStep .Implicits ._
99+ val T = schedule(t)
104100
105101 for {
106- temperatureT <- schedule(t)
107- result <- {
108- if (temperatureT == 0.0d ) { // TODO: don't think this is good practice to compare 0.0 double against constant, could be really close but not exact
109- Success (current)
110- } else {
102+ result <- T match {
103+ case OverTimeStepLimit => Success (current)
104+
105+ case Temperature (temperatureT) =>
111106 val randomSuccessor = randomlySelectSuccessor(current)
112107 val DeltaE = randomSuccessor.value - current.value
113108 lazy val acceptDownHillMove = math.exp(DeltaE / temperatureT) > random.nextDouble()
@@ -122,7 +117,7 @@ object SimulatedAnnealingSearch {
122117
123118 val nextTimeStep : Try [TimeStep ] = t.step
124119 nextTimeStep.flatMap(recurse(nextNode, _))
125- }
120+
126121 }
127122 } yield result
128123
0 commit comments