Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 10 additions & 10 deletions src/Annealing/strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def nearest_neighbor(self, idx: int) -> list[int]:
return self.tour

def minimize(self) -> tuple[list[int], float]:
min_cost: float = float("inf")
cost: float = float("inf")
best_tour: list[int] = []
start: int
func: Callable[[int], list[int]]
Expand All @@ -234,13 +234,13 @@ def minimize(self) -> tuple[list[int], float]:
for func in (self.nearest_neighbor, self.radial_nn):
tour: list[int] = func(start)
tour_cost: float = self.calculate_tour_cost(tour)
if tour_cost < min_cost:
min_cost = tour_cost
if tour_cost < cost:
cost = tour_cost
best_tour = tour

self.tour = best_tour

return self.tour, min_cost
return self.tour, cost


class TwoOptStrategy(TSPStrategy):
Expand Down Expand Up @@ -312,9 +312,9 @@ def two_opt(self, iterations: int = 1000) -> None:

def minimize(self, iterations: int = 10_000) -> tuple[list[int], float]:
self.two_opt(iterations)
min_cost: float = self.calculate_tour_cost(self.tour)
cost: float = self.calculate_tour_cost(self.tour)

return self.tour, min_cost
return self.tour, cost


class ThreeOptStrategy(TSPStrategy):
Expand Down Expand Up @@ -421,9 +421,9 @@ def three_opt(self, iterations: int = 1000) -> None:

def minimize(self, iterations: int = 10_000) -> tuple[list[int], float]:
self.three_opt(iterations)
min_cost = self.calculate_tour_cost(self.tour)
cost: float = self.calculate_tour_cost(self.tour)

return self.tour, min_cost
return self.tour, cost


class ChristofidesStrategy(TSPStrategy):
Expand Down Expand Up @@ -457,7 +457,7 @@ def christofides_tsp(self) -> list[int]:
return tour

def minimize(self) -> tuple[list[int], float]:
self.tour = self.christofides_tsp()
cost = self.calculate_tour_cost(self.tour)
self.tour: list[int] = self.christofides_tsp()
cost: float = self.calculate_tour_cost(self.tour)

return self.tour, cost
41 changes: 41 additions & 0 deletions tests/unit/test_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def dm(coord: np.ndarray) -> np.ndarray:

@pytest.fixture
def tour_nn() -> list[int]:
"""Nearest neighbor tour."""
return [
8,
29,
Expand Down Expand Up @@ -93,6 +94,7 @@ def tour_nn() -> list[int]:

@pytest.fixture
def tour_2opt() -> list[int]:
"""Two opt tour."""
return [
0,
21,
Expand Down Expand Up @@ -149,6 +151,7 @@ def tour_2opt() -> list[int]:

@pytest.fixture
def tour_3opt() -> list[int]:
"""Three opt tour."""
return [
0,
6,
Expand Down Expand Up @@ -260,6 +263,44 @@ def tour_cfs() -> list[int]:
]


@pytest.fixture
def sample_coord() -> np.ndarray:
coordinates: np.ndarray = np.asarray([[1, 2], [3, 4], [5, 6]])
return coordinates


@pytest.fixture
def sample_graph(sample_coord: np.ndarray) -> nx.Graph:
graph: nx.Graph = nx.Graph()
graph.add_node(0, coordinate=sample_coord[0].tolist())
graph.add_node(1, coordinate=sample_coord[1].tolist())
graph.add_node(2, coordinate=sample_coord[2].tolist())
graph.add_edge(0, 1, weight=strategies._euclidean(sample_coord[0], sample_coord[1]))
graph.add_edge(0, 2, weight=strategies._euclidean(sample_coord[0], sample_coord[2]))
graph.add_edge(1, 2, weight=strategies._euclidean(sample_coord[1], sample_coord[2]))

return graph


def test_graph_build_from_coordinates(
sample_coord: np.ndarray,
sample_graph: nx.Graph,
) -> None:
"""Confirm graph is built correctly from coordinates."""
result: nx.Graph = strategies.build_graph(sample_coord)
assert nx.algorithms.is_isomorphic(result, sample_graph), (
"Graphs are not isomorphic"
)

# convert array to list for quick python object equality checks.
for i in result.nodes:
result.nodes[i]["coordinate"] = result.nodes[i]["coordinate"].tolist()

# NOTE: utility function from networkx only performs python object equivalence
# and numpy arrays must use np.all for complete equivalency.
assert nx.utils.graphs_equal(sample_graph, result), "Graphs are not equivalent."


def test_matrix_to_graph(dm: np.ndarray, coord: np.ndarray) -> None:
"""Confirm graphs constructed are equal."""
graph_a = strategies.build_graph_from_2d_distance_matrix(dm)
Expand Down
Loading