import os import subprocess def install(package): subprocess.check_call(["pip", "install", package]) # Install dependencies 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): 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": 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": return sum(d**2 for _, d in graph.degree()) elif index_type == "Zagreb Index M2": return sum(graph.degree(u) * graph.degree(v) for u, v in graph.edges()) elif index_type == "Harary Index": return sum(1 / nx.shortest_path_length(graph, u, v) for u, v in itertools.combinations(graph.nodes(), 2)) elif index_type == "Schultz Index": 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": 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": 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": return graph.number_of_edges() else: return "Invalid Index Type" # --- Graph Drawing Function --- def draw_graph(graph, index_type, index_value): plt.figure(figsize=(6, 6)) # Fixed layout for more consistent shapes pos = nx.spring_layout(graph, seed=42) # Draw only edges (no nodes, no labels) nx.draw_networkx_edges(graph, pos, edge_color="gray", width=2) plt.title(f"{index_type}: {round(index_value, 3)}", fontsize=14) plt.axis('off') filename = "graph.png" plt.savefig(filename, bbox_inches='tight') plt.close() return filename # --- Main Logic --- def process_graph(node_count, edge_count, index_type, custom_edges): G = nx.Graph() 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.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 App --- 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()