This repository has been archived by the owner on Oct 7, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathgw.py
71 lines (53 loc) · 2.27 KB
/
gw.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
#!/usr/bin/env python
# Copyright 2018, Rigetti Computing
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.
"""
Goemans-Williamson classical algorithm for MaxCut
"""
from typing import Tuple
import cvxpy as cvx
import networkx as nx
import numpy as np
from quantumflow.utils import from_graph6
def goemans_williamson(graph: nx.Graph) -> Tuple[np.ndarray, float, float]:
"""
The Goemans-Williamson algorithm for solving the maxcut problem.
Ref:
Goemans, M.X. and Williamson, D.P., 1995. Improved approximation
algorithms for maximum cut and satisfiability problems using
semidefinite programming. Journal of the ACM (JACM), 42(6), 1115-1145
Returns:
np.ndarray: Graph coloring (+/-1 for each node)
float: The GW score for this cut.
float: The GW bound from the SDP relaxation
"""
# Kudos: Originally implementation by Nick Rubin, with refactoring and
# cleanup by Jonathon Ward and Gavin E. Crooks
laplacian = np.array(0.25 * nx.laplacian_matrix(graph).todense())
# Setup and solve the GW semidefinite programming problem
psd_mat = cvx.Variable(laplacian.shape, PSD=True)
obj = cvx.Maximize(cvx.trace(laplacian * psd_mat))
constraints = [cvx.diag(psd_mat) == 1] # unit norm
prob = cvx.Problem(obj, constraints)
prob.solve(solver=cvx.CVXOPT)
evals, evects = np.linalg.eigh(psd_mat.value)
sdp_vectors = evects.T[evals > float(1.0E-6)].T
# Bound from the SDP relaxation
bound = np.trace(laplacian @ psd_mat.value)
random_vector = np.random.randn(sdp_vectors.shape[1])
random_vector /= np.linalg.norm(random_vector)
colors = np.sign([vec @ random_vector for vec in sdp_vectors])
score = colors @ laplacian @ colors.T
return colors, score, bound
if __name__ == '__main__':
# Quick test of GW code
G = from_graph6(r"My]WObEnkmHl}i}\_") # 14 nodes
laplacian = np.array(0.25 * nx.laplacian_matrix(G).todense())
bound = goemans_williamson(G)[2]
assert np.isclose(bound, 36.25438489966327)
print(goemans_williamson(G))
scores = [goemans_williamson(G)[1] for n in range(100)]
assert max(scores) >= 34
print(min(scores), max(scores))