使用遗传算法解决旅行商问题

旅行商问题,简单地说,即一个商人要找一条通过n个城市的最短巡回。

开始产生的随机路径:

TSPstart

遗传算法的其中一个结果

TSPresult

对个体采用字符编码的方式。如[3,1,4,2,5]表示开始从第3个结点开始,然后第1个结点,依次而行。为了避免产生非法解,对个体进行变因时,实质是交换个体中的两个数字的位置。例如[4,1,3,2,5]即为一个新的个体。变异时,例如对于个体a=[3,1,4,2,5],b=[5,2,4,1,3],如果选择a的第2和第3个位置和b的第2和第3个位置进行交换。首先作出在a中而不在b[2,4]中的字符,即c=[3,1,5],然后在c中第1个空位插入b[2,4],即生成新的个休[3,2,4,1,5],从而不会有重复字符,避免了非法解的产生。

ContractedBlock.gif ExpandedBlockStart.gif Code
'''
Created on 2009-10-29
@author: Administrator
'''
import sys, random
from math import sqrt
from pickle import *

PIL_SUPPORT 
= None
try:
   
from PIL import Image, ImageDraw, ImageFont
   PIL_SUPPORT 
= True
except:
   PIL_SUPPORT 
= False 

def cartesian_matrix(coords):
   
""" A distance matrix """
   matrix 
= {}
   
for i, (x1, y1) in enumerate(coords):
      
for j, (x2, y2) in enumerate(coords):
         dx, dy 
= x1 - x2, y1 - y2
         dist 
= sqrt(dx * dx + dy * dy)
         matrix[i, j] 
= dist
   
return matrix 

def tour_length(matrix, tour):
   
""" Returns the total length of the tour """
   total 
= 0
   num_cities 
= len(tour)
   
for i in range(num_cities):
      j 
= (i + 1% num_cities
      city_i 
= tour[i]
      city_j 
= tour[j]
      total 
+= matrix[city_i, city_j]
   
return total

def write_tour_to_img(coords, tour, img_file):
   
""" The function to plot the graph """
   padding 
= 20
   coords 
= [(x + padding, y + padding) for (x, y) in coords]
   maxx, maxy 
= 0, 0
   
for x, y in coords:
      maxx 
= max(x, maxx)
      maxy 
= max(y, maxy)
   maxx 
+= padding
   maxy 
+= padding
   img 
= Image.new("RGB", (int(maxx), int(maxy)), color=(255255255))
   font 
= ImageFont.load_default()
   d 
= ImageDraw.Draw(img);
   num_cities 
= len(tour)
   
for i in range(num_cities):
      j 
= (i + 1% num_cities
      city_i 
= tour[i]
      city_j 
= tour[j]
      x1, y1 
= coords[city_i]
      x2, y2 
= coords[city_j]
      d.line((int(x1), int(y1), int(x2), int(y2)), fill
=(0, 0, 0))
      d.text((int(x1) 
+ 7, int(y1) - 5), str(i), font=font, fill=(323232)) 

   
for x, y in coords:
      x, y 
= int(x), int(y)
      d.ellipse((x 
- 5, y - 5, x + 5, y + 5), outline=(0, 0, 0), fill=(196196196))
   
del d
   img.save(img_file, 
"PNG")
   
print "The plot was saved into the %s file." % (img_file,)  

cm 
= []
coords 
= [] 

def eval_func(chromosome):
   
""" The evaluation function """
   
global cm
   
return tour_length(cm, chromosome) 

def cities_random(cities, xmax=800, ymax=600):
   
""" get random cities/positions """
   coords 
= []
   
for i in xrange(cities):
      x 
= random.randint(0, xmax)
      y 
= random.randint(0, ymax)
      coords.append((float(x), float(y)))
   
return coords

#Individuals
class Individual:
    score 
= 0
    length 
= 30
    seperator 
= ' '
    
def __init__(self, chromosome=None, length=30):
        self.chromosome 
= chromosome or self._makechromosome()
        self.length 
= length
        self.score 
= 0  # set during evaluation  

    
def _makechromosome(self):
        
"makes a chromosome from randomly selected alleles."
        chromosome 
= []
        lst 
= [i for i in xrange(self.length)]
        
for i in xrange(self.length):
            choice 
= random.choice(lst)
            lst.remove(choice)
            chromosome.append(choice)
        
return chromosome

    
def evaluate(self, optimum=None):
        self.score 
= eval_func(self.chromosome)
        
    
def crossover(self, other):
        left, right 
= self._pickpivots()         
        p1 
= Individual()
        p2 
= Individual()   
        c1 
= [ c for c in self.chromosome if c not in other.chromosome[left:right + 1]]
        p1.chromosome 
= c1[:left] + other.chromosome[left:right + 1+ c1[left:]
        c2 
= [ c for c in other.chromosome if c not in self.chromosome[left:right + 1]]
        p2.chromosome 
= c2[:left] + self.chromosome[left:right + 1+ c2[left:]
        
return p1, p2

    
def mutate(self):
        
"swap two element"
        left, right 
= self._pickpivots()      
        temp 
= self.chromosome[left]
        self.chromosome[left] 
= self.chromosome[right]
        self.chromosome[right] 
= temp   

    
def _pickpivots(self):
        left 
= random.randint(0, self.length - 2)
        right 
= random.randint(left, self.length - 1)
        
return left, right    

    
def __repr__(self):
        
"returns string representation of self"
        
return '<%s chromosome="%s" score=%s>' % \
               (self.
__class__.__name__,
                self.seperator.join(map(str, self.chromosome)), self.score)  

    
def copy(self):
        twin 
= self.__class__(self.chromosome[:])
        twin.score 
= self.score
        
return twin
     

    
def __cmp__(self, other):
        
return cmp(self.score, other.score)

class Environment:
    size 
= 0
    
def __init__(self, population=None, size=100, maxgenerations=1000, newindividualrate=0.6,
                 crossover_rate
=0.90, mutation_rate=0.1):       
        self.size 
= size      
        self.population 
= self._makepopulation()       
        self.maxgenerations 
= maxgenerations
        self.newindividualrate 
= newindividualrate  
        self.crossover_rate 
= crossover_rate
        self.mutation_rate 
= mutation_rate       
        
for individual in self.population:           
            individual.evaluate()      
        self.generation 
= 0
        self.minscore 
= sys.maxint       
        self.minindividual 
= None
        
#self._printpopulation()
        if PIL_SUPPORT:
            write_tour_to_img(coords, self.population[0].chromosome, 
"TSPstart.png")
        
else:
            
print "No PIL detected,can not plot the graph"

    
def _makepopulation(self):
        
return [Individual() for i in range(0, self.size)]

    
def run(self):
        
for i in range(1, self.maxgenerations + 1):
            
print "Generation no:" + str(i)
            
for j in range(0, self.size):
                self.population[j].evaluate()
                curscore 
= self.population[j].score
                
if curscore < self.minscore:
                    self.minscore 
= curscore
                    self.minindividual 
= self.population[j]           
            
print "Best individual:", self.minindividual
            
if random.random() < self.crossover_rate:                            
                children 
= []               
                newindividual 
= int(self.newindividualrate * self.size / 2)                               
                
for i in range(0, newindividual):
                    selected1 
= self._selectrank()                   
                    selected2 
= self._selectrank()                   
                    parent1 
= self.population[selected1]
                    parent2 
= self.population[selected2]
                    child1, child2 
= parent1.crossover(parent2)
                    child1.evaluate()
                    child2.evaluate()
                    children.append(child1)
                    children.append(child2)
                
for i in range(0, newindividual):
                    
#replce with child                   
                    totalscore = 0
                    
for k in range(0, self.size):
                        totalscore 
+= self.population[k].score
                    randscore 
= random.random()                   
                    addscore 
= 0
                    
for j in range(0, self.size):
                        addscore 
+= (self.population[j].score / totalscore)                       
                        
if addscore >= randscore:                                                                                 
                            self.population[j] 
= children[i]
                            
break               
            
if random.random() < self.mutation_rate:               
                selected 
= self._select()
                self.population[selected].mutate()
        
#end loop
        for i in range(0, self.size):
                self.population[i].evaluate()
                curscore 
= self.population[i].score
                
if curscore < self.minscore:
                    self.minscore 
= curscore
                    self.minindividual 
= self.population[i]
        
print "Result."
        
print self.minindividual
        
#self._printpopulation()

    
def _select(self):       
        totalscore 
= 0
        
for i in range(0, self.size):
            totalscore 
+= self.population[i].score
        randscore 
= random.random()*(self.size - 1)
        addscore 
= 0
        selected 
= 0
        
for i in range(0, self.size):
            addscore 
+= (1 - self.population[i].score / totalscore)
            
if addscore >= randscore:
                selected 
= i
                
break
        
return selected

    
def _selectrank(self, choosebest=0.9):
        self.population.sort()
        
if random.random() < choosebest:
            
return random.randint(0, self.size * self.newindividualrate)
        
else:
            
return random.randint(self.size * self.newindividualrate, self.size - 1)

    
def _printpopulation(self):
        
for i in range(0, self.size):
            
print "Individual ", i, self.population[i]      

def main_run():   
    
global cm, coords
    
#get cities's coords
    coords = [(553.0132.0), (167.0381.0), (395.051.0), (416.0101.0), (575.0351.0), (243.0347.0), (218.0415.0), (247.086.0), (404.0286.0), (209.0462.0), (23.0204.0), (54.0492.0), (350.0405.0), (689.078.0), (729.0543.0), (429.0371.0), (472.064.0), (316.0570.0), (297.0570.0), (261.0198.0), (559.0272.0), (684.0224.0), (13.0548.0), (146.093.0), (125.0558.0), (499.0414.0), (510.0503.0), (55.0234.0), (454.0144.0), (381.00.0)]

    cm 
= cartesian_matrix(coords)
    ev 
= Environment()
    ev.run()
    
if PIL_SUPPORT:
        write_tour_to_img(coords, ev.minindividual.chromosome, 
"TSPresult.png")
    
else:
        
print "No PIL detected,can not plot the graph"   
if __name__ == "__main__":   
    main_run()    

 

转载于:https://www.cnblogs.com/zgw21cn/archive/2009/11/07/1598249.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值