Skip to content

New #12295

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

New #12295

Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
  • Loading branch information
pre-commit-ci[bot] committed Oct 27, 2024
commit 613f482360dfb51322d8dae2c8bed5bf7ac8ca6b
4 changes: 3 additions & 1 deletion sorts/topological_sort.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

vertices: list[str] = ["a", "b", "c", "d", "e"]


# Perform topological sort on a DAG starting from the specified node
def topological_sort(start: str, visited: list[str], sort: list[str]) -> list[str]:
current = start
Expand All @@ -42,10 +43,11 @@ def topological_sort(start: str, visited: list[str], sort: list[str]) -> list[st
# Return sorted list
return sort


if __name__ == "__main__":
# Topological Sorting from node "a" (Returns the order in bottom up approach)
sort = topological_sort("a", [], [])

# Reversing the list to get the correct topological order (Top down approach)
sort.reverse()
sort.reverse()
print(sort)
43 changes: 28 additions & 15 deletions travelling_salesman_problem.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
""" Travelling Salesman Problem (TSP) """
"""Travelling Salesman Problem (TSP)"""

import itertools
import math


class InvalidGraphError(ValueError):
"""Custom error for invalid graph inputs."""


def euclidean_distance(point1: list[float], point2: list[float]) -> float:
"""
Calculate the Euclidean distance between two points in 2D space.
Expand All @@ -28,6 +30,7 @@ def euclidean_distance(point1: list[float], point2: list[float]) -> float:
except TypeError:
raise ValueError("Invalid input: Points must be numerical coordinates")


def validate_graph(graph_points: dict[str, list[float]]) -> None:
"""
Validate the input graph to ensure it has valid nodes and coordinates.
Expand All @@ -41,12 +44,12 @@ def validate_graph(graph_points: dict[str, list[float]]) -> None:
Traceback (most recent call last):
...
InvalidGraphError: Each node must have a valid 2D coordinate [x, y]

>>> validate_graph([10, 20]) # Invalid input type
Traceback (most recent call last):
...
InvalidGraphError: Graph must be a dictionary with node names and coordinates

>>> validate_graph({"A": [10, 20], "B": [30, 21], "C": [15]}) # Missing coordinate
Traceback (most recent call last):
...
Expand All @@ -66,6 +69,7 @@ def validate_graph(graph_points: dict[str, list[float]]) -> None:
):
raise InvalidGraphError("Each node must have a valid 2D coordinate [x, y]")


# TSP in Brute Force Approach
def travelling_salesman_brute_force(
graph_points: dict[str, list[float]],
Expand All @@ -89,7 +93,7 @@ def travelling_salesman_brute_force(
raise InvalidGraphError("Graph must have at least two nodes")

min_path = [] # List that stores shortest path
min_distance = float("inf") # Initialize minimum distance to infinity
min_distance = float("inf") # Initialize minimum distance to infinity

start_node = nodes[0]
other_nodes = nodes[1:]
Expand All @@ -111,6 +115,7 @@ def travelling_salesman_brute_force(

return min_path, min_distance


# TSP in Dynamic Programming approach
def travelling_salesman_dynamic_programming(
graph_points: dict[str, list[float]],
Expand All @@ -127,20 +132,26 @@ def travelling_salesman_dynamic_programming(
"""
validate_graph(graph_points)

n = len(graph_points) # Extracting the node names (keys)
n = len(graph_points) # Extracting the node names (keys)

# There shoukd be atleast 2 nodes for a valid TSP
if n < 2:
raise InvalidGraphError("Graph must have at least two nodes")

nodes = list(graph_points.keys()) # Extracting the node names (keys)
nodes = list(graph_points.keys()) # Extracting the node names (keys)

# Initialize distance matrix with float values
dist = [[euclidean_distance(graph_points[nodes[i]], graph_points[nodes[j]]) for j in range(n)] for i in range(n)]

# Initialize a dynamic programming table with infinity
dist = [
[
euclidean_distance(graph_points[nodes[i]], graph_points[nodes[j]])
for j in range(n)
]
for i in range(n)
]

# Initialize a dynamic programming table with infinity
dp = [[float("inf")] * n for _ in range(1 << n)]
dp[1][0] = 0 # Only visited node is the starting point at node 0
dp[1][0] = 0 # Only visited node is the starting point at node 0

# Iterate through all masks of visited nodes
for mask in range(1 << n):
Expand All @@ -149,14 +160,16 @@ def travelling_salesman_dynamic_programming(
if mask & (1 << u):
# Traverse nodes 'v' such that u->v
for v in range(n):
if mask & (1 << v) == 0: # If v is not visited
next_mask = mask | (1 << v) # Upodate mask to include 'v'
if mask & (1 << v) == 0: # If v is not visited
next_mask = mask | (1 << v) # Upodate mask to include 'v'
# Update dynamic programming table with minimum distance
dp[next_mask][v] = min(dp[next_mask][v], dp[mask][u] + dist[u][v])
dp[next_mask][v] = min(
dp[next_mask][v], dp[mask][u] + dist[u][v]
)

final_mask = (1 << n) - 1
min_cost = float("inf")
end_node = -1 # Track the last node in the optimal path
end_node = -1 # Track the last node in the optimal path

for u in range(1, n):
if min_cost > dp[final_mask][u] + dist[u][0]:
Expand All @@ -175,7 +188,7 @@ def travelling_salesman_dynamic_programming(
== dp[mask ^ (1 << end_node)][u] + dist[u][end_node]
):
mask ^= 1 << end_node # Update mask to remove end node
end_node = u # Set the previous node as end node
end_node = u # Set the previous node as end node
break

path.append(nodes[0]) # Bottom-up Order
Expand Down
Loading