File:Ant Colony Algorihm applied to the Travelling Salesman Problem.gif
Page contents not supported in other languages.
Tools
Actions
General
In other projects
Appearance
Ant_Colony_Algorihm_applied_to_the_Travelling_Salesman_Problem.gif (640 × 480 pixels, file size: 207 KB, MIME type: image/gif, looped, 88 frames, 44 s)
This is a file from the Wikimedia Commons. Information from its description page there is shown below. Commons is a freely licensed media file repository. You can help. |
Summary
DescriptionAnt Colony Algorihm applied to the Travelling Salesman Problem.gif |
English: Visualization of the ant colony algorithm applied to the travelling salesman problem. Each iteration of the algorithm corresponds to the voyage of a single ant. The green lines represent the paths chosen by the ant, while the blue lines are the possible paths it may take at each given point. The opacity of each blue line is related to the likelihood of choosing the corresponding path (which is proportional to the path’s pheromone level and inversely proportional to its distance). When the ant finishes its voyage, the pheromone levels of each path are represented in red, with those with the highest pheromone levels in a darker tone. |
Date | |
Source | Own work |
Author | Rodrigo Castro Freibott |
Licensing
I, the copyright holder of this work, hereby publish it under the following license:
This file is licensed under the Creative Commons Attribution-Share Alike 4.0 International license.
- You are free:
- to share – to copy, distribute and transmit the work
- to remix – to adapt the work
- Under the following conditions:
- attribution – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- share alike – If you remix, transform, or build upon the material, you must distribute your contributions under the same or compatible license as the original.
This program, written in Python (using the Matplotlib and NumPy libraries), will generate each frame of the animation, and join them together using ImageMagick.
Python code
import matplotlib.pyplot as plt
from math import *
import random
import numpy as np
import os
import matplotlib.patheffects as pe
# Define the number of nodes and their coordinates
num_nodes = 5 # Number of nodes
nodes_x = [1, 3, 2, 5, 4] # Array of size 'num_nodes'
nodes_y = [4, 1.5, 3, 2, 3.5]
# Obtain the distance of each edge
edges_distances = np.matrix([[0.0 for i in range(num_nodes)] for j in range(num_nodes)])
for i in range(num_nodes):
for j in range(i, num_nodes):
edges_distances[i, j] = sqrt((nodes_x[j] - nodes_x[i])**2 + (nodes_y[j] - nodes_y[i])**2)
edges_distances[j, i] = edges_distances[i, j]
# Define the parameters of the algorithm
alpha = 1
beta = 1
# Define the initial pheromone level of each edge
edges_pheromones = np.matrix([[1 for i in range(num_nodes)] for j in range(num_nodes)])
# Define the number of ants (number of iterations of the algorithm)
num_ants = 6
nodes = set(range(num_nodes))
optimal_length = np.matrix.sum(edges_distances) # Initialized as a very high number
optimal_voyage = []
images = []
img_index = 0
filename = "TSP_AntColony_Animation_WithOptimum_BetterCode"
def capture(nframes=1):
"""
Generates 'nframes' images of the current PyPlot figure
"""
for i in range(nframes):
global img_index # Necessary to change its value
image = filename + "_" + str(img_index) + ".png"
img_index += 1
plt.savefig(image)
images.append(image)
def lighten_color(color, amount=0.5):
"""
Function from StackOverflow (https://stackoverflow.com/questions/37765197/darken-or-lighten-a-color-in-matplotlib)
Returns a lighter (amount<1) or darker (amount>1) version of the color
Examples:
>> lighten_color('green', 0.3)
# Returns a color that is like the 'green' color, but lighter
>> lighten_color('green', 1.3)
# Returns a color that is like the 'green' color, but darker
"""
import matplotlib.colors as mc
import colorsys
try:
c = mc.cnames[color]
except:
c = color
c = colorsys.rgb_to_hls(*mc.to_rgb(c))
return colorsys.hls_to_rgb(c[0], 1 - amount * (1 - c[1]), c[2])
ax_main = plt.gca()
ax_optimum = plt.gcf().add_axes((0.05, 0.05, 0.25, 0.25))
ax_optimum.set_xticks([])
ax_optimum.set_yticks([])
ax_optimum.set_title("Current optimum",
path_effects=[pe.withStroke(linewidth=2, foreground='white')])
for ant in range(num_ants):
# Clear main axes
ax_main.clear()
ax_main.scatter(nodes_x, nodes_y, c='black')
ax_main.set_title("Iteration " + str(ant) + " of " + str(num_ants - 1))
current_node = 0
length = 0 # Sum of the distances of the voyage
voyage = [0] # Sequence of nodes
while len(nodes.difference(set(voyage))) > 0: # While there are unvisited nodes
unvisited_nodes = []
probabilities = [] # Likelihood of going to each unvisited node
summation = 0
# Calculate the probabilities to go to each node
for node in nodes.difference(set(voyage)):
unvisited_nodes.append(node)
probability = (edges_pheromones[current_node, node]**alpha) *\
(1/edges_distances[current_node, node]**beta)
probabilities.append(probability)
summation += probability
probabilities = np.array(probabilities)
probabilities = probabilities / summation # Normalized probabilities
# Draw each possible path, indicating its probability with transparency
lines = []
for i in range(len(nodes.difference(set(voyage)))):
lines.append(ax_main.plot([nodes_x[current_node], nodes_x[unvisited_nodes[i]]],
[nodes_y[current_node], nodes_y[unvisited_nodes[i]]],
c='blue', alpha=probabilities[i])[0])
capture()
# Choose a node among the unvisited nodes
chosen_node = random.choices(unvisited_nodes, weights=probabilities, k=1)[0]
# Mark the chosen path as green, and delete the others
for i in range(len(nodes.difference(set(voyage)))):
if unvisited_nodes[i] == chosen_node:
lines[i].set_color('green')
lines[i].set_alpha(1)
else:
lines[i].remove()
capture()
# Update edges, length and current node
edges_pheromones[current_node, chosen_node] += 1 # Update the chosen path
edges_pheromones[chosen_node, current_node] += 1 # We want it to be a symmetrical matrix
length += edges_distances[current_node, chosen_node] # Update the length of the voyage
current_node = chosen_node
voyage.append(current_node)
# Include the path of return from the last node to 0
edges_pheromones[current_node, 0] += 1
edges_pheromones[0, current_node] += 1
length += edges_distances[current_node, 0]
voyage.append(0)
# Update optimal length and voyage
if length < optimal_length:
optimal_length = length
optimal_voyage = voyage
ax_optimum.clear()
ax_optimum.scatter(nodes_x, nodes_y, c='black')
ax_optimum.set_xticks([])
ax_optimum.set_yticks([])
ax_optimum.set_title("Current optimum - " + str(round(optimal_length, 2)) + "m",
path_effects=[pe.withStroke(linewidth=2, foreground='white')])
for i in range(len(optimal_voyage) - 1):
ax_optimum.plot([nodes_x[optimal_voyage[i]], nodes_x[optimal_voyage[i + 1]]],
[nodes_y[optimal_voyage[i]], nodes_y[optimal_voyage[i + 1]]],
c=lighten_color('green'))
# Draw the last path, resulting in a full view of the voyage
ax_main.plot([nodes_x[current_node], nodes_x[0]],
[nodes_y[current_node], nodes_y[0]],
c='green')
ax_main.set_title("Iteration " + str(ant) + " of " + str(num_ants - 1)
+ " - " + str(round(length, 2)) + "m")
capture(3)
# Clear main axes
ax_main.clear()
ax_main.scatter(nodes_x, nodes_y, c='black')
ax_main.set_title("Iteration " + str(ant) + " of " + str(num_ants - 1) + " - resulting pheromone levels")
# Show pheromone level of each path
for i in range(num_nodes):
for j in range(i, num_nodes):
ax_main.plot([nodes_x[i], nodes_x[j]],
[nodes_y[i], nodes_y[j]],
c=lighten_color('red', edges_pheromones[i, j] / num_ants))
capture(3)
# Create a final image
plt.gcf().clf()
ax = plt.gca()
ax.scatter(nodes_x, nodes_y, c='black')
ax.set_title("PROGRAM FINISHED - RESULTING OPTIMUM - " + str(round(optimal_length, 2)) + "m")
for i in range(len(optimal_voyage) - 1):
ax.plot([nodes_x[optimal_voyage[i]], nodes_x[optimal_voyage[i + 1]]],
[nodes_y[optimal_voyage[i]], nodes_y[optimal_voyage[i + 1]]],
c=lighten_color('green'))
capture(4)
# Create the animation using ImageMagick
fps = 2
os.system('convert -delay {} +dither +remap -layers Optimize {} "{}"'.
format(100//fps, ' '.join(['"' + img + '"' for img in images]), filename + '.gif'))
# Delete the images
for img in images:
if os.path.exists(img):
os.remove(img)
Items portrayed in this file
depicts
some value
15 April 2022
image/gif
a59d315f531c4d82bb4e8c776ce02a13978ecdae
211,913 byte
44 second
480 pixel
640 pixel
File history
Click on a date/time to view the file as it appeared at that time.
Date/Time | Thumbnail | Dimensions | User | Comment | |
---|---|---|---|---|---|
current | 20:22, 15 April 2022 | 640 × 480 (207 KB) | Rodrigo Castro Freibott | Uploaded while editing "Ant colony optimization algorithms" on en.wikipedia.org |
File usage
The following page uses this file: