Skip to content

Commit ebe8751

Browse files
committed
Added CSA with variance control
1 parent 7fb9ae3 commit ebe8751

File tree

3 files changed

+65
-47
lines changed

3 files changed

+65
-47
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ packageDescription := "DynaML is a scala library/repl for implementing and worki
1212
"which can be extended easily to implement advanced models for small and large scale applications.\n\n"+
1313
"But the library can also be used as an educational/research tool for data analysis."
1414

15-
val mainVersion = "v1.4-beta.34"
15+
val mainVersion = "v1.4-beta.35"
1616

1717
val dataDirectory = settingKey[File]("The directory holding the data files for running example scripts")
1818

dynaml-core/src/main/scala-2.11/io/github/mandar2812/dynaml/DynaMLPipe.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ object DynaMLPipe {
599599
.setGridSize(grid)
600600
.setStepSize(step)
601601
.setLogScale(false)
602+
.setVariant(CoupledSimulatedAnnealing.MwVC)
602603
}
603604

604605
gs.optimize(startingState, Map("tolerance" -> "0.0001",

dynaml-core/src/main/scala-2.11/io/github/mandar2812/dynaml/optimization/CoupledSimulatedAnnealing.scala

Lines changed: 63 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ under the License.
1818
* */
1919
package io.github.mandar2812.dynaml.optimization
2020

21+
import breeze.linalg.DenseVector
2122
import breeze.stats.distributions.CauchyDistribution
23+
import io.github.mandar2812.dynaml.utils
24+
2225
import scala.util.Random
2326

2427
/**
@@ -32,7 +35,12 @@ class CoupledSimulatedAnnealing[M <: GloballyOptimizable](model: M)
3235

3336
protected var MAX_ITERATIONS: Int = 10
3437

35-
var variant = CoupledSimulatedAnnealing.MuSA
38+
protected var variant = CoupledSimulatedAnnealing.MuSA
39+
40+
def setVariant(v: String) = {
41+
variant = v
42+
this
43+
}
3644

3745
def setMaxIterations(m: Int) = {
3846
MAX_ITERATIONS = m
@@ -56,8 +64,7 @@ class CoupledSimulatedAnnealing[M <: GloballyOptimizable](model: M)
5664

5765
var iTemp = 1.0
5866

59-
protected def acceptance(energy: Double, oldEnergy: Double, coupling: Double, temperature: Double) =
60-
CoupledSimulatedAnnealing.acceptanceProbability(variant)(energy, oldEnergy, coupling, temperature)
67+
var alpha = 0.05
6168

6269
protected val mutate = (config: Map[String, Double], temperature: Double) => {
6370
logger.info("Mutating configuration: "+GlobalOptimizer.prettyPrint(config))
@@ -74,19 +81,27 @@ class CoupledSimulatedAnnealing[M <: GloballyOptimizable](model: M)
7481
def mutationTemperature(initialTemp: Double)(k: Int): Double =
7582
initialTemp/k.toDouble
7683

77-
def gamma(landscape: Seq[Double])(accTemp: Double): Double =
78-
CoupledSimulatedAnnealing.couplingFactor(variant)(landscape, accTemp)
79-
8084
override def optimize(initialConfig: Map[String, Double],
8185
options: Map[String, String] = Map()) = {
8286

83-
//create grid
87+
logger.info("-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-")
88+
logger.info("Coupled Simulated Annealing: "+CoupledSimulatedAnnealing.algorithm(variant))
89+
logger.info("-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-")
8490

8591
var accTemp = iTemp
8692
var mutTemp = iTemp
8793

94+
//Calculate desired variance
95+
val sigmaD = CoupledSimulatedAnnealing.varianceDesired(variant)(math.pow(gridsize, initialConfig.size).toInt)
96+
8897
val initialEnergyLandscape = getEnergyLandscape(initialConfig, options)
8998

99+
100+
val gamma_init = CoupledSimulatedAnnealing.couplingFactor(variant)(initialEnergyLandscape.map(_._1), accTemp)
101+
var acceptanceProbs: List[Double] = initialEnergyLandscape.map(c => {
102+
CoupledSimulatedAnnealing.acceptanceProbability(variant)(c._1, c._1, gamma_init, accTemp)
103+
})
104+
90105
def CSATRec(eLandscape: List[(Double, Map[String, Double])], it: Int): List[(Double, Map[String, Double])] =
91106
it match {
92107
case 0 => eLandscape
@@ -97,60 +112,47 @@ class CoupledSimulatedAnnealing[M <: GloballyOptimizable](model: M)
97112
//the generating distribution
98113
//and accept using the acceptance distribution
99114
mutTemp = mutationTemperature(iTemp)(it)
100-
accTemp = acceptanceTemperature(iTemp)(it)
115+
accTemp = variant match {
116+
case CoupledSimulatedAnnealing.MwVC =>
117+
val (_,variance) = utils.getStats(acceptanceProbs.map(DenseVector(_)))
118+
119+
if (variance(0) < sigmaD)
120+
accTemp * (1-alpha)
121+
else accTemp * (1+alpha)
122+
case _ =>
123+
acceptanceTemperature(iTemp)(it)
124+
}
101125

102126
val maxEnergy = eLandscape.map(_._1).max
103127

104-
val couplingFactor = gamma(eLandscape.map(t => t._1 - maxEnergy))(accTemp)
128+
val couplingFactor = CoupledSimulatedAnnealing.couplingFactor(variant)(
129+
eLandscape.map(t => t._1 - maxEnergy),
130+
accTemp)
131+
105132
//Now mutate each solution and accept/reject
106133
//according to the acceptance probability
107-
val newEnergyLandscape = eLandscape.map((config) => {
134+
val (newEnergyLandscape,probabilities) = eLandscape.map((config) => {
108135
//mutate this config
109136
val new_config = mutate(config._2, mutTemp)
110137
val new_energy = system.energy(new_config, options)
138+
139+
//Calculate the acceptance probability
140+
val acceptanceProbability = CoupledSimulatedAnnealing.acceptanceProbability(variant)(
141+
new_energy - maxEnergy, config._1,
142+
couplingFactor, accTemp)
143+
111144
val ans = if(new_energy < config._1) {
112-
(new_energy, new_config)
145+
((new_energy, new_config), acceptanceProbability)
113146
} else {
114-
val acc = acceptance(new_energy - maxEnergy, config._1, couplingFactor, accTemp)
115-
if(Random.nextDouble <= acc) (new_energy, new_config) else config
147+
if(Random.nextDouble <= acceptanceProbability) ((new_energy, new_config), acceptanceProbability)
148+
else (config, acceptanceProbability)
116149
}
117150
ans
118-
})
151+
}).unzip
152+
acceptanceProbs = probabilities
119153
CSATRec(newEnergyLandscape, it-1)
120154
}
121155

122-
123-
/*cfor(1)(iteration => iteration <= MAX_ITERATIONS, iteration => iteration + 1)( iteration => {
124-
logger.info("**************************")
125-
logger.info("CSA Iteration: "+iteration)
126-
//mutate each element of the grid with
127-
//the generating distribution
128-
//and accept using the acceptance distribution
129-
mutTemp = mutationTemperature(iTemp)(iteration)
130-
accTemp = acceptanceTemperature(iTemp)(iteration)
131-
132-
val maxEnergy = currentEnergyLandscape.map(_._1).max
133-
134-
val couplingFactor = gamma(currentEnergyLandscape.map(t => t._1 - maxEnergy))(accTemp)
135-
//Now mutate each solution and accept/reject
136-
//according to the acceptance probability
137-
val newEnergyLandscape = currentEnergyLandscape.map((config) => {
138-
//mutate this config
139-
val new_config = mutate(config._2, mutTemp)
140-
val new_energy = system.energy(new_config, options)
141-
val ans = if(new_energy < config._1) {
142-
(new_energy, new_config)
143-
} else {
144-
val acc = acceptance(new_energy - maxEnergy, config._1, couplingFactor, accTemp)
145-
if(Random.nextDouble <= acc) (new_energy, new_config) else config
146-
}
147-
ans
148-
})
149-
150-
currentEnergyLandscape = newEnergyLandscape
151-
152-
})*/
153-
154156
val landscape = CSATRec(initialEnergyLandscape, MAX_ITERATIONS).toMap
155157
val optimum = landscape.keys.min
156158

@@ -171,6 +173,13 @@ object CoupledSimulatedAnnealing {
171173
val MwVC = "CSA-MwVC"
172174
val SA = "SA"
173175

176+
def algorithm(variant: String): String = variant match {
177+
case MuSA => "Multi-state Simulated Annealing"
178+
case BA => "Blind Acceptance"
179+
case M => "Modified"
180+
case MwVC => "Modified with Variance Control"
181+
}
182+
174183
def couplingFactor(variant: String)(landscape: Seq[Double], Tacc: Double): Double = {
175184
if(variant == MuSA || variant == BA)
176185
landscape.map(energy => math.exp(-1.0*energy/Tacc)).sum
@@ -189,5 +198,13 @@ object CoupledSimulatedAnnealing {
189198
else gamma/(1.0 + math.exp((energy - oldEnergy)/temperature))
190199
}
191200

201+
def varianceDesired(variant: String)(m: Int):Double = {
202+
if(variant == MuSA || variant == BA)
203+
0.99
204+
else
205+
0.99*(m-1)/math.pow(m, 2.0)
206+
207+
}
208+
192209

193210
}

0 commit comments

Comments
 (0)