Generating a map/graph for a traveling salesmanproblem (Python)

Question:

I’m going to create a couple of algorithms to solve a traveling salesman problem, but first I’m to create a graph/map with n nodes and every node has a border. (if n=100 then it’s 99 borders). Distance between each node should be a random number from 1 to 5.

(I’m doing this in python)
My first thought was for each node to have a list (final map will then be lists within a list) with distances to the other nodes.
If 10 nodes, then each list will have 9 integers in them.

After generating the first list, the other lists would inherit the corresponding distances.
Ex.

A: [5, 5, 3]
B: [5]
C: [5]
D: [3]

Next step is to generate a new list with one less element, place it behind the value that’s already there and do the same as above (rest of the nodes will inherit the corresponding distances). This would be done recursively until all the lists are full.

Final list will look something list this:

[[5, 5, 3],
 [5, 2, 1],
 [5, 2, 4],
 [3, 1, 4]

Could someone give me a hint of how I should go about implementing this?
Or maybe if there’s a much simpler method. Thanks!

import random

def main():
    graph_map = []
    max_nodes = 10
    i = 0
    generate_map(graph_map, max_nodes, i)
    print graph_map

def generate_map(graph_map, max, i):
    temp_list = []
    for j in range(max-1):
        temp_list.append(random.randint(1, 5))
    if i > 0:
        graph_map[i].append(temp_list)
    else:
        graph_map.append(temp_list)

    for j in range(1, max):
        graph_map.append([temp_list[j-1]])





if __name__ == '__main__':
    main()

This code will give me the start I wanted with sample output:

[[4, 5, 5, 2, 1, 3, 3, 3, 2], [4], [5], [5], [2], [1], [3], [3], [3], [2]]
Asked By: user2750342

||

Answers:

I think you are overthinking this. Simply make two loops, first fills in distances from the current node, and inner loop copies them to the destination ones

import random

def main():
    graph_map = []
    max_nodes = 5
    for i in range(max_nodes):
        graph_map.append([])
    for i in range(max_nodes):
        for j in range(max_nodes-1-i):
            d = random.randint(1,5)
            graph_map[i].append(d) 
            graph_map[i+j+1].append(d)    

    print graph_map

if __name__ == '__main__':
    main()

Prints

[[5, 2, 1, 5], 
 [5, 1, 2, 3], 
 [2, 1, 4, 5], 
 [1, 2, 4, 5], 
 [5, 3, 5, 5]]

There are at least few issues with this approach:

  1. Your data representation is quite weird, it would be much easier for later algorithm implementation to actually store the n x n distance matrix, where D[i,j] would mean “distance from i’th city to the j’th”, which would simply have D[i,i]=0. Your representation means something like “distance from the i’th city to the j’th city if j<i and to the j-1‘th otherwise
  2. This (in most cases) will not generate a planar graph, what it means is that you cannot place n points on the plane with such distances between them. So data is quite “unrealistic”, and many heuristic TSP solutions assume planar data (or triangle inequality). A better way to do this would be to generate random n points on the plane and then calculate their distances.

Example for planar generator on [0,m]^2:

import math
import random 
n=5
m=100
def dist(a,b):
    return math.sqrt( (a[0]-b[0])**2 + (a[1]-b[1])**2 )
points = [ [random.randint(0,m), random.randint(0,m) ] for i in range(n) ]
D = [ [ dist( points[i], points[j] ) for i in range(n) ] for j in range(n) ]
print points
print D
Answered By: lejlot

If your nodes(points) are presented as a 2D-NumPy array with coordinates, you may use this code.
The function "calculate_distance" returns the distance between points.
The function create_graph receives a 2D-NumPy array as an argument and returns a graph of distances between that point as a 2D-NumPy array.
import math

def calculate_distance(nodes_list):
    total_distance = 0
    for i in range(len(nodes_list)-1):
        current_distance = math.sqrt(
            (nodes_list[i][0] - nodes_list[i+1][0]) ** 2 + ((nodes_list[i][1] - nodes_list[i+1][1]) ** 2)
        )
        total_distance += current_distance
    return total_distance


def create_graph(nodes_list):
    graph = np.zeros(shape=(n, n))
    for i in range(n):
        for j in range(n):
            graph[i, j] = calculate_distance(np.array([nodes_list[i], nodes_list[j]]))
    return graph


nodes_array_distance = calculate_distance(nodes_array)
print(f"Distance = {nodes_array_distance}")
print(f"Your graph: n {create_graph(nodes_array)}")

In the resul you get something like that:

Answered By: Dmytro
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.