Skip to content

Added Bipartite Algorithm #646

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

Closed
wants to merge 1 commit into from
Closed
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
3 changes: 2 additions & 1 deletion pydatastructs/graphs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
all_pair_shortest_paths,
topological_sort,
topological_sort_parallel,
max_flow
max_flow,
is_bipartite
)

__all__.extend(algorithms.__all__)
57 changes: 56 additions & 1 deletion pydatastructs/graphs/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
'all_pair_shortest_paths',
'topological_sort',
'topological_sort_parallel',
'max_flow'
'max_flow',
'is_bipartite'
]

Stack = Queue = deque
Expand Down Expand Up @@ -1216,3 +1217,57 @@ def max_flow(graph, source, sink, algorithm='edmonds_karp', **kwargs):
f"Currently {algorithm} algorithm isn't implemented for "
"performing max flow on graphs.")
return getattr(algorithms, func)(graph, source, sink)

def is_bipartite(graph):
"""
Determines whether the given undirected graph is bipartite using BFS.

Parameters
==========
graph : Graph
An undirected graph instance.

Returns
=======
(bool, dict)
A tuple where the first element is True if the graph is bipartite and False otherwise.
The second element is a dictionary mapping each vertex (its name) to a color (0 or 1)
if the graph is bipartite; if not, the dictionary may be partially filled.

Examples
========
>>> from pydatastructs import Graph, AdjacencyListGraphNode, is_bipartite
>>> v0 = AdjacencyListGraphNode(0)
>>> v1 = AdjacencyListGraphNode(1)
>>> v2 = AdjacencyListGraphNode(2)
>>> v3 = AdjacencyListGraphNode(3)
>>> graph = Graph(v0, v1, v2, v3, implementation='adjacency_list')
>>> graph.add_edge(v0.name, v1.name)
>>> graph.add_edge(v1.name, v2.name)
>>> graph.add_edge(v2.name, v3.name)
>>> graph.add_edge(v3.name, v0.name)
>>> is_bipartite(graph)
(True, {'0': 0, '1': 1, '2': 0, '3': 1})

References
==========
.. [1] https://en.wikipedia.org/wiki/Bipartite_graph
"""
from collections import deque
color = {}

for vertex in graph.vertices:
vertex_name = vertex.name if hasattr(vertex, "name") else vertex
if vertex_name not in color:
color[vertex_name] = 0
queue = deque([vertex_name])
while queue:
u = queue.popleft()
for neighbor in graph.neighbors(u):
v = neighbor.name if hasattr(neighbor, "name") else neighbor
if v not in color:
color[v] = 1 - color[u]
queue.append(v)
elif color[v] == color[u]:
return (False, color)
return (True, color)
37 changes: 36 additions & 1 deletion pydatastructs/graphs/tests/test_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
breadth_first_search_parallel, minimum_spanning_tree,
minimum_spanning_tree_parallel, strongly_connected_components,
depth_first_search, shortest_paths,all_pair_shortest_paths, topological_sort,
topological_sort_parallel, max_flow)
topological_sort_parallel, max_flow, is_bipartite)
from pydatastructs.utils.raises_util import raises

def test_breadth_first_search():
Expand Down Expand Up @@ -448,3 +448,38 @@ def _test_max_flow(ds, algorithm):
_test_max_flow("Matrix", "edmonds_karp")
_test_max_flow("List", "dinic")
_test_max_flow("Matrix", "dinic")

def test_is_bipartite():
import pydatastructs.utils.misc_util as utils
def _test_bipartite(ds):
GraphNode = getattr(utils, "Adjacency" + ds + "GraphNode")
impl = 'adjacency_list' if ds == "List" else 'adjacency_matrix'

v0 = GraphNode(0)
v1 = GraphNode(1)
v2 = GraphNode(2)
v3 = GraphNode(3)
graph = Graph(v0, v1, v2, v3, implementation=impl)
graph.add_edge(v0.name, v1.name)
graph.add_edge(v1.name, v2.name)
graph.add_edge(v2.name, v3.name)
graph.add_edge(v3.name, v0.name)
bip, colors = is_bipartite(graph)
assert bip is True
assert colors[v0.name] != colors[v1.name]
assert colors[v1.name] != colors[v2.name]
assert colors[v2.name] != colors[v3.name]
assert colors[v3.name] != colors[v0.name]

u0 = GraphNode(0)
u1 = GraphNode(1)
u2 = GraphNode(2)
graph = Graph(u0, u1, u2, implementation=impl)
graph.add_edge(u0.name, u1.name)
graph.add_edge(u1.name, u2.name)
graph.add_edge(u2.name, u0.name)
bip, _ = is_bipartite(graph)
assert bip is False

_test_bipartite("List")
_test_bipartite("Matrix")
Loading