Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f0584c8

Browse files
Finishing up
1 parent 8078e6a commit f0584c8

25 files changed

+774
-17
lines changed

‎LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Arun Kumar
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎Material/Output Screenshot 2.JPG

95.5 KB
Loading[フレーム]

‎Material/Output Screenshot.png

64.8 KB
Loading[フレーム]
49.2 KB
Loading[フレーム]
51.3 KB
Loading[フレーム]
Loading[フレーム]

‎Material/Project Report.pdf

582 KB
Binary file not shown.

‎Material/Project Review PPT.odp

819 KB
Binary file not shown.

‎Material/Time Complexities.jpg

44.9 KB
Loading[フレーム]

‎Material/Writeup.txt

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
ABSTRACT
2+
Prim's algorithm is one of a few algorithms to find the minimum spanning tree of an undirected graph. The algorithm uses a priority queue, and much of its time complexity depends on the priority queue used. This project compares the performances of Prim's algorithm using different priority queues. These are (i) a list which is traversed to find the minimum whenever the ExtractMin operation is performed, (ii) a binary heap, and (iii) a Fibonacci heap.
3+
All of these priority queues' operations have differing time complexities. Theoretically, the Fibonacci heap is superior to other less sophisticated priority queues because its DecreaseKey runs in theta(1) amortized time. But due to the complexity in its structure, it is known not to run fast practically for small input sizes. When we compared our implementations, the Fibonacci heap and the binary heap took more or less the same running time for input sizes of above 2000 vertices.
4+
5+
INTRODUCTION - PROBLEM STATEMENT
6+
To implement Prim's minimum spanning tree algorithm using
7+
1. Lazy and Eager Naive Approaches
8+
2. Binary Heap as Priority Queue
9+
3. Fibonacci Heap as Priority Queue
10+
and compare their performances on large inputs.
11+
The lazy and eager naive approaches will use the adjacency matrix representation for the graph whereas the other approaches will use the adjacency lists representation.
12+
Our project will only be focusing on connected graphs.
13+
14+
INTRODUCTION - OBJECTIVES
15+
We will analyse the performances of the different implementations on many undirected graphs of differing edge densities.
16+
We know that theoretically the Fibonacci heap implementation has the best time complexity. We will test this empirically.
17+
We will create an interface for a user to run our implementations on a given graph and to visualize the minimum spanning tree produced by Prim's algorithm.
18+
19+
DATA STRUCTURES AND ALGORITHMS
20+
<Copy images from the synopsis for this section.>
21+
Minimum Spanning Tree: A minimum spanning tree (MST) is a subset of the edges of a connected, edge-weighted undirected graph that connects all the vertices together, without any cycles and with the minimum possible total edge weight.
22+
23+
Prim’s Algorithm: Prim's algorithm is an algorithm to construct an MST from the given graph. It was developed by Jarnik in 1930, and was later rediscovered and republished by Prim in 1957 and Dijkstra in 1959.
24+
1. Initialize a tree with a single vertex, chosen arbitrarily from the graph.
25+
2. Grow the tree by one edge: of the edges that connect the tree to vertices not yet in the tree, find the minimum-weight edge, and transfer it to the tree.
26+
3. Repeat step 2 until all vertices are in the tree.
27+
28+
Representations of Graph: The two most common ways of representing graphs are adjacency matrix and adjacency list. Suppose the n vertices of a graph are numbered from 0 to n - 1. We take every edge to be of the form (i, j); the edge originates at vertex i and terminates at vertex j. An adjacency matrix is an n*n matrix in which the value of [i, j]th cell is the weight of the edge if there is an edge or 0 if there isn't. An adjacency list is an array of separate lists. The array has length n and the ith element of the array is a list of all those vertices which are directly connected to the ith vertex.
29+
30+
Binary Heap: A binary heap is a complete binary tree where the key stored in each node is either greater than or equal to (for a max-heap) or less than or equal to (for a min-heap) the keys in the node’s children. It was introduced by John Williams in 1964 as a data structure for heapsort. We require a min-heap for Prim's algorithm.
31+
The heap will be implemented using an array rather than self-referential pointers.
32+
The common operations performed on a min-heap are insert, find_min, extract_min and decrease_key. Both insert and extract_min modify the heap to conform to the shape property (heap being a complete binary tree) first, by adding or removing from the end of the heap. Then the heap property is restored by traversing up or down the heap. Both operations take O(log n) time, where n is the number of nodes. We will only use the extract_min and decrease_key operations in Prim's algorithm.
33+
The extract_min operation removes the smallest element i.e. the root from the heap. This is done by replacing the root with the last element on the last level and then repeated swapping of keys until the heap property is satisfied. The decrease_key operation is used to change the key value of a given node to a new smaller value. Since the new value is smaller, key exchanges are upward. This operation also takes O(log n), but that is a less strict upper bound.
34+
35+
Fibonacci Heap: Invented by Fredman and Tarjan in 1984, a Fibonacci heap is a heap data structure similar to the binomial heap, only with a few modifications and a looser structure. The Fibonacci heap was designed in order to improve Dijkstra’s shortest path algorithm. Its name derives from the fact that the Fibonacci sequence is used in the complexity analysis of its operations. It is a collection of heap-ordered trees, each tree having an order that is based on the number of children (i.e. a tree having a single node has degree 0, a tree having one root and two children has degree 2). The trees can have any shape (trees can even be single nodes).
36+
All tree roots are connected using a circular doubly linked list. A pointer to minimum root (which is the minimum value) is maintained. The Fib heap executes operations the lazy way. "Do work only when you must, and then use it to simplify the structure as much as possible so that your future work is easy." Insert operation simply adds a new tree with single node and merge/meld operation simply links two heaps. ExtractMin does the most work -- removing the minimum from the list of roots, making its children roots, and then consolidates all trees with the same order. For DecreaseKey, if the node that has been decreases causes a heap violation, then it is cut from its parent and added to the root list. If any node has lost one child, it is marked, and if it loses another child, it is cut from its parent and added to the root list.
37+
<Tables>
38+
39+
40+
SYSTEM REQUIREMENTS - FUNCTIONAL REQUIREMENTS
41+
In this project, we have programmed data structures of binary heap and Fibonacci heap priority queues and four implementations of Prim's algorithm.
42+
For demonstration: We have a user interface, where the user enters the file name of the test case and the names of the implementations that they want to run it through. The program runs it through these implementations and displays the time taken for each. The program also displays the MST produced by Prim's algorithm. This graph visualization is done by one of the modules using the networkX library.
43+
For analysis: We have a module that generates test cases and then puts them through the implementations. The durations are gathered into CSV files and are used to plot performance comparison plots.
44+
45+
SYSTEM REQUIREMENTS - HARDWARE REQUIREMENTS
46+
RAM of 4 GB or above.
47+
Internal storage of 256 GB or above.
48+
Processor Intel i5 or above.
49+
50+
SYSTEM REQUIREMENTS - SOFTWARE REQUIREMENTS
51+
Programming Language: Python, version 3.6 or above.
52+
External Libraries Used: Numpy, Pandas, Matplotlib, NetworkX
53+
Version Control (For Development): Git and GitHub
54+
Operating System: Windows 10 or Ubuntu Linux.
55+
56+
SYSTEM DESIGN - ARCHITECTURE / DATA FLOW DIAGRAM
57+
58+
SYSTEM DESIGN - MODULES
59+
User Interface: Driver.py
60+
Data Structure for Graph: Graph.py
61+
Binary Heap Data Structure: BinaryHeap.py
62+
Fibonacci Heap Data Structure: FibHeap.py
63+
Lazy Naive Implementation: LazyNaivePrims.py
64+
Eager Naive Implementation: EagerNaivePrims.py
65+
Implementation using Binary Heap: BinaryHeapPrims.py
66+
Implementation using Fibonacci Heap: FibHeapPrims.py
67+
Graph Visualization: VisualizeMst.py
68+
Creation and Analysis of Test Cases: GraphGeneration.py, AutomatingTests.py, "Performance Comparison Plotter.ipynb"
69+
70+
SYSTEM IMPLEMENTATION - MODULE DESCRIPTION
71+
Driver.py
72+
Renders the user interface. Takes the name of the test file as a command line argument, but if not provided, prompts for it. Also reads implementation choices and display choice. Runs the algorithm's desired implementation and times it. Calls functions in other modules to display the MST.
73+
74+
Graph.py
75+
Contains the class Graph. This class has functionalities like reading and printing the graph and changing the graph data from adjacency matrix to adjacency lists representation. This module also contains a function to find the adjacency matrix of the MST and its cost given a parent node - child node map of the MST.
76+
77+
LazyNaivePrims.py
78+
This module contains the lazy naive implementation of Prim's algorithm, where edges are extracted and inserted, as opposed to vertices. This module contains the class EdgeList, inherited from built-in type list. EdgeList is the priority queue of edges.
79+
80+
EagerNaivePrims.py
81+
This module contains the eager naive implementation of Prim's algorithm and the class KeyList, inherited from built-in type list. KeyList is the priority queue of vertices.
82+
83+
BinaryHeap.py
84+
Contains the classes MinHeap and MinHeapForPrims. MinHeap is a binary min-heap which uses an array to store key values. MinHeapForPrims is inherited from MinHeap and is a priority queue to store vertex-key pairs. It maintains a map connecting vertices to nodes in the heap (since DecreaseKey takes the desired vertex as one of its inputs). Each heap node also contains the label of the vertex it is associated with (for ExtractMin since it returns a vertex).
85+
86+
BinaryHeapPrims.py
87+
The implementation of Prim's algorithm which uses MinHeapForPrims as the priority queue.
88+
89+
TestsForHeap.py
90+
Unit tests for binary heap operations.
91+
92+
FibHeap.py
93+
Contains the classes FibHeap and FibHeapForPrims. FibHeap is a Fibonacci heap which stores key values. The data structure is built on multiple doubly circular linked lists. FibHeapForPrims serves a similar purpose as MinHeapForPrims.
94+
95+
FibHeapPrims.py
96+
The implementation of Prim's algorithm which uses FibHeapForPrims as the priority queue.
97+
98+
TestsForFibHeap.py
99+
Unit tests for Fibonacci heap operations.
100+
101+
VisualizeMst.py
102+
Uses the networkX module to display the graph with the MST highlighted.
103+
104+
GraphGeneration.py
105+
To generate test cases -- undirected connected graphs.
106+
107+
AutomatingTests.py
108+
To create many test files for performance comparison purpose, put them through all the implementations, time the durations and store the durations in CSV files.
109+
110+
"Performance Comparison Plotter.ipynb"
111+
Uses the data from CSV files to plot input size vs duration graphs to observe the differences in the performances of the implementations. The plotting is done with the help of the Matplotlib library.
112+
113+
SYSTEM IMPLEMENTATION - PSEUDOCODE
114+
Prim's Algorithm - Lazy Approach:
115+
1) visited := {0}
116+
2) pq := PriorityQueue()
117+
3) Add all edges from vertex 0 to pq.
118+
4) Repeat |V| - 1 times.
119+
4.1) from_vx, cur_vx, weight = pq.ExtractMin()
120+
4.2) If cur_vx is in visited, go to 4.1.
121+
4.3) visited += {cur_vx}
122+
4.4) Add all edges from vertex cur_vx to pq.
123+
124+
Prim's Algorithm - Eager Approach:
125+
This is also how the other implementations work.
126+
1) visited := {0}
127+
2) pq := PriorityQueue()
128+
3) Add all vertices to pq with key infinity.
129+
4) pq[0] := 0
130+
5) Repeat |V| times.
131+
5.1) u = pq.ExtractMin()
132+
5.3) visited += {u}
133+
5.4) For all unvisited vertices adjacent to u (say v)
134+
5.4.1) If pq[v] > weight of edge u-v
135+
5.4.1.1) pq.DecreaseKey(v, weight of edge u-v)
136+
137+
Binary Heap Operations:
138+
SiftUp(idx):
139+
1) Repeat until heap property is restored:
140+
1.1) parent_idx := (idx - 1) // 2 (where // is integer division)
141+
1.2) if arr[idx] < arr[parent_idx]
142+
1.2.1) Swap(arr[idx], arr[parent_idx]).
143+
1.2.2) idx := parent_idx
144+
145+
SiftDown(idx):
146+
1) Repeat until heap property is restored:
147+
1.1) left_child_idx := idx * 2
148+
1.2) right_child_idx := left_child_idx + 1
149+
1.3) desired_child_idx := index of minimum child
150+
1.4) If arr[idx] > arr[desired_child_idx]:
151+
1.4.1) swap(arr[idx], arr[desired_child_idx])
152+
1.4.2) idx = desired_child_idx
153+
154+
Insert(key):
155+
1) arr.append(key)
156+
2) SiftUp(size(arr) - 1)
157+
158+
DecreaseKey(idx, newkey):
159+
1) arr[idx] := newkey
160+
2) SiftUp(idx)
161+
162+
ExtractMin():
163+
1) Swap(arr[0], arr[size(arr) - 1])
164+
2) Discard and return arr[size(arr) - 1]
165+
166+
Fibonacci Heap Operations
167+
Merge (fibheapA, fibheapB):
168+
1) fibheapC.root_list = concatenate(fibheapA.root_list, fibheapB.root_list)
169+
2) fibheapC.min_node = min(fibheapA.min_node, fibheapB.min_node)
170+
171+
ExtractMin():
172+
1) Remove min_node from root_list.
173+
2) Add the min_node's children to root_list.
174+
3) Consolidate root_list i.e. merge trees of the same rank.
175+
4) min_node = min(root_list).
176+
177+
Insert(key):
178+
1) Create a new fibheap consisting of one node containing key.
179+
2) Merge(fibheap, new fibheap)
180+
181+
DecreaseKey(node, newkey):
182+
1) node.key := newkey
183+
2) If node.parent is None:
184+
2.1) Return
185+
3) If node.parent.key <= node.key:
186+
3.1) Return
187+
4) Cut(node)
188+
5) CascadingCut(node.parent)
189+
190+
Cut(node):
191+
1) Remove node from node.parent.child list.
192+
2) Decrement node.parent.rank.
193+
3) Add node to root list.
194+
195+
CascadingCut(node):
196+
1) If node is marked:
197+
1.1) Cut(node)
198+
1.2) CascadingCut(node.parent)
199+
2) Else:
200+
2.1) Mark node.
201+
202+
OUTPUT SCREENSHOTS
203+
204+
OBSERVATIONS
205+
We generated three tests each with input sizes from 10 to 200 in steps of 10, then 250 to 2000 in steps of 50, and then 2100 to 3500 in steps of 100. Note that input size refers to the number of vertices. For each input size, we generated one medium density graph, one high density graph and one compelete graph. There is no low density category because we are considering a low density graph to be a graph solely consisting of a spanning tree.
206+
On running the implementations on these tests, we observed that:
207+
1) Lazy Naive Approach takes the most time for every test case and therefore is an inefficent way to find the MST for a graph.
208+
2) For low input sizes (10 to 200), the Fibonacci heap implementation took much more time than the other two. The eager naive approach took slightly lesser time than the binary heap implementation until the input size of approximately 160 vertices.
209+
3) For large input sizes (250 to 3500), the two heap implementations have more or less the same duration. The eager naive approach proves to be very inefficient when the input size exceeds 1000 vertices.
210+
211+
Since the Fibonacci heap implementation has a better time complexity than the others, we expected that it would take the least amount of time for very large graphs. But, it looks like we will need larger test cases to reach that threshold. We tried with an input size of 10,000 but the program ran out of memory.
212+
213+
CONCLUSION
214+
The lazy naive approach is not an efficient implementation of the Prim's algorithm for any input size.
215+
The eager naive approach is easily implementable and proves efficient for graphs with less than one thousand vertices.
216+
The Fibonacci heap implementation takes a lot of time for graphs with low input sizes but its performance is almost the same as the binary heap implementation for graphs with more than 500 vertices.
217+
218+
REFERENCES
219+
Prim, R. C. (November 1957), "Shortest connection networks and some generalizations", Bell System Technical Journal
220+
Fredman, Michael Lawrence; Tarjan, Robert E. (July 1987). "Fibonacci heaps and their uses in improved network optimization algorithms". Journal of the Association for Computing Machinery.
221+
Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford (2001) [1990]. "Chapter 20: Fibonacci Heaps". Introduction to Algorithms
222+
223+
224+
225+
226+
227+
228+
229+
230+
231+
232+
233+
234+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /