File size: 17,251 Bytes
b39c815
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
import subprocess
import math
import gradio as gr

# Ensure required packages are installed
def install(package):
    subprocess.check_call(["pip", "install", package])

install("gradio")

# =========================
# Mathematical Formulas (from the paper and our implementation)
# =========================
formulas = {
    "Wiener Index (W)":
        "W = Σ d(u,v)\nwhere d(u,v) is the shortest-path distance between every unordered pair of vertices.",
    "First Zagreb Index (M₁)":
        "M₁ = Σ [deg(v)]  for v ∈ V(G)\n(This sums the degrees of all vertices.)",
    "Second Zagreb Index (M₂)":
        "M₂ = Σ [deg(u) × deg(v)] for each edge uv ∈ E(G)\n(This sums the product of the degrees for each edge.)",
    "Randić Index (R)":
        "R = Σ [1 / √(deg(u) × deg(v))] for each edge uv ∈ E(G)\n(This measures connectivity by using the inverse square root of vertex degree products.)",
    "Atom-Bond Connectivity Index (ABC)":
        "ABC = Σ √((deg(u)+deg(v)-2)/(deg(u)×deg(v))) for each edge uv ∈ E(G)\n(This index relates to the molecular stability in chemical graphs.)",
    "Augmented Zagreb Index (AZI)":
        "AZI = Σ [(deg(u)×deg(v))/(deg(u)+deg(v)-2)]³ for each edge uv ∈ E(G)\n(This index amplifies the contribution of high-degree vertices.)",
    "Geometric-Arithmetic Index (GA)":
        "GA = Σ [2×√(deg(u)×deg(v))/(deg(u)+deg(v))] for each edge uv ∈ E(G)\n(This index blends the geometric and arithmetic means of vertex degrees.)",
    "Sum-Connectivity Index (SCI)":
        "SCI = Σ [1/√(deg(u)+deg(v))] for each edge uv ∈ E(G)\n(This index focuses on the sum of the degrees.)",
    "Harmonic Index (Harm)":
        "Harm = Σ [2/(deg(u)+deg(v))] for each edge uv ∈ E(G)\n(A measure emphasizing balanced degrees.)",
    "Gutman Index (Gut)":
        "Gut = Σ [deg(u)×deg(v)×d(u,v)] for every unordered pair u,v\n(This index combines connectivity with distance information.)",
    "Eccentric Connectivity Index (ECI)":
        "ECI = Σ [deg(v)×ecc(v)] for every vertex v\n(Here, ecc(v) is the maximum distance from v to any other vertex.)",
    "Total Eccentricity (TE)":
        "TE = Σ [ecc(v)] for every vertex v\n(This sums the eccentricity of each vertex.)",
    "Harary Index (H)":
        "H = Σ [1/d(u,v)] for every unordered pair u,v\n(This sums the reciprocals of distances for each vertex pair.)"
}

# ==========================
# Functions to update which input groups are visible based on the selected index
# ==========================
def update_inputs(selected_index):
    # Indices that use vertex-based values only: M₁, TE, ECI.
    vertex_vis = selected_index in ["First Zagreb Index (M₁)", "Total Eccentricity (TE)",
                                     "Eccentric Connectivity Index (ECI)"]
    # Indices that use edge-based inputs: M₂, R, ABC, AZI, GA, SCI, Harm.
    edge_vis = selected_index in ["Second Zagreb Index (M₂)",
                                   "Randić Index (R)",
                                   "Atom-Bond Connectivity Index (ABC)",
                                   "Augmented Zagreb Index (AZI)",
                                   "Geometric-Arithmetic Index (GA)",
                                   "Sum-Connectivity Index (SCI)",
                                   "Harmonic Index (Harm)"]
    # Gutman index uses its own group.
    gutman_vis = (selected_index == "Gutman Index (Gut)")
    # Wiener and Harary indices use distance inputs.
    distance_vis = selected_index in ["Wiener Index (W)", "Harary Index (H)"]
    return (
        gr.update(visible=vertex_vis),
        gr.update(visible=edge_vis),
        gr.update(visible=gutman_vis),
        gr.update(visible=distance_vis)
    )

# ==========================
# Calculation Functions
# (For simplicity, we assume a triangle graph with 3 vertices, 3 edges, and 3 unordered pairs.)
# ==========================
def solve_index(selected_index, vertex_deg1, vertex_deg2, vertex_deg3,
                vertex_ecc1, vertex_ecc2, vertex_ecc3,
                edge1_a, edge1_b, edge2_a, edge2_b, edge3_a, edge3_b,
                gutman_degs, gutman_dists,
                distance1, distance2, distance3):
    try:
        # -----------------------
        # Vertex-based Calculations
        # -----------------------
        if selected_index == "First Zagreb Index (M₁)":
            degrees = [vertex_deg1, vertex_deg2, vertex_deg3]
            result = sum(degrees)
            steps = [
                f"Step 1: Record the degree of each vertex: {degrees}.",
                f"Step 2: Sum all vertex degrees since M₁ is defined as Σ deg(v): {degrees[0]} + {degrees[1]} + {degrees[2]} = {result}."
            ]
            return f"### First Zagreb Index (M₁)\n{formulas[selected_index]}\n\nDetailed Steps:\n" + "\n".join(steps)
        
        elif selected_index == "Total Eccentricity (TE)":
            ecc = [vertex_ecc1, vertex_ecc2, vertex_ecc3]
            result = sum(ecc)
            steps = [
                f"Step 1: Record the eccentricity (maximum distance) for each vertex: {ecc}.",
                f"Step 2: Sum all eccentricities since TE is defined as Σ ecc(v): {ecc[0]} + {ecc[1]} + {ecc[2]} = {result}."
            ]
            return f"### Total Eccentricity (TE)\n{formulas[selected_index]}\n\nDetailed Steps:\n" + "\n".join(steps)
        
        elif selected_index == "Eccentric Connectivity Index (ECI)":
            pairs = [(vertex_deg1, vertex_ecc1), (vertex_deg2, vertex_ecc2), (vertex_deg3, vertex_ecc3)]
            contributions = [d * e for d, e in pairs]
            result = sum(contributions)
            steps = [
                f"Step 1: For each vertex, record the pair (degree, eccentricity): {pairs}.",
                f"Step 2: Multiply the degree and eccentricity for each vertex: {contributions} (because ECI = Σ [deg(v)×ecc(v)]).",
                f"Step 3: Sum these products: {contributions[0]} + {contributions[1]} + {contributions[2]} = {result}."
            ]
            return f"### Eccentric Connectivity Index (ECI)\n{formulas[selected_index]}\n\nDetailed Steps:\n" + "\n".join(steps)
        
        # -----------------------
        # Edge-based Calculations
        # -----------------------
        elif selected_index in ["Second Zagreb Index (M₂)", "Randić Index (R)",
                                 "Atom-Bond Connectivity Index (ABC)", "Augmented Zagreb Index (AZI)",
                                 "Geometric-Arithmetic Index (GA)", "Sum-Connectivity Index (SCI)",
                                 "Harmonic Index (Harm)"]:
            edges = [(edge1_a, edge1_b), (edge2_a, edge2_b), (edge3_a, edge3_b)]
            if selected_index == "Second Zagreb Index (M₂)":
                products = [a * b for a, b in edges]
                result = sum(products)
                steps = [
                    f"Step 1: Each edge connects two vertices with degrees as given: {edges}.",
                    f"Step 2: For each edge, multiply the degrees: {products} (since M₂ sums the product for each edge).",
                    f"Step 3: Sum these products: {products[0]} + {products[1]} + {products[2]} = {result}."
                ]
            elif selected_index == "Randić Index (R)":
                values = [1 / math.sqrt(a * b) for a, b in edges]
                result = sum(values)
                steps = [
                    f"Step 1: Record the degree pairs for each edge: {edges}.",
                    f"Step 2: For each edge, compute 1/√(deg(u)×deg(v)): {['{:.4f}'.format(v) for v in values]}.",
                    f"Step 3: Sum these values to obtain R: {result:.4f}."
                ]
            elif selected_index == "Atom-Bond Connectivity Index (ABC)":
                values = [math.sqrt((a + b - 2) / (a * b)) for a, b in edges]
                result = sum(values)
                steps = [
                    f"Step 1: For each edge, note the degree pair: {edges}.",
                    f"Step 2: Compute √((deg(u)+deg(v)-2)/(deg(u)×deg(v))) for each edge: {['{:.4f}'.format(v) for v in values]}.",
                    f"Step 3: Sum the results: {result:.4f}."
                ]
            elif selected_index == "Augmented Zagreb Index (AZI)":
                values = []
                for a, b in edges:
                    denom = a + b - 2
                    val = (a * b / denom) ** 3 if denom != 0 else 0
                    values.append(val)
                result = sum(values)
                steps = [
                    f"Step 1: For each edge, record degrees: {edges}.",
                    f"Step 2: For each, compute ( (deg(u)×deg(v))/(deg(u)+deg(v)-2) )³: {['{:.4f}'.format(v) for v in values]}.",
                    f"Step 3: Sum these values: {result:.4f}."
                ]
            elif selected_index == "Geometric-Arithmetic Index (GA)":
                values = [(2 * math.sqrt(a * b))/(a + b) for a, b in edges]
                result = sum(values)
                steps = [
                    f"Step 1: Record edge degree pairs: {edges}.",
                    f"Step 2: For each edge, calculate 2×√(deg(u)×deg(v))/(deg(u)+deg(v)): {['{:.4f}'.format(v) for v in values]}.",
                    f"Step 3: Sum to obtain GA: {result:.4f}."
                ]
            elif selected_index == "Sum-Connectivity Index (SCI)":
                values = [1 / math.sqrt(a + b) for a, b in edges]
                result = sum(values)
                steps = [
                    f"Step 1: Note the degree pairs for each edge: {edges}.",
                    f"Step 2: For each edge, compute 1/√(deg(u)+deg(v)): {['{:.4f}'.format(v) for v in values]}.",
                    f"Step 3: Sum the computed values to get SCI: {result:.4f}."
                ]
            elif selected_index == "Harmonic Index (Harm)":
                values = [2 / (a + b) for a, b in edges]
                result = sum(values)
                steps = [
                    f"Step 1: Record the edge degree pairs: {edges}.",
                    f"Step 2: For each edge, compute 2/(deg(u)+deg(v)): {['{:.4f}'.format(v) for v in values]}.",
                    f"Step 3: Sum these values for the final Harmonic Index: {result:.4f}."
                ]
            return f"### {selected_index}\n{formulas[selected_index]}\n\nDetailed Steps:\n" + "\n".join(steps)
        
        # -----------------------
        # Gutman Index: Requires vertex degrees and distances
        # -----------------------
        elif selected_index == "Gutman Index (Gut)":
            degs = [float(x) for x in gutman_degs.split(',')]
            dists = [float(x) for x in gutman_dists.split(',')]
            # For a triangle, the unordered pairs are (1,2), (1,3), and (2,3)
            total = degs[0]*degs[1]*dists[0] + degs[0]*degs[2]*dists[1] + degs[1]*degs[2]*dists[2]
            steps = [
                f"Step 1: The vertex degrees are recorded as: {degs}.",
                f"Step 2: The shortest-path distances for unordered vertex pairs (1,2), (1,3), and (2,3) are: {dists}.",
                f"Step 3: For each pair, multiply deg(u)×deg(v)×d(u,v):",
                f"        For (1,2): {degs[0]}×{degs[1]}×{dists[0]} = {degs[0]*degs[1]*dists[0]},",
                f"        For (1,3): {degs[0]}×{degs[2]}×{dists[1]} = {degs[0]*degs[2]*dists[1]},",
                f"        For (2,3): {degs[1]}×{degs[2]}×{dists[2]} = {degs[1]*degs[2]*dists[2]}.",
                f"Step 4: Sum all products: {total}."
            ]
            return f"### Gutman Index (Gut)\n{formulas[selected_index]}\n\nDetailed Steps:\n" + "\n".join(steps)
        
        # -----------------------
        # Distance-based: Wiener and Harary indices
        # -----------------------
        elif selected_index in ["Wiener Index (W)", "Harary Index (H)"]:
            dists = [distance1, distance2, distance3]
            if selected_index == "Wiener Index (W)":
                result = sum(dists)
                steps = [
                    f"Step 1: Record the shortest-path distances for each unordered pair: {dists}.",
                    f"Step 2: Sum all distances: {dists[0]} + {dists[1]} + {dists[2]} = {result}."
                ]
                return f"### Wiener Index (W)\n{formulas[selected_index]}\n\nDetailed Steps:\n" + "\n".join(steps)
            else:  # Harary Index (H)
                values = [1/d if d != 0 else 0 for d in dists]
                result = sum(values)
                steps = [
                    f"Step 1: Record the shortest-path distances: {dists}.",
                    f"Step 2: Compute the reciprocal for each distance (1/d): {['{:.4f}'.format(1/d) if d!=0 else 'undefined' for d in dists]}.",
                    f"Step 3: Sum these reciprocals: {result:.4f}."
                ]
                return f"### Harary Index (H)\n{formulas[selected_index]}\n\nDetailed Steps:\n" + "\n".join(steps)
        else:
            return "Index not recognized."
    except Exception as e:
        return f"Error: {e}"

# ==========================
# Build the Gradio Interface with Dynamic Input Groups
# ==========================
with gr.Blocks() as demo:
    gr.Markdown("## Topological Index Calculator\n\nSelect an index and enter the required values in the relevant fields. The fields below will change based on the chosen index. (For illustration, this example uses a fixed triangle graph with 3 vertices, 3 edges, and 3 unordered pairs.)")
    
    index_dropdown = gr.Dropdown(
        label="Select an Index", 
        choices=[
            "Wiener Index (W)",
            "First Zagreb Index (M₁)",
            "Second Zagreb Index (M₂)",
            "Randić Index (R)",
            "Atom-Bond Connectivity Index (ABC)",
            "Augmented Zagreb Index (AZI)",
            "Geometric-Arithmetic Index (GA)",
            "Sum-Connectivity Index (SCI)",
            "Harmonic Index (Harm)",
            "Gutman Index (Gut)",
            "Eccentric Connectivity Index (ECI)",
            "Total Eccentricity (TE)",
            "Harary Index (H)"
        ]
    )
    
    # Group 1: Vertex-based inputs (for M₁, TE, ECI)
    with gr.Group(visible=False) as vertex_group:
        gr.Markdown("### Vertex Inputs\nEnter the degree and/or eccentricity for each vertex.")
        vertex_deg1 = gr.Number(label="Vertex 1 Degree", value=2)
        vertex_deg2 = gr.Number(label="Vertex 2 Degree", value=2)
        vertex_deg3 = gr.Number(label="Vertex 3 Degree", value=2)
        vertex_ecc1 = gr.Number(label="Vertex 1 Eccentricity", value=1)
        vertex_ecc2 = gr.Number(label="Vertex 2 Eccentricity", value=1)
        vertex_ecc3 = gr.Number(label="Vertex 3 Eccentricity", value=1)
    
    # Group 2: Edge-based inputs (for M₂, R, ABC, AZI, GA, SCI, Harm)
    with gr.Group(visible=False) as edge_group:
        gr.Markdown("### Edge Inputs\nFor each edge, enter the degree of each end vertex.")
        with gr.Row():
            edge1_a = gr.Number(label="Edge 1: Vertex A Degree", value=2)
            edge1_b = gr.Number(label="Edge 1: Vertex B Degree", value=2)
        with gr.Row():
            edge2_a = gr.Number(label="Edge 2: Vertex A Degree", value=2)
            edge2_b = gr.Number(label="Edge 2: Vertex B Degree", value=2)
        with gr.Row():
            edge3_a = gr.Number(label="Edge 3: Vertex A Degree", value=2)
            edge3_b = gr.Number(label="Edge 3: Vertex B Degree", value=2)
    
    # Group 3: Gutman inputs (for Gutman Index)
    with gr.Group(visible=False) as gutman_group:
        gr.Markdown("### Gutman Index Inputs\nEnter vertex degrees and the distances for each unordered vertex pair.")
        gutman_degs = gr.Textbox(label="Vertex Degrees (comma-separated)", value="2,2,2")
        gutman_dists = gr.Textbox(label="Distances for pairs ((1,2), (1,3), (2,3)) (comma-separated)", value="1,1,1")
    
    # Group 4: Distance-based inputs (for Wiener and Harary indices)
    with gr.Group(visible=False) as distance_group:
        gr.Markdown("### Distance Inputs\nEnter the shortest-path distance for each unordered vertex pair.")
        distance1 = gr.Number(label="Distance for Pair 1", value=1)
        distance2 = gr.Number(label="Distance for Pair 2", value=1)
        distance3 = gr.Number(label="Distance for Pair 3", value=1)
    
    output_box = gr.Textbox(label="Step-by-Step Detailed Solution", lines=20)
    solve_btn = gr.Button("Solve")
    
    # Update input group visibility when index is selected
    index_dropdown.change(fn=update_inputs,
                          inputs=index_dropdown,
                          outputs=[vertex_group, edge_group, gutman_group, distance_group])
    
    # Run calculations when Solve is clicked
    solve_btn.click(fn=solve_index,
                    inputs=[index_dropdown, 
                            vertex_deg1, vertex_deg2, vertex_deg3,
                            vertex_ecc1, vertex_ecc2, vertex_ecc3,
                            edge1_a, edge1_b, edge2_a, edge2_b, edge3_a, edge3_b,
                            gutman_degs, gutman_dists,
                            distance1, distance2, distance3],
                    outputs=output_box)

demo.launch()