summrs commited on
Commit
efb736b
·
verified ·
1 Parent(s): 4dfd40a

import os
import subprocess

def install(package):
subprocess.check_call(["pip", "install", package])

# Manually install each required library
install("numpy")
install("networkx")
install("matplotlib")
install("gradio")

import math
import itertools
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import gradio as gr

# --- Topological Index Functions ---

def wiener_index(graph):
"""
Wiener Index: Sum of shortest path distances between all pairs of vertices.
"""
sp = dict(nx.all_pairs_shortest_path_length(graph))
total = 0
for u in sp:
for v in sp[u]:
if u < v:
total += sp[u][v]
return total

def compute_indices(graph, index_type):
if index_type == "Wiener Index":
return wiener_index(graph)

elif index_type == "Randić Index":
# Randić Index = Σ[1/√(d(u)*d(v))] for every edge (u,v)
return sum(1 / math.sqrt(graph.degree(u) * graph.degree(v)) for u, v in graph.edges())

elif index_type == "Balaban Index":
n = graph.number_of_nodes()
m = graph.number_of_edges()
if m == 0 or n <= 1:
return 0
return (m / (n - 1)) * sum(1 / math.sqrt(graph.degree(u) * graph.degree(v)) for u, v in graph.edges())

elif index_type == "Zagreb Index M1":
# M1 = Σ[d(v)]² over all vertices
return sum(d**2 for _, d in graph.degree())

elif index_type == "Zagreb Index M2":
# M2 = Σ[d(u)*d(v)] for every edge (u,v)
return sum(graph.degree(u) * graph.degree(v) for u, v in graph.edges())

elif index_type == "Harary Index":
# H = Σ[1 / d(u,v)] for all distinct vertex pairs
return sum(1 / nx.shortest_path_length(graph, u, v)
for u, v in itertools.combinations(graph.nodes(), 2))

elif index_type == "Schultz Index":
# Schultz Index = Σ[(d(u)+d(v))*d(u,v)] over all edges (simplified version)
return sum((graph.degree(u) + graph.degree(v)) * nx.shortest_path_length(graph, u, v)
for u, v in graph.edges())

elif index_type == "Gutman Index":
# Gutman Index = Σ[d(u)*d(v)*d(u,v)] over all edges
return sum(graph.degree(u) * graph.degree(v) * nx.shortest_path_length(graph, u, v)
for u, v in graph.edges())

elif index_type == "Estrada Index":
# Estrada Index = Σ(exp(λ)) over all eigenvalues of the adjacency matrix.
A = nx.adjacency_matrix(graph).todense()
eigenvalues = np.linalg.eigvals(A)
return sum(math.exp(ev) for ev in eigenvalues)

elif index_type == "Hosoya Index":
# Hosoya Index is the number of matchings; here we use the number of edges.
return graph.number_of_edges()

else:
return "Invalid Index Type"

# --- Graph Visualization Function ---

def draw_graph(graph, index_type, index_value, is_regular=False, expected_degree=None):
"""
Draws the graph using a spring layout.
If is_regular is True, it checks each node:
- Nodes with degree equal to expected_degree receive a red marker.
- The plot title also indicates whether the graph is regular or not.
"""
plt.figure(figsize=(6, 6))
pos = nx.spring_layout(graph, seed=42)

# Draw the edges
nx.draw_networkx_edges(graph, pos, edge_color="gray")

# Set up default node color (light blue)
node_colors = ['lightblue' for _ in graph.nodes()]

regular_flag = None
if is_regular and expected_degree is not None:
# Check each node if it meets the expected degree
regular_flag = all(graph.degree(n) == expected_degree for n in graph.nodes())
# Draw a red dot on nodes that meet the expected degree.
for n in graph.nodes():
if graph.degree(n) == expected_degree:
x, y = pos[n]
plt.scatter(x, y, c="red", s=100, zorder=3)

# Construct title text
title_text = f"{index_type}: {round(index_value, 3)}"
if is_regular and expected_degree is not None:
if regular_flag:
title_text += " | Regular Graph"
else:
title_text += " | Not Regular"

plt.title(title_text, fontsize=14)

filename = "graph.png"
plt.savefig(filename)
plt.close()
return filename

# --- Extended Main Processing Function with Regular Graph Feature ---

def process_graph(node_count, edge_count, index_type, custom_edges, is_regular, degree):
G = nx.Graph()
if is_regular:
try:
n = int(node_count)
d = int(degree)
# Validate that the degree is less than the number of nodes.
if d >= n:
return "Error: 'Degree per Node' must be less than 'Number of Nodes'.", None
# Validate that (n*d) is even.
if (n * d) % 2 != 0:
return "Error: (Nodes × Degree) must be even for a valid regular graph.", None
G = nx.random_regular_graph(d, n)
except Exception as e:
return f"Error generating regular graph: {e}", None
elif not custom_edges.strip():
G = nx.gnm_random_graph(int(node_count), int(edge_count))
else:
try:
edges = [tuple(map(int, e.strip().split("-"))) for e in custom_edges.split(",")]
all_nodes = set()
for u, v in edges:
all_nodes.update([u, v])
n = max(all_nodes) + 1
G = nx.Graph()
G.add_nodes_from(range(n))
G.add_edges_from(edges)
except Exception as e:
return f"Error in custom edges input: {e}", None

index_value = compute_indices(G, index_type)

# If regular graph mode, pass the expected degree to the drawing function.
if is_regular:
graph_img = draw_graph(G, index_type, index_value, is_regular=True, expected_degree=int(degree))
else:
graph_img = draw_graph(G, index_type, index_value)

return index_value, graph_img

# --- Gradio Interface Setup ---

with gr.Blocks() as demo:
gr.Markdown("# Topological Index Calculator with Graph Visualization")

with gr.Row():
node_count = gr.Number(label="Number of Nodes", value=5, minimum=1)
edge_count = gr.Number(label="Number of Edges", value=5, minimum=0)

index_type = gr.Dropdown(
choices=["Wiener Index", "Randić Index", "Balaban Index", "Zagreb Index M1", "Zagreb Index M2",
"Harary Index", "Schultz Index", "Gutman Index", "Estrada Index", "Hosoya Index"],
label="Select Topological Index"
)

custom_edges = gr.Textbox(label="Custom Edges (e.g., 0-1,1-2,2-3)", placeholder="Leave blank for random graph")

with gr.Row():
regular_graph_checkbox = gr.Checkbox(label="Generate Regular Graph?", value=False)
degree_input = gr.Number(label="Degree per Node", value=2, minimum=1, visible=False)

def toggle_degree_input(is_checked):
return gr.update(visible=is_checked)

regular_graph_checkbox.change(
toggle_degree_input,
inputs=regular_graph_checkbox,
outputs=degree_input
)

calc_button = gr.Button("Calculate & Visualize")
result_box = gr.Textbox(label="Computed Index Value", interactive=False)
graph_output = gr.Image(label="Graph Visualization", interactive=False)

calc_button.click(
fn=process_graph,
inputs=[node_count, edge_count, index_type, custom_edges, regular_graph_checkbox, degree_input],
outputs=[result_box, graph_output]
)

# --- Run the App ---

if __name__ == "__main__":
demo.launch()

Files changed (1) hide show
  1. app.py +67 -21
app.py CHANGED
@@ -10,7 +10,6 @@ install("networkx")
10
  install("matplotlib")
11
  install("gradio")
12
 
13
- # Now import the installed libraries
14
  import math
15
  import itertools
16
  import numpy as np
@@ -61,7 +60,7 @@ def compute_indices(graph, index_type):
61
  for u, v in itertools.combinations(graph.nodes(), 2))
62
 
63
  elif index_type == "Schultz Index":
64
- # Schultz Index = Σ[(d(u)+d(v))*d(u,v)] over all edges (as a simplified version)
65
  return sum((graph.degree(u) + graph.degree(v)) * nx.shortest_path_length(graph, u, v)
66
  for u, v in graph.edges())
67
 
@@ -77,8 +76,7 @@ def compute_indices(graph, index_type):
77
  return sum(math.exp(ev) for ev in eigenvalues)
78
 
79
  elif index_type == "Hosoya Index":
80
- # Hosoya Index counts the number of matchings in a graph.
81
- # For simplicity, we use a dummy value: the number of edges.
82
  return graph.number_of_edges()
83
 
84
  else:
@@ -86,36 +84,65 @@ def compute_indices(graph, index_type):
86
 
87
  # --- Graph Visualization Function ---
88
 
89
- def draw_graph(graph, index_type, index_value):
90
  """
91
  Draws the graph using a spring layout.
92
- Only the edges are drawn (removing the blue nodes with numbers).
93
- The title shows the index type and computed value.
 
94
  """
95
  plt.figure(figsize=(6, 6))
96
  pos = nx.spring_layout(graph, seed=42)
97
 
98
- # Draw only the edges
99
  nx.draw_networkx_edges(graph, pos, edge_color="gray")
100
 
101
- plt.title(f"{index_type}: {round(index_value, 3)}", fontsize=14)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- # Save the plot as an image and return its filename.
104
  filename = "graph.png"
105
  plt.savefig(filename)
106
  plt.close()
107
  return filename
108
 
109
- # --- Main Processing Function ---
110
 
111
- def process_graph(node_count, edge_count, index_type, custom_edges):
112
- """
113
- Creates a graph either from random generation or from custom edge input.
114
- Then computes the selected topological index and draws the graph.
115
- """
116
  G = nx.Graph()
117
- # If custom_edges is empty, generate a random graph with given node and edge counts.
118
- if not custom_edges.strip():
 
 
 
 
 
 
 
 
 
 
 
 
119
  G = nx.gnm_random_graph(int(node_count), int(edge_count))
120
  else:
121
  try:
@@ -131,7 +158,13 @@ def process_graph(node_count, edge_count, index_type, custom_edges):
131
  return f"Error in custom edges input: {e}", None
132
 
133
  index_value = compute_indices(G, index_type)
134
- graph_img = draw_graph(G, index_type, index_value)
 
 
 
 
 
 
135
  return index_value, graph_img
136
 
137
  # --- Gradio Interface Setup ---
@@ -150,14 +183,27 @@ with gr.Blocks() as demo:
150
  )
151
 
152
  custom_edges = gr.Textbox(label="Custom Edges (e.g., 0-1,1-2,2-3)", placeholder="Leave blank for random graph")
153
-
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  calc_button = gr.Button("Calculate & Visualize")
155
  result_box = gr.Textbox(label="Computed Index Value", interactive=False)
156
  graph_output = gr.Image(label="Graph Visualization", interactive=False)
157
 
158
  calc_button.click(
159
  fn=process_graph,
160
- inputs=[node_count, edge_count, index_type, custom_edges],
161
  outputs=[result_box, graph_output]
162
  )
163
 
 
10
  install("matplotlib")
11
  install("gradio")
12
 
 
13
  import math
14
  import itertools
15
  import numpy as np
 
60
  for u, v in itertools.combinations(graph.nodes(), 2))
61
 
62
  elif index_type == "Schultz Index":
63
+ # Schultz Index = Σ[(d(u)+d(v))*d(u,v)] over all edges (simplified version)
64
  return sum((graph.degree(u) + graph.degree(v)) * nx.shortest_path_length(graph, u, v)
65
  for u, v in graph.edges())
66
 
 
76
  return sum(math.exp(ev) for ev in eigenvalues)
77
 
78
  elif index_type == "Hosoya Index":
79
+ # Hosoya Index is the number of matchings; here we use the number of edges.
 
80
  return graph.number_of_edges()
81
 
82
  else:
 
84
 
85
  # --- Graph Visualization Function ---
86
 
87
+ def draw_graph(graph, index_type, index_value, is_regular=False, expected_degree=None):
88
  """
89
  Draws the graph using a spring layout.
90
+ If is_regular is True, it checks each node:
91
+ - Nodes with degree equal to expected_degree receive a red marker.
92
+ - The plot title also indicates whether the graph is regular or not.
93
  """
94
  plt.figure(figsize=(6, 6))
95
  pos = nx.spring_layout(graph, seed=42)
96
 
97
+ # Draw the edges
98
  nx.draw_networkx_edges(graph, pos, edge_color="gray")
99
 
100
+ # Set up default node color (light blue)
101
+ node_colors = ['lightblue' for _ in graph.nodes()]
102
+
103
+ regular_flag = None
104
+ if is_regular and expected_degree is not None:
105
+ # Check each node if it meets the expected degree
106
+ regular_flag = all(graph.degree(n) == expected_degree for n in graph.nodes())
107
+ # Draw a red dot on nodes that meet the expected degree.
108
+ for n in graph.nodes():
109
+ if graph.degree(n) == expected_degree:
110
+ x, y = pos[n]
111
+ plt.scatter(x, y, c="red", s=100, zorder=3)
112
+
113
+ # Construct title text
114
+ title_text = f"{index_type}: {round(index_value, 3)}"
115
+ if is_regular and expected_degree is not None:
116
+ if regular_flag:
117
+ title_text += " | Regular Graph"
118
+ else:
119
+ title_text += " | Not Regular"
120
+
121
+ plt.title(title_text, fontsize=14)
122
 
 
123
  filename = "graph.png"
124
  plt.savefig(filename)
125
  plt.close()
126
  return filename
127
 
128
+ # --- Extended Main Processing Function with Regular Graph Feature ---
129
 
130
+ def process_graph(node_count, edge_count, index_type, custom_edges, is_regular, degree):
 
 
 
 
131
  G = nx.Graph()
132
+ if is_regular:
133
+ try:
134
+ n = int(node_count)
135
+ d = int(degree)
136
+ # Validate that the degree is less than the number of nodes.
137
+ if d >= n:
138
+ return "Error: 'Degree per Node' must be less than 'Number of Nodes'.", None
139
+ # Validate that (n*d) is even.
140
+ if (n * d) % 2 != 0:
141
+ return "Error: (Nodes × Degree) must be even for a valid regular graph.", None
142
+ G = nx.random_regular_graph(d, n)
143
+ except Exception as e:
144
+ return f"Error generating regular graph: {e}", None
145
+ elif not custom_edges.strip():
146
  G = nx.gnm_random_graph(int(node_count), int(edge_count))
147
  else:
148
  try:
 
158
  return f"Error in custom edges input: {e}", None
159
 
160
  index_value = compute_indices(G, index_type)
161
+
162
+ # If regular graph mode, pass the expected degree to the drawing function.
163
+ if is_regular:
164
+ graph_img = draw_graph(G, index_type, index_value, is_regular=True, expected_degree=int(degree))
165
+ else:
166
+ graph_img = draw_graph(G, index_type, index_value)
167
+
168
  return index_value, graph_img
169
 
170
  # --- Gradio Interface Setup ---
 
183
  )
184
 
185
  custom_edges = gr.Textbox(label="Custom Edges (e.g., 0-1,1-2,2-3)", placeholder="Leave blank for random graph")
186
+
187
+ with gr.Row():
188
+ regular_graph_checkbox = gr.Checkbox(label="Generate Regular Graph?", value=False)
189
+ degree_input = gr.Number(label="Degree per Node", value=2, minimum=1, visible=False)
190
+
191
+ def toggle_degree_input(is_checked):
192
+ return gr.update(visible=is_checked)
193
+
194
+ regular_graph_checkbox.change(
195
+ toggle_degree_input,
196
+ inputs=regular_graph_checkbox,
197
+ outputs=degree_input
198
+ )
199
+
200
  calc_button = gr.Button("Calculate & Visualize")
201
  result_box = gr.Textbox(label="Computed Index Value", interactive=False)
202
  graph_output = gr.Image(label="Graph Visualization", interactive=False)
203
 
204
  calc_button.click(
205
  fn=process_graph,
206
+ inputs=[node_count, edge_count, index_type, custom_edges, regular_graph_checkbox, degree_input],
207
  outputs=[result_box, graph_output]
208
  )
209