Skip to content

Commit b846388

Browse files
committed
adding sum type for temperature instead of using constant values
1 parent 600a5e6 commit b846388

File tree

2 files changed

+26
-24
lines changed

2 files changed

+26
-24
lines changed

core/src/main/scala/aima/core/search/local/SimulatedAnnealingSearch.scala

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,23 @@ package time {
4646
*/
4747
object 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

core/src/test/scala/aima/core/search/local/SimulatedAnnealingSearchSpec.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package aima.core.search.local
22

3+
import aima.core.search.local.SimulatedAnnealingSearch.{OverTimeStepLimit, Temperature, TemperatureResult}
34
import aima.core.search.local.time.TimeStep
45
import org.specs2.mutable.Specification
56

@@ -20,16 +21,22 @@ class SimulatedAnnealingSearchSpec extends Specification {
2021
}
2122

2223
"lower limit check" in {
23-
schedule(TimeStep.start) must beCloseTo(19.1d within 3.significantFigures)
24+
schedule(TimeStep.start) match {
25+
case Temperature(t) => t must beCloseTo(19.1d within 3.significantFigures)
26+
case other => ko(other.toString)
27+
}
2428
}
2529

2630
"upper limit check" in {
27-
increment(TimeStep.start, 98).map(schedule(_)) must beSuccessfulTry(
28-
beCloseTo(0.232d within 3.significantFigures))
31+
increment(TimeStep.start, 98).map(schedule(_)) match {
32+
case Success(Temperature(t)) => t must beCloseTo(0.232d within 3.significantFigures)
33+
case other => ko(other.toString)
34+
}
35+
2936
}
3037

3138
"over limit check" in {
32-
increment(TimeStep.start, 99).map(schedule(_)) must beSuccessfulTry(beCloseTo(0.00d within 3.significantFigures))
39+
increment(TimeStep.start, 99).map(schedule(_)) must beSuccessfulTry[TemperatureResult](OverTimeStepLimit)
3340
}
3441
}
3542

0 commit comments

Comments
 (0)