Resolved per commit checks and unresolved conversations

This commit is contained in:
Tarun Vishwakarma 2024-10-14 21:22:06 +05:30
parent a547676800
commit 15ba2808ad

View File

@ -5,7 +5,19 @@ class BlossomAuxData:
"""Class to hold auxiliary data during the blossom algorithm's execution.""" """Class to hold auxiliary data during the blossom algorithm's execution."""
def __init__(self, queue: deque, parent: list[int], base: list[int], def __init__(self, queue: deque, parent: list[int], base: list[int],
in_blossom: list[bool], match: list[int], in_queue: list[bool]): in_blossom: list[bool],
match: list[int], in_queue: list[bool]) -> None:
"""
Initializes the BlossomAuxData instance.
Args:
queue: A deque for BFS processing.
parent: List of parent vertices in the augmenting path.
base: List of base vertices for each vertex.
in_blossom: Boolean list indicating if a vertex is in a blossom.
match: List of matched vertices.
in_queue: Boolean list indicating if a vertex is in the queue.
"""
self.queue = queue self.queue = queue
self.parent = parent self.parent = parent
self.base = base self.base = base
@ -17,11 +29,22 @@ class BlossomAuxData:
class BlossomData: class BlossomData:
"""Class to encapsulate data related to a blossom in the graph.""" """Class to encapsulate data related to a blossom in the graph."""
def __init__(self, aux_data: BlossomAuxData, u: int, v: int, lca: int): def __init__(self, aux_data: BlossomAuxData,
vertex_u: int, vertex_v: int,
lowest_common_ancestor: int) -> None:
"""
Initializes the BlossomData instance.
Args:
aux_data: The auxiliary data related to the blossom.
vertex_u: One vertex in the blossom.
vertex_v: The other vertex in the blossom.
lowest_common_ancestor: The lowest common ancestor of vertex_u and vertex_v.
"""
self.aux_data = aux_data self.aux_data = aux_data
self.u = u self.vertex_u = vertex_u
self.v = v self.vertex_v = vertex_v
self.lca = lca self.lowest_common_ancestor = lowest_common_ancestor
class EdmondsBlossomAlgorithm: class EdmondsBlossomAlgorithm:
@ -40,7 +63,7 @@ class EdmondsBlossomAlgorithm:
A list of matched pairs in the form of a list of lists. A list of matched pairs in the form of a list of lists.
""" """
# Create an adjacency list for the graph # Create an adjacency list for the graph
graph = [[] for _ in range(vertex_count)] graph: list[list[int]] = [[] for _ in range(vertex_count)]
# Populate the graph with the edges # Populate the graph with the edges
for edge in edges: for edge in edges:
@ -49,11 +72,13 @@ class EdmondsBlossomAlgorithm:
graph[v].append(u) graph[v].append(u)
# All vertices are initially unmatched # All vertices are initially unmatched
match = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count match: list[int] = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
parent = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count parent: list[int] = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
base = list(range(vertex_count)) # Each vertex is its own base initially # Each vertex is its own base initially
in_blossom = [False] * vertex_count base: list[int] = list(range(vertex_count))
in_queue = [False] * vertex_count # Tracks vertices in the BFS queue in_blossom: list[bool] = [False] * vertex_count
# Tracks vertices in the BFS queue
in_queue: list[bool] = [False] * vertex_count
# Main logic for finding maximum matching # Main logic for finding maximum matching
for u in range(vertex_count): for u in range(vertex_count):
@ -82,7 +107,8 @@ class EdmondsBlossomAlgorithm:
continue continue
if parent[y] == EdmondsBlossomAlgorithm.UNMATCHED: if parent[y] == EdmondsBlossomAlgorithm.UNMATCHED:
# Case 1: y is unmatched; we've found an augmenting path # Case 1: y is unmatched;
# we've found an augmenting path
if match[y] == EdmondsBlossomAlgorithm.UNMATCHED: if match[y] == EdmondsBlossomAlgorithm.UNMATCHED:
parent[y] = current # Update the parent parent[y] = current # Update the parent
augmenting_path_found = True augmenting_path_found = True
@ -92,7 +118,8 @@ class EdmondsBlossomAlgorithm:
y) y)
break break
# Case 2: y is matched; add y's match to the queue # Case 2: y is matched;
# add y's match to the queue
z = match[y] z = match[y]
parent[y] = current parent[y] = current
parent[z] = y parent[z] = y
@ -102,10 +129,8 @@ class EdmondsBlossomAlgorithm:
else: else:
# Case 3: Both current and y have a parent; # Case 3: Both current and y have a parent;
# check for a cycle/blossom # check for a cycle/blossom
base_u = EdmondsBlossomAlgorithm.find_base(base, base_u = EdmondsBlossomAlgorithm.find_base(base, parent,
parent, current, y)
current,
y)
if base_u != EdmondsBlossomAlgorithm.UNMATCHED: if base_u != EdmondsBlossomAlgorithm.UNMATCHED:
EdmondsBlossomAlgorithm.contract_blossom(BlossomData( EdmondsBlossomAlgorithm.contract_blossom(BlossomData(
BlossomAuxData(queue, parent, BlossomAuxData(queue, parent,
@ -114,66 +139,72 @@ class EdmondsBlossomAlgorithm:
current, y, base_u)) current, y, base_u))
# Create result list of matched pairs # Create result list of matched pairs
matching_result = [] matching_result: list[list[int]] = []
for v in range(vertex_count): for v in range(vertex_count):
# Ensure pairs are unique if (match[v] != EdmondsBlossomAlgorithm.UNMATCHED
if match[v] != EdmondsBlossomAlgorithm.UNMATCHED and v < match[v]: and v < match[v]): # Ensure pairs are unique
matching_result.append([v, match[v]]) matching_result.append([v, match[v]])
return matching_result return matching_result
@staticmethod @staticmethod
def update_matching(match: list[int], parent: list[int], u: int): def update_matching(match: list[int],
parent: list[int],
matched_vertex: int) -> None:
""" """
Updates the matching based on the augmenting path found. Updates the matching based on the augmenting path found.
Args: Args:
match: The current match list. match: The current match list.
parent: The parent list from BFS traversal. parent: The parent list from BFS traversal.
u: The vertex where the augmenting path ends. matched_vertex: The vertex where the augmenting path ends.
""" """
while u != EdmondsBlossomAlgorithm.UNMATCHED: while matched_vertex != EdmondsBlossomAlgorithm.UNMATCHED:
v = parent[u] # Get the parent vertex v = parent[matched_vertex] # Get the parent vertex
next_match = match[v] # Store the next match next_match = match[v] # Store the next match
match[v] = u # Update match for v match[v] = matched_vertex # Update match for v
match[u] = v # Update match for u match[matched_vertex] = v # Update match for matched_vertex
u = next_match # Move to the next vertex matched_vertex = next_match # Move to the next vertex
@staticmethod @staticmethod
def find_base(base: list[int], parent: list[int], u: int, v: int) -> int: def find_base(base: list[int],
parent: list[int],
vertex_u: int, vertex_v: int) -> int:
""" """
Finds the base of the blossom. Finds the base of the blossom.
Args: Args:
base: The base array for each vertex. base: The base array for each vertex.
parent: The parent array from BFS. parent: The parent array from BFS.
u: One endpoint of the blossom. vertex_u: One endpoint of the blossom.
v: The other endpoint of the blossom. vertex_v: The other endpoint of the blossom.
Returns: Returns:
The lowest common ancestor of u and v in the blossom. The lowest common ancestor of vertex_u and vertex_v in the blossom.
""" """
visited = [False] * len(base) visited: list[bool] = [False] * len(base)
# Mark ancestors of u # Mark ancestors of vertex_u
current_u = u current_vertex_u = vertex_u
while True: while True:
current_u = base[current_u] current_vertex_u = base[current_vertex_u]
visited[current_u] = True # Mark this base as visited # Mark this base as visited
if parent[current_u] == EdmondsBlossomAlgorithm.UNMATCHED: visited[current_vertex_u] = True
if parent[current_vertex_u] == EdmondsBlossomAlgorithm.UNMATCHED:
break break
current_u = parent[current_u] current_vertex_u = parent[current_vertex_u]
# Find the common ancestor of v # Find the common ancestor of vertex_v
current_v = v current_vertex_v = vertex_v
while True: while True:
current_v = base[current_v] current_vertex_v = base[current_vertex_v]
if visited[current_v]: # Check if we've already visited this base # Check if we've already visited this base
return current_v if visited[current_vertex_v]:
current_v = parent[current_v] return current_vertex_v
current_vertex_v = parent[current_vertex_v]
@staticmethod @staticmethod
def contract_blossom(blossom_data: BlossomData): def contract_blossom(blossom_data: BlossomData) -> None:
""" """
Contracts a blossom found during the matching process. Contracts a blossom found during the matching process.
@ -181,16 +212,18 @@ class EdmondsBlossomAlgorithm:
blossom_data: The data related to the blossom to be contracted. blossom_data: The data related to the blossom to be contracted.
""" """
# Mark vertices in the blossom # Mark vertices in the blossom
for x in range(blossom_data.u, for x in range(blossom_data.vertex_u,
blossom_data.aux_data.base[blossom_data.u] != blossom_data.lca): blossom_data.aux_data.base
[blossom_data.vertex_u] != blossom_data.lowest_common_ancestor):
base_x = blossom_data.aux_data.base[x] base_x = blossom_data.aux_data.base[x]
match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]] match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]]
# Mark the base as in a blossom # Mark the base as in a blossom
blossom_data.aux_data.in_blossom[base_x] = True blossom_data.aux_data.in_blossom[base_x] = True
blossom_data.aux_data.in_blossom[match_base_x] = True blossom_data.aux_data.in_blossom[match_base_x] = True
for x in range(blossom_data.v, for x in range(blossom_data.vertex_v,
blossom_data.aux_data.base[blossom_data.v] != blossom_data.lca): blossom_data.aux_data.base
[blossom_data.vertex_v] != blossom_data.lowest_common_ancestor):
base_x = blossom_data.aux_data.base[x] base_x = blossom_data.aux_data.base[x]
match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]] match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]]
# Mark the base as in a blossom # Mark the base as in a blossom
@ -201,7 +234,7 @@ class EdmondsBlossomAlgorithm:
for i in range(len(blossom_data.aux_data.base)): for i in range(len(blossom_data.aux_data.base)):
if blossom_data.aux_data.in_blossom[blossom_data.aux_data.base[i]]: if blossom_data.aux_data.in_blossom[blossom_data.aux_data.base[i]]:
# Contract to the lowest common ancestor # Contract to the lowest common ancestor
blossom_data.aux_data.base[i] = blossom_data.lca blossom_data.aux_data.base[i] = blossom_data.lowest_common_ancestor
if not blossom_data.aux_data.in_queue[i]: if not blossom_data.aux_data.in_queue[i]:
# Add to queue if not already present # Add to queue if not already present
blossom_data.aux_data.queue.append(i) blossom_data.aux_data.queue.append(i)