Spaces:
Sleeping
app.py
Browse filesimport 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")
# Now import the installed libraries
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 (as a 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 counts the number of matchings in a graph.
# For simplicity, we use a dummy value: 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):
"""
Draws the graph using a spring layout.
Only the edges are drawn (removing the blue nodes with numbers).
The title shows the index type and computed value.
"""
plt.figure(figsize=(6, 6))
pos = nx.spring_layout(graph, seed=42)
# Draw only the edges
nx.draw_networkx_edges(graph, pos, edge_color="gray")
plt.title(f"{index_type}: {round(index_value, 3)}", fontsize=14)
# Save the plot as an image and return its filename.
filename = "graph.png"
plt.savefig(filename)
plt.close()
return filename
# --- Main Processing Function ---
def process_graph(node_count, edge_count, index_type, custom_edges):
"""
Creates a graph either from random generation or from custom edge input.
Then computes the selected topological index and draws the graph.
"""
G = nx.Graph()
# If custom_edges is empty, generate a random graph with given node and edge counts.
if 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)
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")
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],
outputs=[result_box, graph_output]
)
# --- Run the App ---
if __name__ == "__main__":
demo.launch()
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import subprocess
|
| 3 |
+
|
| 4 |
+
def install(package):
|
| 5 |
+
subprocess.check_call(["pip", "install", package])
|
| 6 |
+
|
| 7 |
+
# Manually install each required library
|
| 8 |
+
install("numpy")
|
| 9 |
+
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
|
| 17 |
+
import networkx as nx
|
| 18 |
+
import matplotlib.pyplot as plt
|
| 19 |
+
import gradio as gr
|
| 20 |
+
|
| 21 |
+
# --- Topological Index Functions ---
|
| 22 |
+
|
| 23 |
+
def wiener_index(graph):
|
| 24 |
+
"""
|
| 25 |
+
Wiener Index: Sum of shortest path distances between all pairs of vertices.
|
| 26 |
+
"""
|
| 27 |
+
sp = dict(nx.all_pairs_shortest_path_length(graph))
|
| 28 |
+
total = 0
|
| 29 |
+
for u in sp:
|
| 30 |
+
for v in sp[u]:
|
| 31 |
+
if u < v:
|
| 32 |
+
total += sp[u][v]
|
| 33 |
+
return total
|
| 34 |
+
|
| 35 |
+
def compute_indices(graph, index_type):
|
| 36 |
+
if index_type == "Wiener Index":
|
| 37 |
+
return wiener_index(graph)
|
| 38 |
+
|
| 39 |
+
elif index_type == "Randić Index":
|
| 40 |
+
# Randić Index = Σ[1/√(d(u)*d(v))] for every edge (u,v)
|
| 41 |
+
return sum(1 / math.sqrt(graph.degree(u) * graph.degree(v)) for u, v in graph.edges())
|
| 42 |
+
|
| 43 |
+
elif index_type == "Balaban Index":
|
| 44 |
+
n = graph.number_of_nodes()
|
| 45 |
+
m = graph.number_of_edges()
|
| 46 |
+
if m == 0 or n <= 1:
|
| 47 |
+
return 0
|
| 48 |
+
return (m / (n - 1)) * sum(1 / math.sqrt(graph.degree(u) * graph.degree(v)) for u, v in graph.edges())
|
| 49 |
+
|
| 50 |
+
elif index_type == "Zagreb Index M1":
|
| 51 |
+
# M1 = Σ[d(v)]² over all vertices
|
| 52 |
+
return sum(d**2 for _, d in graph.degree())
|
| 53 |
+
|
| 54 |
+
elif index_type == "Zagreb Index M2":
|
| 55 |
+
# M2 = Σ[d(u)*d(v)] for every edge (u,v)
|
| 56 |
+
return sum(graph.degree(u) * graph.degree(v) for u, v in graph.edges())
|
| 57 |
+
|
| 58 |
+
elif index_type == "Harary Index":
|
| 59 |
+
# H = Σ[1 / d(u,v)] for all distinct vertex pairs
|
| 60 |
+
return sum(1 / nx.shortest_path_length(graph, u, v)
|
| 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 |
+
|
| 68 |
+
elif index_type == "Gutman Index":
|
| 69 |
+
# Gutman Index = Σ[d(u)*d(v)*d(u,v)] over all edges
|
| 70 |
+
return sum(graph.degree(u) * graph.degree(v) * nx.shortest_path_length(graph, u, v)
|
| 71 |
+
for u, v in graph.edges())
|
| 72 |
+
|
| 73 |
+
elif index_type == "Estrada Index":
|
| 74 |
+
# Estrada Index = Σ(exp(λ)) over all eigenvalues of the adjacency matrix.
|
| 75 |
+
A = nx.adjacency_matrix(graph).todense()
|
| 76 |
+
eigenvalues = np.linalg.eigvals(A)
|
| 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:
|
| 85 |
+
return "Invalid 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:
|
| 122 |
+
edges = [tuple(map(int, e.strip().split("-"))) for e in custom_edges.split(",")]
|
| 123 |
+
all_nodes = set()
|
| 124 |
+
for u, v in edges:
|
| 125 |
+
all_nodes.update([u, v])
|
| 126 |
+
n = max(all_nodes) + 1
|
| 127 |
+
G = nx.Graph()
|
| 128 |
+
G.add_nodes_from(range(n))
|
| 129 |
+
G.add_edges_from(edges)
|
| 130 |
+
except Exception as e:
|
| 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 ---
|
| 138 |
+
|
| 139 |
+
with gr.Blocks() as demo:
|
| 140 |
+
gr.Markdown("# Topological Index Calculator with Graph Visualization")
|
| 141 |
+
|
| 142 |
+
with gr.Row():
|
| 143 |
+
node_count = gr.Number(label="Number of Nodes", value=5, minimum=1)
|
| 144 |
+
edge_count = gr.Number(label="Number of Edges", value=5, minimum=0)
|
| 145 |
+
|
| 146 |
+
index_type = gr.Dropdown(
|
| 147 |
+
choices=["Wiener Index", "Randić Index", "Balaban Index", "Zagreb Index M1", "Zagreb Index M2",
|
| 148 |
+
"Harary Index", "Schultz Index", "Gutman Index", "Estrada Index", "Hosoya Index"],
|
| 149 |
+
label="Select Topological Index"
|
| 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 |
+
|
| 164 |
+
# --- Run the App ---
|
| 165 |
+
|
| 166 |
+
if __name__ == "__main__":
|
| 167 |
+
demo.launch()
|