11from  tkinter  import  * 
2+ from  tkinter  import  messagebox 
23import  sys 
34import  os .path 
45sys .path .append (os .path .join (os .path .dirname (__file__ ), '..' ))
56from  search  import  * 
7+ import  utils 
68import  numpy  as  np 
79
810distances  =  {}
@@ -56,6 +58,7 @@ def __init__(self, root, all_cities):
5658        self .calculate_canvas_size ()
5759        self .button_text  =  StringVar ()
5860        self .button_text .set ("Start" )
61+         self .algo_var  =  StringVar ()
5962        self .all_cities  =  all_cities 
6063        self .frame_select_cities  =  Frame (self .root )
6164        self .frame_select_cities .grid (row = 1 )
@@ -85,9 +88,18 @@ def create_buttons(self):
8588        """ Create start and quit button """ 
8689
8790        Button (self .frame_select_cities , textvariable = self .button_text ,
88-                command = self .run_traveling_salesman ).grid (row = 3 , column = 4 , sticky = E  +  W )
89-         Button (self .frame_select_cities , text = 'Quit' , command = self .root .destroy ).grid (
90-             row = 3 , column = 5 , sticky = E  +  W )
91+                command = self .run_traveling_salesman ).grid (row = 5 , column = 4 , sticky = E  +  W )
92+         Button (self .frame_select_cities , text = 'Quit' , command = self .on_closing ).grid (
93+             row = 5 , column = 5 , sticky = E  +  W )
94+ 
95+     def  create_dropdown_menu (self ):
96+         """ Create dropdown menu for algorithm selection """ 
97+ 
98+         choices  =  {'Simulated Annealing' , 'Genetic Algorithm' , 'Hill Climbing' }
99+         self .algo_var .set ('Simulated Annealing' )
100+         dropdown_menu  =  OptionMenu (self .frame_select_cities , self .algo_var , * choices )
101+         dropdown_menu .grid (row = 4 , column = 4 , columnspan = 2 , sticky = E  +  W )
102+         dropdown_menu .config (width = 19 )
91103
92104    def  run_traveling_salesman (self ):
93105        """ Choose selected citites """ 
@@ -151,13 +163,30 @@ def create_canvas(self, problem):
151163                            variable = self .speed , label = "Speed ----> " , showvalue = 0 , font = "Times 11" ,
152164                            relief = "sunken" , cursor = "gumby" )
153165        speed_scale .grid (row = 1 , columnspan = 5 , sticky = N  +  S  +  E  +  W )
154-         self .temperature  =  IntVar ()
155-         temperature_scale  =  Scale (self .frame_canvas , from_ = 100 , to = 0 , orient = HORIZONTAL ,
166+         
167+         if  self .algo_var .get () ==  'Simulated Annealing' :
168+             self .temperature  =  IntVar ()
169+             temperature_scale  =  Scale (self .frame_canvas , from_ = 100 , to = 0 , orient = HORIZONTAL ,
156170                                  length = 200 , variable = self .temperature , label = "Temperature ---->" ,
157171                                  font = "Times 11" , relief = "sunken" , showvalue = 0 , cursor = "gumby" )
158- 
159-         temperature_scale .grid (row = 1 , column = 5 , columnspan = 5 , sticky = N  +  S  +  E  +  W )
160-         self .simulated_annealing_with_tunable_T (problem , map_canvas )
172+             temperature_scale .grid (row = 1 , column = 5 , columnspan = 5 , sticky = N  +  S  +  E  +  W )
173+             self .simulated_annealing_with_tunable_T (problem , map_canvas )
174+         elif  self .algo_var .get () ==  'Genetic Algorithm' :
175+             self .mutation_rate  =  DoubleVar ()
176+             self .mutation_rate .set (0.05 )
177+             mutation_rate_scale  =  Scale (self .frame_canvas , from_ = 0 , to = 1 , orient = HORIZONTAL , 
178+                                         length = 200 , variable = self .mutation_rate , label = 'Mutation Rate ---->' ,
179+                                         font = 'Times 11' , relief = 'sunken' , showvalue = 0 , cursor = 'gumby' , resolution = 0.001 )
180+             mutation_rate_scale .grid (row = 1 , column = 5 , columnspan = 5 , sticky = 'nsew' )
181+             self .genetic_algorithm (problem , map_canvas )
182+         elif  self .algo_var .get () ==  'Hill Climbing' :
183+             self .no_of_neighbors  =  IntVar ()
184+             self .no_of_neighbors .set (100 )
185+             no_of_neighbors_scale  =  Scale (self .frame_canvas , from_ = 10 , to = 1000 , orient = HORIZONTAL , 
186+                                           length = 200 , variable = self .no_of_neighbors , label = 'Number of neighbors ---->' ,
187+                                           font = 'Times 11' ,relief = 'sunken' , showvalue = 0 , cursor = 'gumby' )
188+             no_of_neighbors_scale .grid (row = 1 , column = 5 , columnspan = 5 , sticky = 'nsew' )
189+             self .hill_climbing (problem , map_canvas )
161190
162191    def  exp_schedule (k = 100 , lam = 0.03 , limit = 1000 ):
163192        """ One possible schedule function for simulated annealing """ 
@@ -191,6 +220,102 @@ def simulated_annealing_with_tunable_T(self, problem, map_canvas, schedule=exp_s
191220                map_canvas .update ()
192221                map_canvas .after (self .speed .get ())
193222
223+     def  genetic_algorithm (self , problem , map_canvas ):
224+         """ Genetic Algorithm modified for the given problem """ 
225+ 
226+         def  init_population (pop_number , gene_pool , state_length ):
227+             """ initialize population """ 
228+ 
229+             population  =  []
230+             for  i  in  range (pop_number ):
231+                 population .append (utils .shuffled (gene_pool ))
232+             return  population 
233+ 
234+         def  recombine (state_a , state_b ):
235+             """ recombine two problem states """ 
236+ 
237+             start  =  random .randint (0 , len (state_a ) -  1 )
238+             end  =  random .randint (start  +  1 , len (state_a ))
239+             new_state  =  state_a [start :end ]
240+             for  city  in  state_b :
241+                 if  city  not  in   new_state :
242+                     new_state .append (city )
243+             return  new_state 
244+ 
245+         def  mutate (state , mutation_rate ):
246+             """ mutate problem states """ 
247+ 
248+             if  random .uniform (0 , 1 ) <  mutation_rate :
249+                 sample  =  random .sample (range (len (state )), 2 )
250+                 state [sample [0 ]], state [sample [1 ]] =  state [sample [1 ]], state [sample [0 ]]
251+             return  state 
252+ 
253+         def  fitness_fn (state ):
254+             """ calculate fitness of a particular state """ 
255+             
256+             fitness  =  problem .value (state )
257+             return  int ((5600  +  fitness ) **  2 )
258+ 
259+         current  =  Node (problem .initial )
260+         population  =  init_population (100 , current .state , len (current .state ))
261+         all_time_best  =  current .state 
262+         while (1 ):
263+             population  =  [mutate (recombine (* select (2 , population , fitness_fn )), self .mutation_rate .get ()) for  i  in  range (len (population ))]
264+             current_best  =  utils .argmax (population , key = fitness_fn )
265+             if  fitness_fn (current_best ) >  fitness_fn (all_time_best ):
266+                 all_time_best  =  current_best 
267+                 self .cost .set ("Cost = "  +  str ('%0.3f'  %  (- 1  *  problem .value (all_time_best ))))
268+             map_canvas .delete ('poly' )
269+             points  =  []
270+             for  city  in  current_best :
271+                 points .append (self .frame_locations [city ][0 ])
272+                 points .append (self .frame_locations [city ][1 ])
273+             map_canvas .create_polygon (points , outline = 'red' , width = 1 , fill = '' , tag = 'poly' )
274+             best_points  =  []
275+             for  city  in  all_time_best :
276+                 best_points .append (self .frame_locations [city ][0 ])
277+                 best_points .append (self .frame_locations [city ][1 ])
278+             map_canvas .create_polygon (best_points , outline = 'red' , width = 3 , fill = '' , tag = 'poly' )
279+             map_canvas .update ()
280+             map_canvas .after (self .speed .get ())
281+ 
282+     def  hill_climbing (self , problem , map_canvas ):
283+         """ hill climbing where number of neighbors is taken as user input """ 
284+ 
285+         def  find_neighbors (state , number_of_neighbors = 100 ):
286+             """ finds neighbors using two_opt method """ 
287+ 
288+             neighbors  =  []
289+             for  i  in  range (number_of_neighbors ):
290+                 new_state  =  problem .two_opt (state )
291+                 neighbors .append (Node (new_state ))
292+                 state  =  new_state 
293+             return  neighbors 
294+ 
295+         current  =  Node (problem .initial )
296+         while (1 ):
297+             neighbors  =  find_neighbors (current .state , self .no_of_neighbors .get ())
298+             neighbor  =  utils .argmax_random_tie (neighbors , key = lambda  node : problem .value (node .state ))
299+             map_canvas .delete ('poly' )
300+             points  =  []
301+             for  city  in  current .state :
302+                 points .append (self .frame_locations [city ][0 ])
303+                 points .append (self .frame_locations [city ][1 ])
304+             map_canvas .create_polygon (points , outline = 'red' , width = 3 , fill = '' , tag = 'poly' )
305+             neighbor_points  =  []
306+             for  city  in  neighbor .state :
307+                 neighbor_points .append (self .frame_locations [city ][0 ])
308+                 neighbor_points .append (self .frame_locations [city ][1 ])
309+             map_canvas .create_polygon (neighbor_points , outline = 'red' , width = 1 , fill = '' , tag = 'poly' )
310+             map_canvas .update ()
311+             map_canvas .after (self .speed .get ())
312+             if  problem .value (neighbor .state ) >  problem .value (current .state ):
313+                 current .state  =  neighbor .state 
314+                 self .cost .set ("Cost = "  +  str ('%0.3f'  %  (- 1  *  problem .value (current .state ))))
315+ 
316+     def  on_closing (self ):
317+         if  messagebox .askokcancel ('Quit' , 'Do you want to quit?' ):
318+             self .root .destroy ()
194319
195320def  main ():
196321    all_cities  =  []
@@ -212,6 +337,8 @@ def main():
212337    cities_selection_panel  =  TSP_Gui (root , all_cities )
213338    cities_selection_panel .create_checkboxes ()
214339    cities_selection_panel .create_buttons ()
340+     cities_selection_panel .create_dropdown_menu ()
341+     root .protocol ('WM_DELETE_WINDOW' , cities_selection_panel .on_closing )
215342    root .mainloop ()
216343
217344
0 commit comments