Discretecode 4
Discretecode 4
ics
at
m
Laboratory Manual
he
at
M
te
re
sc
Di
Prince Achankunju
ics
Hasse Diagram of Posets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
at
Plotting Different Types of Directed and Undirected Graphs with Proper
Labelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
m
Matrix Representation of Graphs . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
he
Minimum Spanning Tree Algorithm – Prim’s and Kruskal’s Algorithm . . . 34
at
1
Exercise No: 1
Structures
Python offers several libraries that are effective in solving problems related to discrete mathe-
matical structures. These libraries provide tools for handling combinatorics, graph theory, logic,
sets, and more. Below is an overview of relevant libraries and their usage:
1. NumPy
ics
Purpose: Numerical computations, matrix operations, and combinatorial functions.
at
Why NumPy?
NumPy (Numerical Python) is a powerful library used to perform mathematical and logical
m
operations on large arrays and matrices. It is essential for implementing algorithms related to
he
sets, logic, relations, and other discrete structures.
at
This example calculates the number of combinations of r elements from a set of n elements
1 import numpy as np
2 from math import comb
3 n, r = 5, 3 # Calculate combinations
4 print ( f " Combinations C ({ n } ,{ r }) : { comb (n , r ) } " )
Output:
Combinations C(5,3): 10
2
Example 2: Logical Operations Using NumPy Arrays
In discrete mathematics, logic operations like AND, OR are applied to truth values. NumPy
ics
Output:
at
Logical AND: [False False True]
m
Example 3: Set Operations (Union and Intersection)
he
Sets are a fundamental part of discrete structures. NumPy provides operations to handle sets
at
efficiently.
M
or B
sc
Output:
Union: [1 2 3 4 5]
Intersection: [3]
2. SymPy
3
Applications:
Logical equivalences
Truth tables
Propositional calculus
s
4 simplified_expr = simplify ( expr )
ic
5 print ( f " Simplified Expression : { simplified_expr } " )
at
1 from sympy . logic . boolalg import truth_table
2 # Truth Table
3
4
tt = truth_table ( expr , [p , q ])
for row in tt :
em
th
5 print ( row )
Ma
3. NetworkX
Di
Applications:
4
1 import networkx as nx
2 G = nx . Graph () # Create a graph
3 G . add_edges_from ([(1 , 2) , (2 , 3) , (3 , 4) , (4 , 1) ])
4 # Check connectivity
5 print ( f " Is graph connected ? { nx . is_connected ( G ) } " )
6 # Find shortest path
7 path = nx . shortest_path (G , source =1 , target =3)
8 print ( f " Shortest path from 1 to 3: { path } " )
s
ic
4. Matplotlib
at
Applications:
Visualizing graphs
em
th
Displaying logical relationships
Ma
1 import networkx as nx
2 import matplotlib . pyplot as plt
te
3 # Directed graph
4 G = nx . DiGraph ()
re
5 G . add_edges_from ([(1 , 2) , (2 , 3) , (3 , 1) ])
nx . draw (G , with_labels = True )
sc
8 plt . show ()
1 # Cycle graph
2 G = nx . cycle_graph (5)
3 nx . draw (G , with_labels = True , node_color = ’ skyblue ’ , font_weight = ’ bold
’)
4 plt . title ( " Cycle Graph " )
5 plt . show ()
5
1 # Venn diagram using pie chart
2 labels = [ ’ Set A ’ , ’ Set B ’]
3 sizes = [3 , 2]
4 plt . pie ( sizes , labels = labels , autopct = ’ %1.1 f %% ’)
5 plt . title ( " Venn Representation of Sets " )
6 plt . show ()
5. itertools
s
Purpose: Handling combinatorics and permutations.
ic
Applications:
at
Generating permutations, combinations, and Cartesian products
3 # Permutations
4 perm = list ( permutations ([1 , 2 , 3]) )
5 print ( f " Permutations : { perm } " )
te
7 # Combinations
re
6. SciPy
Applications:
6
1 from scipy . optimize import linprog
2 # Linear programming
3 c = [ -1 , -2] # Objective coefficients
4 A = [[2 , 1] , [1 , 2]] # Constraint coefficients
5 b = [20 , 20]
6 result = linprog (c , A_ub =A , b_ub =b , method = ’ highs ’)
7 print ( f " Optimal solution : { result . x } , Maximum value : { - result . fun } " )
7. PyEDA
ics
Purpose: Boolean algebra and truth tables.
Applications:
at
Solving Boolean equations
7
Exercise No: 2
in Propositional Logic
Aim:
To develop a Python program that generates and displays truth tables for multiple logical
ics
Objectives:
at
Understand the representation of logical expressions as Python functions.
m
Implement a function to generate all possible combinations of truth values for given vari-
he
ables.
Algorithm:
sc
1. Import necessary libraries: Use pandas for table creation and IPython.display for
Di
pressions dynamically.
3. Extract Variables: From the first logical expression’s function, extract the list of vari-
able names using Python’s func. code .co varnames. Assumes all expressions use the
8
4. Calculate Number of Rows
Compute the total number of rows as 2n , which represents all possible combinations
of input values.
– Generate a list of Boolean values of length 2n such that the truth value toggles
s
every 2n−j−1 rows.
ic
For example, the first variable toggles every half of the rows, the second every quarter,
at
and so on.
This structure will represent the variable columns of the truth table.
7. Evaluate Logical Expressions: For each logical expression (name, func) in the input:
te
For each row (combination of variable truth values), call func with the corresponding
re
arguments.
Store the result in the data structure under the column labeled with name.
sc
Convert the final data structure into a formatted table using a Python tool like
pandas.DataFrame.
9
Pseudocode (Python):
1 import pandas as pd
2 from IPython . display import display , Math
3
4 def g e n e r a t e _ t r u t h _ t a b l e (* expressions ) :
5 variables = list ( expressions [0][1]. __code__ . co_varnames ) # Extract
variable names
6 n = len ( variables ) # Number of variables
s
7 rows = 2 ** n # Number of rows (2^ n )
ic
8
at
10 data = { var : [( i // (2 ** ( n - j - 1) ) ) % 2 == 1 for i in range ( rows
m
) ] for j , var in enumerate ( variables ) }
11 he
12 # Apply each logical expression function
13 for name , func in expressions :
at
14 data [ name ] = [ func (**{ var : row [ var ] for var in variables }) for row
in pd . DataFrame ( data ) . to_dict ( ’ records ’) ]
M
15
18
19 truth_table = g e n e r a t e _ t r u t h _ t a b l e (
cr
10
Result and Discussion:
The generated truth table accurately evaluates three compound logical expressions involving
variables A, B, and C:
The expression A ∧ (B ∨ C) returns True only when A is True and at least one of B or C
is True.
False.
ics
The expression ¬A ∨ ¬B is False only when both A and B are True, as expected from
De Morgan’s law.
at
m
The logic is implemented correctly and matches classical truth table behavior. The program
Application:
M
In digital circuit design, a three-input logic gate is defined with the function f (A, B, C) =
te
A ∧ (B ∨ C). A fault is suspected when the gate does not output True for some expected input
re
combinations. Using the provided truth table generation algorithm, construct the truth table
for the function. Identify input conditions under which the gate should ideally output True,
sc
11
Exercise No: 3
Logic
Aim
Objectives
ics
To analyze the logical validity of a compound proposition.
at
To evaluate the proposition using a truth table.
m
To determine whether it is a tautology, contradiction, or satisfiable.
he
Proposition:: ((P ∨ Q) ∧ (¬Q ∨ R)) → ((P ∧ R) ∨ ¬Q)
at
M
Algorithm
te
LHS: (P ∨ Q) ∧ (¬Q ∨ R)
RHS: (P ∧ R) ∨ ¬Q
6. Check if the full expression is always True (tautology), always False (contradiction), or
mixed (satisfiable).
12
Python Code
1 import pandas as pd
2 from IPython . display import display
3 def g e n e r a t e _ t r u t h _ t a b l e (* expressions ) :
4 # Extract variable names from the first expression
5 variables = list ( expressions [0][1]. __code__ . co_varnames )
6 n = len ( variables ) # Number of variables
7 rows = 2 ** n # Number of rows (2^ n )
8 # Generate all possible combinations of truth values
s
9 data = { var : [( i // (2 ** ( n - j - 1) ) ) % 2 == 1 for i in range ( rows
ic
) ] for j , var in enumerate ( variables ) }
# Apply logical expressions
at
10
em
data [ name ] = [ func (**{ var : row [ var ] for var in variables }) for row
in pd . DataFrame ( data ) . to_dict ( ’ records ’) ]
th
13 return pd . DataFrame ( data )
14 # Define the logical proposition
Ma
15 truth_table = g e n e r a t e _ t r u t h _ t a b l e (
16 ( " ( P ∨ Q ) ∧ (¬Q ∨ R ) " , lambda P , Q , R : ( P or Q ) and ( not Q or R ) ) ,
# Left - hand side of the implication
te
proposition
# Display the truth table
Di
19
20 display ( truth_table )
21 # Check if the proposition is a tautology
22 pr op os it io n_ co lu mn = truth_table [ " (( P ∨ Q ) ∧ (¬Q ∨ R ) ) → (( P ∧ R ) ∨ (¬
Q))"]
23 if all ( p ro po si ti on _c ol um n ) :
24 print ( " The proposition is a Tautology . " )
25 elif not any ( p ro po si ti on _c ol um n ) :
26 print ( " The proposition is a Contradiction . " )
13
27 else :
28 print ( " The proposition is Satisfiable . " )
(P ∨ Q) ∧ (¬P ∨ Q) is a tautology.
s
ic
1 import pandas as pd
2 from IPython . display import display
at
3
4 def g e n e r a t e _ t r u t h _ t a b l e (* expressions ) :
5
6
em
# Extract variable names from the first expression
variables = list ( expressions [0][1]. __code__ . co_varnames )
th
7 n = len ( variables ) # Number of variables
8 rows = 2 ** n # Number of rows (2^ n )
Ma
14
24 display ( truth_table )
25 # Check if the proposition is a tautology
26 pr op os it io n_ co lu mn = truth_table [ " ( P ∨ Q ) ∧ (¬P ∨ Q ) " ]
27 if all ( p ro po si ti on _c ol um n ) :
28 print ( " The proposition is a Tautology . " )
29 elif not any ( p ro po si ti on _c ol um n ) :
30 print ( " The proposition is a Contradiction . " )
31 else :
32 print ( " The proposition is Satisfiable . " )
ics
Result and Discussion
at
The analysis of the compound proposition ((P ∨ Q) ∧ (¬Q ∨ R)) → ((P ∧ R) ∨ ¬Q) using
m
Python and SymPy reveals that it evaluates to true for all possible combinations of truth
values assigned to the variables P, Q, and R. The generated truth table confirms that the final
he
column contains only True values, indicating the expression is always valid regardless of input.
at
Therefore, the proposition is a tautology, demonstrating its logical consistency and universal
M
truth in propositional.
te
Application Problem:
re
the result in terms of network reliability—i.e., under what conditions can we ensure that at
Di
least one backup or recovery system (Q or R) will function if either the primary is online or
recovery is triggered in the absence of it? Use Python to construct the truth table and justify
your conclusion.
15
Exercise No: 4
Aim
To plot and visualize basic mathematical functions including quadratic, sine, cosine, exponential,
Objectives
ics
To demonstrate the functions graphically using NumPy and Matplotlib.
at
Algorithm
m
1. Import Libraries: Import numpy as np and matplotlib.pyplot as plt.
he
2. Define Ranges of x-values:
at
Quadratic: y1 = x1 ∗ ∗2
Sine: y2 = sin(x2 )
Di
Cosine: y3 = cos(x2 )
Exponential: y4 = exp(x1 )
Logarithmic: y5 = ln(x3 )
6. Add Labels and Titles: Set axis labels and function titles.
16
7. Adjust Layout: Use plt.tight layout() to optimize spacing.
Python Code
1 import numpy as np
2 import matplotlib . pyplot as plt
3
s
functions
ic
6 x2 = np . linspace (0 , 2 * np . pi , 400) # Range for sine and cosine functions
7 x3 = np . linspace (0.1 , 10 , 400) # Range for logarithmic function
at
8
11
y1 = x1 **2
y2 = np . sin ( x2 )
em
# Quadratic function f ( x ) = x ^2
# Sine function f ( x ) = sin ( x )
th
12 y3 = np . cos ( x2 ) # Cosine function f ( x ) = cos ( x )
13 y4 = np . exp ( x1 ) # Exponential function f ( x ) = e ^ x
Ma
23 ax [0 , 0]. set_ylabel ( ’f ( x ) ’)
24 ax [0 , 0]. grid ( True )
25 ax [0 , 0]. legend ()
26
17
32 ax [0 , 1]. legend ()
33
ics
44 ax [1 , 1]. set_ylabel ( ’f ( x ) ’)
45 ax [1 , 1]. grid ( True )
at
46 ax [1 , 1]. legend ()
47
48
m
ax [2 , 0]. plot ( x3 , y5 , label = r ’ $ f ( x ) = \ ln ( x ) $ ’ , color = ’c ’)
he
49 ax [2 , 0]. set_title ( ’ Logarithmic Function : $ f ( x ) = \ ln ( x ) $ ’)
50 ax [2 , 0]. set_xlabel ( ’x ’)
at
51 ax [2 , 0]. set_ylabel ( ’f ( x ) ’)
M
58 plt . tight_layout ()
Di
18
Exponential Function: Shows exponential growth for x > 0 and decay for x < 0.
Application Problem
4
f (x) = 2x3 − 3x2 + 5 sin(x) +
x+1
models the response time of a processor node under varying system load x, where x ∈ (−0.9, 10]
to avoid division by zero. Plotting this function allows system designers to analyze critical
ics
response delays and optimize performance under different load conditions.
at
m
he
at
M
te
re
sc
Di
19
Exercise No: 5
Aim
To visualize partially ordered sets (Posets) using Hasse diagrams for better understanding of
Objectives
ics
– A set of numbers with the divisibility relation.
at
To understand hierarchical representation in partially ordered sets.
m
To implement Hasse diagram construction using Python libraries: networkx and matplotlib.
he
at
Algorithm
M
Define relation a ≤ b if a | b. Construct edges for each pair where divisibility holds.
Add edges representing the partial order (covering relations only, i.e., omit transitive
20
Convert set elements to tuples (for hashability) if needed.
s
6. Interpret the Diagram:
ic
Lower elements at the bottom.
at
Edges point upward to indicate the order relation.
No edge is drawn for transitive relations (i.e., transitively implied paths are omitted
Python Code
em
th
Divisibility Poset
Ma
4 G = nx . DiGraph ()
re
7 (4 , 12) , (6 , 12) ])
8
Di
9 pos = nx . spring_layout ( G )
10 plt . figure ( figsize =(8 , 6) )
11 nx . draw (G , pos , with_labels = True , node_size =3000 , node_color = "
lightblue " , font_size =12 , font_weight = " bold " , arrows = True )
12 plt . title ( " Hasse Diagram of Divisibility Poset " , fontsize =14)
13 plt . show ()
21
Subset Poset of {a, b, c}
1 import itertools
2 import networkx as nx
3
s
9 """
ic
10 edges = []
11 for a , b in itertools . permutations (S , 2) :
at
12 if relation (a , b ) : # a < b
# Check if there ’s no c with a < c < b
13
14
em
if not any ( relation (a , c ) and relation (c , b ) for c in S if c not in
th
(a , b ) ) :
15 edges . append (( a , b ) )
Ma
16 return edges
17
19 S = [1 , 2 , 3 , 4 , 6 , 12]
20 relation = lambda a , b : ( b % a == 0 and a != b )
re
21
22
33 # Position nodes : arrange by level
34 pos = { n : (i , levels [ n ]) for i , n in enumerate ( sorted (S , key = lambda
x : ( levels [ x ] , x ) ) ) }
35
36 # Draw
37 plt . figure ( figsize =(6 , 6) )
38 nx . draw (H , pos , with_labels = True , node_size =1500 , node_color = "
lightgreen " ,
39 font_size =12 , font_weight = " bold " , arrows = False )
s
40 plt . title ( " Hasse Diagram of Divisibility Poset {1 ,2 ,3 ,4 ,6 ,12} " )
ic
41 plt . show ()
at
Tree Structure as Hasse Diagram
2
import networkx as nx
import matplotlib . pyplot as plt
em
th
3
5 G = nx . DiGraph ()
6 G . add_edges_from ( tree_structure )
te
8 pos = {
re
9 1: (0 , 3) ,
10 2: ( -1 , 2) ,
sc
11 3: (1 , 2) ,
12 4: ( -1.5 , 1) ,
Di
13 5: ( -0.5 , 1) ,
14 6: (0.5 , 1) ,
15 7: (1.5 , 1)
16 }
17
23
20 plt . title ( " Exact Tree Structure as Hasse Diagram " , fontsize =16)
21 plt . show ()
22
23 tree_structure = [(1 , 2) , (1 , 3) , (2 , 4) , (2 , 5) , (3 , 6) , (3 , 7) ]
24 draw_exact_tree ( tree_structure )
The Hasse diagrams effectively demonstrate the hierarchical structure of partial orders:
Divisibility Poset: The diagram clearly shows how each number in {1, 2, 3, 4, 6, 12} is
ics
related via divisibility. Transitive edges are omitted to highlight the minimal covering
relations.
at
Subset Poset: The diagram illustrates how subsets of {a, b, c} are ordered by inclusion,
Application Problem
te
You are given a set of tasks and their dependencies in the form of directed edges, where each
re
Tasks: {1, 2, 3, 4, 5, 6, 7}
Di
Dependencies: [(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)]
Draw the corresponding Hasse diagram to determine a valid task execution order and un-
24
Exercise No: 6
Aim
To construct and visualize different types of directed and undirected graphs using Python
libraries (NetworkX and Matplotlib), and label their nodes and edges for clear representation.
ics
Objectives
at
To understand the structure and difference between directed and undirected graphs.
m
To use NetworkX for creating graphs and Matplotlib for visualization.
he
To apply proper labeling and styling for clarity in graphical representation.
at
To compare simple and complex graph structures using different layouts and visual fea-
M
tures.
te
3. Add nodes and directed edges using DG.add edges from() with ordered pairs.
25
6. Set the plot title using plt.title().
1 import networkx as nx
2 import matplotlib . pyplot as plt
3 # Creating a directed graph
DG = nx . DiGraph ()
s
4
ic
5 # Add nodes and edges
6 DG . add_edges_from ([(1 , 2) , (2 , 3) , (3 , 4) , (4 , 5) , (5 , 1) ])
at
7 # Plotting the directed graph with proper labeling
8 plt . figure ( figsize =(8 , 6) )
m
9 nx . draw ( DG , with_labels = True , node_size =3000 , node_color = ’ lightblue ’
he
, font_size =14 , font_weight = ’ bold ’ , arrows = True )
10 # Title for the plot
at
11 plt . title ( ’ Directed Graph Example ’ , fontsize =16)
12 plt . show ()
M
26
Pseudocode for Undirected Graph
ics
9 plt . title ( ’ Undirected Graph Example ’ , fontsize =16)
10 plt . show ()
at
Result and Discussion m
he
The implemented algorithms successfully demonstrate the creation and visualization of both
at
The directed graph displays connections with arrows, indicating one-way relationships
The undirected graph uses plain edges to represent mutual or bidirectional connections.
sc
Layout functions like spring layout enhance visual clarity and spacing between nodes.
Di
Custom node sizes, colors, and font styles improve readability and presentation.
These visualizations are vital in understanding network-based models across various com-
puter science domains, such as social networks, dependency graphs, and process workflows.
Application Problem
27
Model: Represent tasks and dependencies using a directed graph to visualize task flow and
Dependencies:
Task D → Task E
By visualizing the directed graph of task dependencies, developers can detect potential
cycles (which would indicate flawed task planning) and identify critical paths necessary for
ics
timely project completion.
at
m
he
at
M
te
re
sc
Di
28
Exercise No: 7
Aim
To represent a weighted, directed graph using both an adjacency matrix and an incidence
s
Objectives
ic
Understand how graphs can be represented using matrices.
at
Implement the adjacency matrix for a weighted, directed graph.
em
Construct the incidence matrix using the convention of −w for outgoing and +w for
incoming edges.
th
Analyse the connectivity and directionality of the graph through matrix representations.
Ma
2. Initialize:
sc
29
Pseudocode (Undirected Graph)
ics
10 adj_matrix = np . array ([
11 [0 , 1 , 1 , 0] , # Vertex 0 connections
at
12 [1 , 0 , 0 , 1] , # Vertex 1 connections
[1 , 0 , 0 , 1] , # Vertex 2 connections
13
14 [0 , 1 , 1 , 0] # Vertex 3 connections m
he
15 ])
at
16
18 print ( adj_matrix )
19
te
21
22 inc_matrix = np . array ([
sc
23 [1 , 1 , 0 , 0] , # Vertex 0
Di
24 [1 , 0 , 1 , 0] , # Vertex 1
25 [0 , 1 , 0 , 1] , # Vertex 2
26 [0 , 0 , 1 , 1] # Vertex 3
27 ])
28 print ( " \ nIncidence Matrix : " )
29 print ( inc_matrix )
30
Algorithm: Matrix Representation of a Directed Weighted Graph
2. Initialize:
s
Set adj[u][v] = w.
ic
Set inc[u][i] = −w, inc[v][i] = w.
at
4. Display the matrices.
7 # Adjacency Matrix
8 adj_matrix = np . array ([
sc
18 # Incidence Matrix
31
19 # Edges : E1 (0 -> 1 , weight 5) , E2 (1 -> 2 , weight 3) ,
20 # E3 (2 -> 3 , weight 4) , E4 (0 -> 2 , weight 6) , E5 (1 -> 3 ,
weight 2)
21 inc_matrix = np . array ([
22 [ -5 , 0, 0 , -6 , 0] , # Vertex 0 ( outgoing edges : E1 , E4 )
23 [ 5 , -3 , 0, 0 , -2] , # Vertex 1 ( incoming : E1 , outgoing : E2 , E5 )
24 [ 0, 3 , -4 , 6, 0] , # Vertex 2 ( incoming : E2 , outgoing : E3 )
25 [ 0, 0, 4, 0, 2] # Vertex 3 ( incoming : E3 , E5 )
26 ])
27 print ( " \ nIncidence Matrix : " )
28 print ( inc_matrix )
ics
29 # Analyze the graph
30 print ( " \ nAnalysis : " )
at
31 # In - degree and Out - degree
32 in_degrees = np . sum ( inc_matrix > 0 , axis =1)
m
out_degrees = np . sum ( inc_matrix < 0 , axis =1)
he
33
39
40
values divided by 2
42 print ( " Total weight of all edges : " , total_weight )
The adjacency and incidence matrices accurately represent both undirected and directed
graphs.
32
In directed graphs, the adjacency matrix is asymmetric and the incidence matrix distin-
guishes direction using signed weights (−w for source, +w for destination).
These matrix forms are useful for algorithmic graph processing and provide insight into
ics
0 → 1 : 10 Mbps
0 → 2 : 20 Mbps
at
1 → 3 : 15 Mbps
m
he
2 → 3 : 25 Mbps
at
M
te
re
sc
Di
33
Exercise No: 8
Algorithm
Aim
Objectives
s
ic
To implement and compare Prim’s and Kruskal’s algorithms for finding the Minimum Spanning
at
Tree (MST) of a weighted connected graph using Python.
property.
Ma
1 import heapq
2 heap = []
te
heapq.heappop(heap): Removes and returns the smallest element from the heap.
heapq.heappushpop(heap, item): Adds a new item to the heap and then removes and
34
1 heap = [3 , 5 , 8]
2 result = heapq . heappushpop ( heap , 4)
3 print ( result ) # Output : 3
4 print ( heap ) # Output : [4 , 5 , 8]
heapq.heapreplace(heap, item): Removes and returns the smallest element, then adds
1 heap = [3 , 5 , 8]
2 result = heapq . heapreplace ( heap , 4)
ics
3 print ( result ) # Output : 3
4 print ( heap ) # Output : [4 , 5 , 8]
at
m
heapq.heapify(iterable): Converts a list into a valid heap in-place.
he
1 nums = [5 , 3 , 8 , 1]
at
1 nums = [5 , 3 , 8 , 1]
Di
Applications of heapq
35
Dijkstra’s Algorithm: Find the shortest path in a graph.
Algorithm
Prim’s Algorithm
2. Initialize a min-heap (priority queue) with all edges from this node.
ics
3. While the MST does not contain all nodes:
at
Pick the edge with the minimum weight from the heap.
– Add all edges from this node to the heap (only those leading to unvisited nodes).
Kruskal’s Algorithm
sc
36
Pseudocode
1 import heapq
2 import matplotlib . pyplot as plt
3 import networkx as nx
4
5 # - - - - - - - - - - - - - - - - - - - Prim ’s Algorithm - - - - - - - - - - - - - - - - - - -
6 def prim_mst ( graph , start =0) :
7 n = len ( graph ) # Step 1: Count the number of vertices
8 visited = [ False ] * n # Step 2: Track visited nodes
s
9 mst_edges = [] # Step 3: Store MST edges
ic
10 total_weight = 0 # Step 4: Store total weight of MST
at
11
13
to_node , from_node )
min_heap = [(0 , start , -1) ]
em
# Step 6: Start from the source node (
th
start )
14
Ma
min weight
18 if visited [ u ]: # Step 9: Skip if already visited
re
19 continue
20 visited [ u ] = True # Step 10: Mark node as visited
sc
22
23 if prev != -1: # Step 12: If not the starting node , add edge to MST
24 mst_edges . append (( prev , u , weight ) )
25
26 # Step 13: Push all valid ( non - visited ) neighboring edges into heap
27 for v , w in enumerate ( graph [ u ]) :
28 if not visited [ v ] and w > 0:
29 heapq . heappush ( min_heap , (w , v , u ) )
30
37
31 return mst_edges , total_weight
32
33 # - - - - - - - - - - - - - - - - - - - Kruskal ’s Algorithm - - - - - - - - - - - - - - - - - - -
34 class DisjointSet :
35 def __init__ ( self , n ) :
36 self . parent = list ( range ( n ) ) # Step 1: Initialize parent to self
37 self . rank = [0] * n # Step 2: Initialize rank for union by
rank
38
s
39 def find ( self , u ) :
ic
40 if self . parent [ u ] != u : # Step 3: Path compression
41 self . parent [ u ] = self . find ( self . parent [ u ])
at
42 return self . parent [ u ]
43
44
45
def union ( self , u , v ) :
root_u = self . find ( u )
em
th
46 root_v = self . find ( v )
47
Ma
50
56
38
64
s
73 return mst_edges , total_weight
ic
74
75 # - - - - - - - - - - - - - - - - - - - Visualization Function - - - - - - - - - - - - - - - - - - -
at
76 def pl ot _g ra ph _an d_ ms t ( graph , mst_edges , title ) :
77 G = nx . Graph ()
78
82 if weight > 0:
83 G . add_edge (i , j , weight = weight )
te
84
86
39
95 nx . d ra w _ ne t w or k x _e d g es (G , pos , edgelist = mst_edges_set , edge_color = ’
red ’ , width =2)
96
s
102 # Step 1: Adjacency matrix for Prim ’s algorithm
ic
103 graph = [
104 [0 , 2 , 0 , 6 , 0] ,
at
105 [2 , 0 , 3 , 8 , 5] ,
106 [0 , 3 , 0 , 0 , 7] ,
107
108
[6 , 8 , 0 , 0 , 9] ,
[0 , 5 , 7 , 9 , 0]
em
th
109 ]
110
Ma
113
119 (0 , 1 , 2) , (1 , 2 , 3) , (0 , 3 , 6) ,
120 (1 , 3 , 8) , (1 , 4 , 5) , (2 , 4 , 7) ,
121 (3 , 4 , 9)
122 ]
123 n = 5
124 # Step 4: Convert edges to adjacency matrix for plotting
125 adj_matrix = [[0] * n for _ in range ( n ) ]
126 for u , v , w in edges :
40
127 adj_matrix [ u ][ v ] = w
128 adj_matrix [ v ][ u ] = w
129 # Step 5: Run Kruskal ’s Algorithm
130 kruskal_mst_edges , k r u s k a l _ t o t a l _ w e i g h t = kruskal_mst ( edges , n )
131 print ( " Kruskal ’s MST Edges : " , krusk al_mst _edges )
132 print ( " Total Weight : " , k r u s k a l _ t o t a l _ w e i g h t )
133 pl ot _g ra ph _a nd _m st ( adj_matrix , kruskal_mst_edges , " Kruskal ’s
Algorithm MST " )
ics
Both Prim’s and Kruskal’s algorithms successfully identified the Minimum Spanning Tree (MST)
at
of the given graph, yielding identical total weights of 16, confirming the correctness of the
m
implementations. Prim’s algorithm incrementally built the MST by selecting the smallest edge
connecting the growing tree to a new vertex, while Kruskal’s algorithm sorted all edges by weight
he
and added them one by one without forming cycles. The resulting MST edges highlight the
at
optimal connections minimizing overall edge cost. Visualization clearly distinguished the MST
M
edges in red over the original graph, demonstrating the practical applicability of both algorithms
for network design problems such as efficient road or communication link construction.
te
re
Application Problem
sc
Scenario: A government wants to build roads to connect several cities. The goal is to ensure
Di
that every city is reachable from any other city, but to minimize the total construction cost.
Input:
Possible roads between cities with their construction costs (weighted edges).
41
No cycles exist (to avoid redundant roads).
ics
at
m
he
at
M
te
re
sc
Di
42
Exercise No: 9
Aim:
Write a Python program that uses Dijkstra’s algorithm to compute the shortest path from a
given source node to all other nodes in a weighted, connected, and directed graph.
Objectives:
ics
Algorithms
at
Inputs:
m
A graph represented as an adjacency list: each node maps to a list of tuples (neighbor,
Steps:
1. Initialization:
te
Create a distance array, initialized to infinity (∞) for all nodes except the start node,
re
which is set to 0.
sc
Create a priority queue (min-heap) and insert the start node with distance 0.
Di
2. Main loop:
Extract the node with the smallest current distance from the priority queue.
For each neighbor of this node, calculate the tentative distance through the current
node.
If this distance is smaller than the currently recorded distance for the neighbor,
update the distance and record the current node as the neighbor’s predecessor.
43
Push the updated distance and neighbor into the priority queue.
3. Repeat until the priority queue is empty (all shortest distances found).
4. Path reconstruction:
To get the shortest path to any node, trace back from the target node through
Pseudocode
1 import heapq
s
2 import networkx as nx
ic
3 import matplotlib . pyplot as plt
at
4
5 # - - - - - - - - - - - - - - - - - - - Dijkstra ’s Algorithm - - - - - - - - - - - - - - - - - - -
6
7
def dijkstra ( graph , start ) :
n = len ( graph )
em
# Step 1: Total number of nodes
th
8 distances = [ float ( ’ inf ’) ] * n # Step 2: Initialize distances to
infinity
Ma
14 while priority_queue :
current_distance , current_node = heapq . heappop ( priority_queue )
Di
15
16
44
23 distance = current_distance + weight # Tentative distance via
current node
24
s
31 return distances , previous_nodes
ic
32
33 # - - - - - - - - - - - - - - - - - - - Visualization - - - - - - - - - - - - - - - - - - -
at
34 def plot_graph ( graph , shortest_distances , start_node ) :
35 G = nx . DiGraph ()
36
42
43
re
}
46 nx . draw (G , pos , with_labels = True , node_size =700 , node_color = ’ skyblue
Di
45
1) ]
54 nx . d ra w _ ne t w or k x _e d g es (G , pos , edgelist = highlight_edges , edge_color =
’ red ’ , width =2.5)
55
56 plt . title ( f " Graph with Shortest Paths from Node { start_node } " )
57 plt . show ()
58
59 # - - - - - - - - - - - - - - - - - - - Path Reconstruction - - - - - - - - - - - - - - - - - - -
60 def reconstruct_path ( target_node , start_node , previous_nodes ) :
s
61 path = []
ic
62 current = target_node
63 # Step 1: Backtrack from target to start using previous_nodes
at
64 while current is not None :
65 path . append ( current )
66
67
current = previous_nodes [ current ]
path . reverse ()
em
# Step 2: Reverse to get path from start to target
th
68 return path
69
Ma
70 # - - - - - - - - - - - - - - - - - - - Example Graph - - - - - - - - - - - - - - - - - - -
71 # Step 1: Graph is defined using adjacency list
graph = {
te
72
73 0: [(1 , 4) , (2 , 1) ] ,
re
74 1: [(3 , 1) ] ,
75 2: [(1 , 2) , (3 , 5) ] ,
sc
76 3: []
77 }
Di
78
46
85
The implemented Dijkstra’s algorithm efficiently computes the shortest paths from the source
node to all other nodes in the weighted directed graph, as demonstrated by the resulting short-
est distance array. The algorithm correctly updates distances using a priority queue, ensuring
optimal path selection with time complexity suitable for sparse graphs. Visualization high-
lights these shortest paths clearly, confirming that the algorithm identifies minimum cumula-
ics
tive weights along the routes. This approach is practical for routing and network optimization
at
Application Problem:
m
A delivery company operates in a city represented as a network of intersections (nodes) con-
nected by roads (edges), where each road has an associated travel time in minutes. The company
he
wants to find the shortest travel time routes from its central warehouse (node 0) to all other
at
delivery locations.
M
0 1 4
te
0 2 1
re
1 3 1
sc
2 1 2
2 3 5
Di
47
Exercise No: 10
Aim:
To assign colors to the nodes of a graph such that no two adjacent nodes share the same color,
Objectives:
Assign colors to each vertex of a graph such that no two adjacent vertices share the same
s
color.
ic
Minimize the total number of colors used (though greedy does not always guarantee the
at
minimum).
Ensure that coloring is done efficiently in polynomial time suitable for large graphs.
Algorithm:
te
Input: A graph G = (V, E) where V is the set of vertices and E is the set of edges.
Output: A color assignment for each vertex such that no two adjacent vertices have the same
re
colour.
sc
1. Initialize an empty dictionary color assignment to store the color assigned to each node.
Di
Select the smallest non-negative integer color that is not used by any of the neighbors.
48
Pseudocode
1 import networkx as nx
2 import matplotlib . pyplot as plt
3
s
9 # Step 2: Loop through each node in the graph
ic
10 for node in graph . nodes () :
11 # Step 3: Get the colors of all adjacent ( neighboring ) nodes
at
12 adjacent_colors = { color_assignment . get ( neighbor ) for neighbor in
graph . neighbors ( node ) }
13
14
em
# Step 4: Assign the smallest possible color ( integer ) that isn ’t
th
taken by a neighbor
15 color = 0
Ma
20 return color_assignment
21
sc
22 # - - - - - - - - - - - - - - - - - - - Visualization Function - - - - - - - - - - - - - - - - - - -
23 def pl ot _c ol or ed_ gr ap h ( graph , color_assignment ) :
Di
30 # Step 3: Draw the graph with node colors based on the color
assignment
49
31 nx . draw (
32 graph , pos , with_labels = True ,
33 node_color = colors , cmap = plt . cm . rainbow ,
34 node_size =700 , font_size =14 , font_weight = ’ bold ’ ,
35 edge_color = ’ black ’
36 )
37
ics
42 # Step 1: Define edges of the graph ( conflicting pairs )
43 edges = [(0 , 1) , (0 , 2) , (1 , 2) , (1 , 3) , (2 , 3) , (3 , 4) ]
at
44
47 G . add_edges_from ( edges )
at
48
50 color_assignment = g r e e d y _ g r a p h _ c o l o r i n g ( G )
51
te
54
56 pl ot _c ol or ed _g ra ph (G , color_assignment )
The greedy graph coloring algorithm successfully assigned colors to each node of the sample
graph such that no two adjacent nodes share the same color, using only three colors in this case.
The approach efficiently produced a valid coloring by iteratively selecting the smallest available
color for each node based on its neighbors’ colors. Although the greedy method does not always
guarantee the absolute minimum number of colors, it provides a quick and practical solution
suitable for many real-world problems like scheduling and resource allocation. The visualized
50
graph clearly highlights the distinct color assignments, demonstrating the effectiveness of the
Application Problem:
A university needs to schedule exams for 5 courses: C0, C1, C2, C3, and C4. Some courses
have students enrolled in both, so their exams cannot be scheduled at the same time to avoid
C0 and C1
C0 and C2
C1 and C2
ics
C1 and C3
at
C2 and C3
C3 and C4
m
he
The goal is to assign exam time slots to each course such that no two conflicting courses share
at
the same time slot, minimizing the total number of time slots used.
M
te
re
sc
Di
51