Spaces:
Sleeping
Sleeping
File size: 7,699 Bytes
4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a efb736b 4dfd40a |
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 |
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()
|