-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathMCMCMC.py
73 lines (61 loc) · 2.33 KB
/
MCMCMC.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import random
import math
import InitMutFit as imf
def InitializeTemps(maxtemp, mintemp, nchains):
# Uniform spacing here, but this can be done differently
# Log spacing is another option. In my experience this
# has led to overall higher swap acceptance rates.
tempstep = float(maxtemp - mintemp) / float(nchains - 1)
temps = [maxtemp - i * tempstep for i in range(nchains)]
return temps
def TrySwap(hotFit, coldFit, hotTemp, coldTemp):
# save computation and prevent overflow error
if hotFit < coldFit:
return True
prob = math.exp((coldFit - hotFit) * (1 / coldTemp - 1 / hotTemp))
if random.random() <= prob:
return True
else:
return False
def MCMCMC(steps, nchains, distMat, seed):
# hardcoded, but these can also be tuned!
SWAPSTEPS = 20
MAXTEMP = 5
MINTEMP = .001
random.seed(seed)
stops = distMat.shape[0]
# Initialize temperatures and chains
temps = InitializeTemps(MAXTEMP, MINTEMP, nchains)
chains = [imf.InitializeSol(stops) for x in range(nchains)]
fits = [imf.Fitness(chain, distMat) for chain in chains]
bestFit = min(fits)
bestSol = chains[fits.index(bestFit)]
fitHistory = []
for i in range(steps):
# swap chains
if i % SWAPSTEPS == 0:
for j in range(0, nchains - 1):
flag = TrySwap(fits[j], fits[j + 1], temps[j], temps[j + 1])
if flag:
chains[j], chains[j + 1] = chains[j + 1], chains[j]
fits[j], fits[j + 1] = fits[j + 1], fits[j]
# let each chain take a step
for j in range(nchains):
trialSol = imf.Mutate(chains[j])
trialFit = imf.Fitness(trialSol, distMat)
if trialFit < fits[j]:
# automatically accept to avoid overflow error
probAccept = 1
else:
probAccept = math.exp((fits[j] - trialFit) / temps[j])
if random.random() <= probAccept:
fits[j] = trialFit
chains[j] = trialSol
# update best solution if appropriate
if trialFit < bestFit:
bestFit = trialFit
bestSol = trialSol
if i % 1000 == 0:
print(bestFit)
fitHistory.append(bestFit)
return bestSol, fitHistory