-
Notifications
You must be signed in to change notification settings - Fork 13
/
graph_coloring.py
118 lines (85 loc) · 3.28 KB
/
graph_coloring.py
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
# Copyright 2022 D-Wave Systems Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import matplotlib
import networkx as nx
from dimod import ConstrainedQuadraticModel, Binary, quicksum
from dwave.system import LeapHybridCQMSampler
try:
import matplotlib.pyplot as plt
except ImportError:
matplotlib.use("agg")
import matplotlib.pyplot as plt
def build_graph(num_nodes):
"""Build graph."""
print("\nBuilding graph...")
G = nx.powerlaw_cluster_graph(num_nodes, 3, 0.4)
pos = nx.spring_layout(G)
nx.draw(G, pos=pos, node_size=50, edgecolors='k')
plt.savefig("original_graph.png")
return G, pos
def build_cqm(G, num_colors):
"""Build CQM model."""
print("\nBuilding constrained quadratic model...")
# Initialize the CQM object
cqm = ConstrainedQuadraticModel()
# Build CQM variables
colors = {n: {c: Binary((n, c)) for c in range(num_colors)} for n in G.nodes}
# Add constraint to make variables discrete
for n in G.nodes():
cqm.add_discrete([(n, c) for c in range(num_colors)])
# Build the constraints: edges have different color end points
for u, v in G.edges:
for c in range(num_colors):
cqm.add_constraint(colors[u][c]*colors[v][c] == 0)
return cqm
def run_hybrid_solver(cqm):
"""Solve CQM using hybrid solver."""
print("\nRunning hybrid sampler...")
# Initialize the CQM solver
sampler = LeapHybridCQMSampler()
# Solve the problem using the CQM solver
sampleset = sampler.sample_cqm(cqm, label='Example - Graph Coloring')
feasible_sampleset = sampleset.filter(lambda row: row.is_feasible)
try:
sample = feasible_sampleset.first.sample
except:
print("\nNo feasible solutions found.")
exit()
soln = {key[0]: key[1] for key, val in sample.items() if val == 1.0}
return soln
def plot_soln(sample, pos):
"""Plot results and save file.
Args:
sample (dict):
Sample containing a solution. Each key is a node and each value
is an int representing the node's color.
pos (dict):
Plotting information for graph so that same graph shape is used.
"""
print("\nProcessing sample...")
node_colors = [sample[i] for i in G.nodes()]
nx.draw(G, pos=pos, node_color=node_colors, node_size=50, edgecolors='k', cmap='hsv')
fname = 'graph_result.png'
plt.savefig(fname)
print("\nSaving results in {}...".format(fname))
# ------- Main program -------
if __name__ == "__main__":
num_nodes = 50
G, pos = build_graph(num_nodes)
num_colors = max(d for _, d in G.degree()) + 1
cqm = build_cqm(G, num_colors)
sample = run_hybrid_solver(cqm)
plot_soln(sample, pos)
colors_used = max(sample.values())+1
print("\nColors used:", colors_used, "\n")