#!/usr/bin/env python # coding: utf-8 # # Simulated annealing & Traveling Salesman problem # Simulated annealing is a technique which uses Matropolis to find a global minimum of a # function of many variables. It is typically used for large scale problems, especially ones where a desired global minimum is hidden among many poorer local minima. # # The class of problems known as NP-complete problems, whose computation time for an exact solution increases with N as $\exp(const.× N)$, were basically unsolvable until recently. # # Only in 1983, the method was invented ( Kirkpatrick, S., Gelatt, C.D., and Vecchi, M.P. 1983, Science, vol. \textbf{220}, 671-680 (1083).) which effectively solved most of these problems for practical purposes. # # Simulated annealing does not "solve" them exactly, but in most cases we just need reasonable good solution even if its not the one with exacly the lowest total energy. # # The archtype example of NP-complete problems, the traveling salesman problem, is easy to solve with this method. # # Other very important application is in designing complex integrated circuits: The arrangement of several hundred thousand circuit elements on a tiny silicon substrate is optimized so as to minimize interference among their connecting wires. # # # The simulated annealing uses Metropolis algorithm with slowly decreasing temperature in order that system relaxes into its "ground state". # # The steps consis of # - Pick initial configuration $X$ and an initial temperature # $T_0$. $T_0$ should be much higher than the changes in function $f$ # to be minimized when typical Monte Carlo step is taken. # - Loop through decreasing temperature $T_i$ # # - Equilibrate at $T_i$ using Metropolis with selected, allowed # elementary changes in the system. The system is equilibrated when # the rate of change of $f$ averaged over some number of Monte Carlo # steps is small. # - Measure the termal average of $f$. If $f$ does not decrease at # this temperature $T_i$ compared to previous temperature $T_{i-1}$, # exit the loop. # - Decrease $T_i$ to $T_{i+1}$. For example, reduces the effective temperature by 10\%. # # # The major difficulty (art) in implementation of the algorithm is that # there is no obvious analogy for the temperature T with respect to a # free parameter in the combinatorial problem. Furthermore, avoidance of # entrainment in local minima (quenching) is dependent on the "annealing # schedule", the choice of initial temperature, how many iterations are # performed at each temperature, and how much the temperature is # decremented at each step as cooling proceeds. # # ## The Traveling Salesman problem # # The seller visits $N$ cities ($i=0...N-1$) with given positions # $R_i$, returning finally to his or her city of origin. # **Each city** is to be **visited only once**, and the **route** is to be made **as # short as possible**. This problem belongs to a class known as # *NP-complete* problems, whose computation time for an exact solution # increases with N exponentially. # # The traveling salesman problem also belongs to a class of minimization # problems for which the objective function E has many local minima. In # practical cases, it is often enough to be able to choose from these a # minimum which, even if not absolute, cannot be significantly improved # upon. # # The annealing method manages to achieve this, while limiting its # calculations to scale as a small power of $N$. # # # As a problem in simulated annealing, the traveling salesman problem is handled # as follows: # # - 1 **Configuration:** The cities are numbered $i = 0. . .N-1$ and each has coordinate $R_i$. A configuration is a permutation of the number $0 ...N-1$, interpreted as the order in which the cities are visited. # - 2 **Rearrangements:** An efficient set of moves are: # - **(a)** A section of path is removed and then replaced with the same cities running in the opposite order; or # - **(b)** A section of path is removed and then replaced in between two cities on another, randomly chosen, part of the path. # # - 3 **Objective Function:** In the simplest form of the problem, $E$ is taken just as the total length of journey # # # The above two mentioned moves are hardest to implement. The following # plot explains them by an example # # # # # For details of implementation, check the example source code. # # In[16]: import scipy as scp from numpy import random from numpy import linalg from numba import jit ncity=100 # random coordinates in 2D for n-cities R = random.random((ncity,2)) # completely randomly positioned cities city = range(ncity) # we are visiting them in order in the array # In[3]: def Distance(R1,R2): return linalg.norm(R1-R2) # sqrt(x^2+y^2) def TotalDistance(city, R): dist=0 for i in range(len(city)-1): dist += Distance(R[city[i]],R[city[i+1]]) dist += Distance(R[city[-1]],R[city[0]]) return dist # In[17]: def Plot(city, R, dist): Pt = [R[city[i]] for i in range(len(city))] # list of [(x_i,y_i),...] coordinates Pt += [R[city[0]]] # add the very last/first city so that the curve is connected to itself Pt = array(Pt) title('Total distance='+str(dist)) plot(Pt[:,0],Pt[:,1],'o-') show() # In[18]: from pylab import * get_ipython().run_line_magic('matplotlib', 'inline') Plot(city,R, TotalDistance(city,R)) # In[19]: @jit(nopython=True) def FindASegment(R): nct = len(R) # number of cities while True: # Two cities n[0] and n[1] chosen at random n0 = int(nct*rand()) n1 = int((nct-1)*rand()) if n1>=n0 : n1 +=1 if n1n0 nn = (nct-(n1-n0+1)) # the rest of the cities if nn>=3 : break # the rest is big enough n2 = (n0-1) % nct # the city before first n3 = (n1+1) % nct # the city past second return (n0,n1,n2,n3) # In[20]: def CostReverse(R, city, n0, n1, n2, n3): # cost for reverse move de = Distance(R[city[n2]],R[city[n1]])+Distance(R[city[n0]],R[city[n3]]) de-= Distance(R[city[n2]],R[city[n0]])+Distance(R[city[n1]],R[city[n3]]) return de def Reverse(R, city, n0, n1, n2, n3): newcity = copy(city) for j in range(n1-n0+1): newcity[n0+j] = city[n1-j] return newcity # In[21]: @jit(nopython=True) def FindTSegment(R): (n0,n1,n2,n3) = FindASegment(R) nct = len(R) nn = nct - (n1-n0+1) # number for the rest of the cities n4 = (n1+1 + int(rand()*(nn-1)) ) % nct # city on the rest of the path n5 = (n4+1) % nct return (n0,n1,n2,n3,n4,n5) # In[22]: def CostTranspose(R, city, n0,n1,n2,n3,n4,n5): de = -Distance(R[city[n1]], R[city[n3]]) de-= Distance(R[city[n0]], R[city[n2]]) de-= Distance(R[city[n4]], R[city[n5]]) de+= Distance(R[city[n0]], R[city[n4]]) de+= Distance(R[city[n1]], R[city[n5]]) de+= Distance(R[city[n2]], R[city[n3]]) return de def Transpose(R, city, n0,n1,n2,n3,n4,n5): nct = len(R) newcity = [] # Segment in the range n0,...n1 for j in range(n1-n0+1): newcity.append( city[ (j+n0)%nct ] ) # is followed by segment n5...n2 for j in range( (n2-n5)%nct + 1): newcity.append( city[ (j+n5)%nct ] ) # is followed by segement n3..n4 for j in range( (n4-n3)%nct + 1): newcity.append( city[ (j+n3)%nct ] ) return newcity # In[25]: nn = FindTSegment(R) de = CostTranspose(R, city, *nn) # *nn = nn[0],nn[1],nn[2],nn[3],nn[4],nn[5], i.e., unpacking the list print(nn) print(de) r1 = Transpose(R, city, *nn) print(r1) # In[26]: def TravelingSalesman(city, R, maxSteps, maxAccepted, Tstart, fCool, maxTsteps, Preverse=0.5): T = Tstart dist = TotalDistance(city,R) for t in range(maxTsteps): accepted = 0 for i in range(maxSteps): if Preverse > rand(): # Try reverse nn = FindASegment(R) de = CostReverse(R, city, *nn) if de < 0 or exp(-de/T) > rand(): accepted += 1 dist += de city = Reverse(R, city, *nn) else: # here we transpose nn = FindTSegment(R) de = CostTranspose(R, city, *nn) if de < 0 or exp(-de/T) > rand(): accepted += 1 dist += de city = Transpose(R, city, *nn) if accepted > maxAccepted: break T *= fCool Plot(city, R, dist) print("T=%10.5f , distance=%10.5f acc.steps=%d" % (T, dist,accepted)) if accepted == 0: break Plot(city, R, dist) return city # In[28]: from numpy import random ncity = 100 maxSteps = 100*ncity maxAccepted = 10*ncity Tstart = 0.2 fCool = 0.9 maxTsteps = 100 random.seed(1) R = random.random((ncity,2)) city = range(ncity) ncity = TravelingSalesman(city, R, maxSteps, maxAccepted, Tstart, fCool, maxTsteps) # In[29]: Plot(ncity,R, TotalDistance(ncity,R)) # ## Homework # # 1) Implement Traveling Salesman problem. # # 2) Test traveling salesman problem and plot distance $d$ versus $N$, where $N$ is number of cities. What is the optimal curve distance? # In[ ]: