1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
pub mod dijkstras {
    use std::{
        cmp::Ordering, // Importing Ordering to make node structure comparision based on distances
        collections::{BinaryHeap, HashSet}, // Importing BinaryHeap and HashSet to get priority Node and to mark visited Nodes
        io::{stdin, stdout, Write}, // Importing input/output library for reading user input and for printing output
    };

    #[derive(Clone, Eq, PartialEq, PartialOrd)]
    #[doc(hidden)]
    struct Node {
        vertex: usize, // Vertex name in the Graph
        dist: i32,     // Distance from source to vertex
    }

    /// A graph data structure represented as an adjacency list.
    pub struct Graph {
        /// The adjacency list of the graph, where the i-th element contains a list of adjacent nodes for vertex i.
        adj_list: Vec<Vec<Node>>, // Adjacency list representation using Node structure
        /// The total number of vertices in the graph.
        vertices: usize, // Total number of vertices in the Graph
    }

    impl Ord for Node {
        fn cmp(&self, other: &Self) -> Ordering {
            // Custom comparison function for Node to compare on dist
            other.dist.cmp(&self.dist) // Nodes will be compared by their distance from the source
        }
    }
    #[doc(hidden)]
    impl Graph {
        /// Constructs a new Graph with the specified number of vertices.
        ///
        /// # Arguments
        ///
        /// * `vertices`: The number of vertices in the graph.
        ///
        /// # Example
        ///
        /// ```
        /// use graph::Graph;
        ///
        /// let g = Graph::new(10);
        /// ```
        pub fn new(vertices: usize) -> Self {
            // Constructor for Graph structure
            Graph {
                adj_list: vec![Vec::new(); vertices], // Initializing adjacency list with empty vectors with size equal to vertices number
                vertices,
            }
        }

        /// Adds an undirected edge between two vertices in the graph, with the specified weight.
        ///
        /// # Arguments
        ///
        /// * `u`: The source vertex.
        /// * `v`: The destination vertex.
        /// * `w`: The weight of the edge.
        ///
        /// # Example
        ///
        /// ```
        /// use graph::{Graph, Node};
        ///
        /// let mut g = Graph::new(3);
        ///
        /// g.add_edge(0, 1, 10);
        /// g.add_edge(1, 2, 20);
        /// g.add_edge(2, 0, 30);
        ///
        /// ```
        pub fn add_edge(&mut self, u: usize, v: usize, w: i32) {
            // Function `add_edge` to add edges to the graphs
            self.adj_list[u].push(Node { vertex: v, dist: w }); // Adding Vertex `v` as adjacent vertex of Vertex `u`
            self.adj_list[v].push(Node { vertex: u, dist: w }); // Add Vertex `u` as adjacent vertex of Vertex `v`
        }

        /// performs Dijkstra's algorithm on a weighted graph to find the shortest path from a source vertex to every vertex in the graph.
        ///
        /// # Arguments
        ///
        /// * `self` - A reference to the graph object.
        /// * `src` - The index of the source vertex.
        ///
        /// # Returns
        ///
        /// A `Vec<i32>` containing the shortest distance from the source vertex to every other vertex in the graph.
        ///
        /// # Example
        ///
        /// ```
        /// use graph::Graph;
        ///
        /// let g = Graph::new(4);
        /// g.add_edge(0, 1, 1);
        /// g.add_edge(0, 2, 4);
        /// g.add_edge(1, 2, 2);
        /// g.add_edge(1, 3, 5);
        /// g.add_edge(2, 3, 1);
        ///
        /// let dist = g.dijkstra(0);
        /// assert_eq!(dist, vec![0, 1, 3, 4]);
        /// ```
        pub fn dijkstra(&self, src: usize) -> Vec<i32> {
            let mut dist = vec![i32::max_value(); self.vertices]; // Initializing all distances to max value So that we can select min distance and update the graph
            let mut visited_vertices = HashSet::new(); // To store the visited vertices
            dist[src] = 0; // Initializing distance from source to the source to 0
            let mut pq = BinaryHeap::new(); // Creating a BinaryHeap to store nodes for priority queue

            pq.push(Node {
                vertex: src,
                dist: dist[src],
            }); // Pushing the source node into priority queue

            // Loop till the BinaryHeap is empty
            while !pq.is_empty() {
                let Node { vertex: u, dist: _ } = pq.pop().unwrap(); // Getting the node with minimum distance from the priority queue

                // Checking if the vertex is already visited
                if visited_vertices.contains(&u) {
                    continue;
                } else {
                    visited_vertices.insert(u); // marking the vertex as visited by inserting into the HashSet
                }

                // For every adjacent vertex of u, relax the edge
                for Node { vertex: v, dist: w } in &self.adj_list[u] {
                    let new_dist = dist[u] + *w; // Calculating the new distance
                    if new_dist < dist[*v] {
                        // Check if the new distance is less than current distance
                        dist[*v] = new_dist; // Relax the distance
                        pq.push(Node {
                            vertex: *v,
                            dist: dist[*v],
                        }); // Push the node into priority queue
                    }
                }
            }

            // Return the distances from source to every other vertex
            dist
        }
    }

    /// Performs Dijkstra's algorithm on a given directed graph represented as an adjacency list.
    /// Prints a vector of vectors, where each inner vector contains the nodes of dijkstras in sorted order.
    ///
    /// # Inputs
    ///
    /// * `vertices` - Total number of vertices in the graph.
    ///
    /// * `source` - A vertex in the graph from which min weight to be calculated to all other vertices in the graph.
    ///
    /// * `edges` - Total Number of edges in the graph.
    ///
    /// * `Source(s) Destination(d) Weight(w) ` - Source, Destination and Weight for each edge in the graph.  
    ///
    /// # Output
    ///
    /// Prints minimum weight from the source vertex to all vertices in the graph.
    ///
    /// # Sample Input
    /// ```
    /// Please Enter Number of Vertices in the Graph : 5
    /// Please Enter Source Vertex : 0
    /// Please Enter Number of edges in the graph : 3
    /// Please Enter Edge 1 values
    /// Source : 0
    /// Destination : 1
    /// Weight(>0) : 10
    /// Please Enter Edge 2 values
    /// Source : 0
    /// Destination : 2
    /// Weight(>0) : 5
    /// Please Enter Edge 3 values
    /// Source : 3
    /// Destination : 4
    /// Weight(>0) : 4
    ///
    /// ```
    /// # Sample Output
    /// ```
    /// Distance from vertex 0 to vertex 0 is 0
    /// Distance from vertex 0 to vertex 1 is 10
    /// Distance from vertex 0 to vertex 2 is 5
    /// Distance from vertex 0 to vertex 3 is 2147483647
    /// Distance from vertex 0 to vertex 4 is 2147483647
    pub fn dijkstras() {
        // Create two empty strings to store user input(Source & Vertices Count)
        let mut ve = String::new();
        let mut so = String::new();

        // Printing the introduction message
        println!("******Dijkstras Algorithm*******");
        println!("******************");

        // Prompting user to input number of vertices in the Graph
        print!("Please Enter Number of Vertices in the Graph : ");
        let _ = stdout().flush();

        // Reading user input for number of vertices, parsing it into an integer and handling errors
        stdin()
            .read_line(&mut ve)
            .expect("Please Enter Valid number for vertices.");
        let vertices: usize = ve
            .trim()
            .parse()
            .expect("Invalid input for number of vertices");

        // Prompting user to input the source vertex
        print!("Please Enter Source Vertex : ");
        let _ = stdout().flush();

        // Reading user input for source vertex and parsing it into an integer
        stdin()
            .read_line(&mut so)
            .expect("Please Enter Valid Input for Source.");
        let source: usize = so.trim().parse().expect("Invalid input for source");

        // Prompting user to input the number of edges
        let mut edges = String::new();
        print!("Please Enter Number of edges in the graph : ");
        let _ = stdout().flush(); // Flushing the output buffer to ensure prompt is displayed before taking input from user

        // Reading user input for number of edges and parsing it into an integer
        stdin()
            .read_line(&mut edges)
            .expect("Please Enter Valid Input for number of Edges.");
        let edges: i32 = edges
            .trim()
            .parse()
            .expect("Invalid input for number of edges");

        // Creating a new graph with the number of vertices entered by the user
        let mut g = Graph::new(vertices);

        // Initializing counter variable to keep track of the number of edges added
        let mut cnt = 0;

        // Loop Prompting user to input all edges source, destination and weight
        while cnt < edges {
            println!("Please Enter Edge {} values ", cnt + 1);
            let mut s = String::new();
            let mut d = String::new();
            let mut w = String::new();

            // Prompting user to input source vertex of current edge
            print!("Source : ");
            let _ = stdout().flush();

            // Reading user input for source vertex and parsing it into an integer
            stdin()
                .read_line(&mut s)
                .expect("Please Enter Valid Input for Source.");
            let s: usize = s.trim().parse().expect("Invalid input for source");

            // Prompting user to input destination vertex of current edge
            print!("Destination : ");
            let _ = stdout().flush();

            // Reading user input for destination vertex and parsing it into an integer
            stdin()
                .read_line(&mut d)
                .expect("Please Enter Valid Input for destination.");
            let d: usize = d.trim().parse().expect("Invalid input for destination");

            // Prompting user to input weight of current edge
            print!("Weight(>0) : ");
            let _ = stdout().flush();

            // Reading user input for edge weight and parsing it into an integer
            stdin()
                .read_line(&mut w)
                .expect("Please Enter Valid Input for weight.");
            let w: i32 = w.trim().parse().expect("Invalid input for weight");

            // Adding the current edge to the graph
            g.add_edge(s, d, w);

            // Increasing the edge counter
            cnt = cnt + 1;
        }

        // Calling Dijkstra's algorithm to find the shortest path from th e Source
        let dist = g.dijkstra(source);
        println!("******************");
        // Looping and printing the distances from Source to respective vertices
        for (v, d) in dist.iter().enumerate() {
            println!("Distance from vertex {} to vertex {} is {}", source, v, d);
        }
    }
}
// stdin, stdout and Write trait from std::io module

#[cfg(test)]
mod tests {

    use super::dijkstras::Graph;

    #[test]
    fn test_dijkstra() {
        let mut g = Graph::new(5);
        g.add_edge(0, 1, 10);
        g.add_edge(0, 2, 5);
        g.add_edge(1, 3, 1);
        g.add_edge(2, 1, 3);
        g.add_edge(2, 3, 8);
        g.add_edge(2, 4, 2);
        g.add_edge(3, 4, 4);
        let dist = g.dijkstra(0);
        assert_eq!(dist, vec![0, 8, 5, 9, 7]);
    }

    #[test]
    #[should_panic]
    fn test_empty_graph() {
        let g = Graph::new(0);
        g.dijkstra(0);
    }

    #[test]
    fn test_single_vertex() {
        let g = Graph::new(1);
        let dist = g.dijkstra(0);
        assert_eq!(dist, vec![0]);
    }

    #[test]
    fn test_disconnected_graph() {
        let mut g = Graph::new(5);
        g.add_edge(0, 1, 10);
        g.add_edge(0, 2, 5);
        g.add_edge(3, 4, 4);
        let dist = g.dijkstra(0);
        assert_eq!(dist, vec![0, 10, 5, i32::max_value(), i32::max_value()]);
    }

    #[test]
    fn test_negative_weights() {
        let mut g = Graph::new(3);
        g.add_edge(0, 1, 1);
        g.add_edge(1, 2, -2);
        g.add_edge(0, 2, 4);
        let dist = g.dijkstra(0);
        assert_eq!(dist, vec![0, 1, -1]);
    }
}