graphs / app.py
carbon225's picture
coloring
884c797
import streamlit as st
import graphviz
import random
import gurobipy as gp
from gurobipy import GRB
import colorsys
def hsv2rgb(h, s, v):
r, g, b = colorsys.hsv_to_rgb(h, s, v)
return int(255 * r), int(255 * g), int(255 * b)
def format_color(color):
return '#%02x%02x%02x' % color
def generate_colors(n):
colors = [hsv2rgb(i / n, 0.5, 1.0) for i in range(n)]
return [format_color(color) for color in colors]
def generate_random_graph(V, density):
E = [(u, v) for u in range(V - 1) for v in range(u + 1, V)]
random.shuffle(E)
E = E[:int(density * V * (V - 1) / 2)]
return V, E
def solve_matching(V, E):
m = gp.Model()
x = m.addVars(E, vtype=GRB.BINARY)
m.setObjective(x.sum(), GRB.MAXIMIZE)
m.addConstrs(x.sum(u, '*') + x.sum('*', u) <= 1 for u in range(V))
m.optimize()
return [e for e in E if x[e].x > 0.5]
def app_matching(V, E):
M = set(solve_matching(V, E))
if len(M) == V // 2:
st.success('Perfect matching found')
else:
st.metric('Matching size', len(M))
G = graphviz.Graph()
for u, v in E:
if (u, v) in M:
G.edge(str(u), str(v), color='red')
else:
G.edge(str(u), str(v), color='gray', style='dashed')
st.graphviz_chart(G)
def solve_hamilton(V, E):
m = gp.Model()
x = m.addVars(range(V), range(V), vtype=GRB.BINARY)
m.addConstrs(x.sum(u, '*') == 1 for u in range(V))
m.addConstrs(x.sum('*', i) == 1 for i in range(V))
for u in range(V):
for v in range(V):
if (u, v) not in E and (v, u) not in E:
for i in range(V - 1):
m.addConstr(x[u, i] + x[v, i + 1] <= 1)
m.addConstr(x[u, V - 1] + x[v, 0] <= 1)
m.optimize()
if m.status != GRB.OPTIMAL:
return None
cycle = []
for i in range(V):
for u in range(V):
if x[u, i].x > 0.5:
cycle.append(u)
break
return cycle
def app_hamilton(V, E):
cycle = solve_hamilton(V, E)
if cycle is None:
st.error('Hamilton cycle not found')
else:
st.success('Hamilton cycle found')
G = graphviz.Graph()
if cycle is not None:
for u in range(V):
G.node(str(cycle.index(u)))
for u, v in E:
if ((cycle.index(u) + 1) % len(cycle)) == cycle.index(v):
G.edge(str(cycle.index(u)), str(cycle.index(v)), dir='forward')
elif ((cycle.index(u) - 1) % len(cycle)) == cycle.index(v):
G.edge(str(cycle.index(u)), str(cycle.index(v)), dir='back')
else:
G.edge(str(cycle.index(u)), str(cycle.index(v)), style='dashed', color='gray')
else:
for u in range(V):
G.node(str(u))
for u, v in E:
G.edge(str(u), str(v))
st.graphviz_chart(G)
def solve_vertex_cover(V, E):
m = gp.Model()
x = m.addVars(range(V), vtype=GRB.BINARY)
m.setObjective(x.sum(), GRB.MINIMIZE)
m.addConstrs(x[u] + x[v] >= 1 for u, v in E)
m.optimize()
return [u for u in range(V) if x[u].x > 0.5]
def app_vertex_cover(V, E):
cover = solve_vertex_cover(V, E)
st.metric('Vertex cover size', len(cover))
G = graphviz.Graph()
for u in range(V):
if u in cover:
G.node(str(u), style='filled', fillcolor='lightblue')
else:
G.node(str(u), color='gray')
for u, v in E:
G.edge(str(u), str(v))
st.graphviz_chart(G)
def solve_coloring(V, E):
m = gp.Model()
vertex_color = m.addVars(range(V), vtype=GRB.INTEGER, lb=0)
or_helper = m.addVars(E, vtype=GRB.BINARY)
chi = m.addVar(vtype=GRB.INTEGER)
m.setObjective(chi, GRB.MINIMIZE)
m.addConstrs(vertex_color[u] <= chi for u in range(V))
m.addConstrs((or_helper[u, v] == 0) >> (vertex_color[u] - vertex_color[v] >= 1) for u, v in E)
m.addConstrs((or_helper[u, v] == 1) >> (vertex_color[v] - vertex_color[u] >= 1) for u, v in E)
m.optimize()
return [round(vertex_color[u].x) for u in range(V)]
def app_coloring(V, E):
coloring = solve_coloring(V, E)
st.metric('Chromatic number', max(coloring) + 1)
colors = generate_colors(max(coloring) + 1)
G = graphviz.Graph()
for u in range(V):
G.node(str(u), style='filled', fillcolor=colors[coloring[u]])
for u, v in E:
G.edge(str(u), str(v))
st.graphviz_chart(G)
def main():
V = st.number_input('Number of vertices', min_value=1, value=10)
density = st.slider('Density', min_value=0.0, max_value=1.0, value=0.5)
st.button('Generate')
V, E = generate_random_graph(V, density)
if len(E) > 40:
st.warning('Too many edges to display')
return
apps = [
app_matching,
app_hamilton,
app_vertex_cover,
app_coloring,
]
tabs = st.tabs([
'Matching',
'Hamilton',
'Vertex cover',
'Coloring',
])
for t, a in zip(tabs, apps):
with t:
a(V, E)
if __name__ == '__main__':
main()