QAPLIB Figures¶
%load_ext autoreload
%autoreload 1
from pkg.gmp import quadratic_assignment
from pkg.gmp import quadratic_assignment_ot
from pkg.plot import set_theme
import numpy as np
# hide
import sys
sys.path
sys.path.insert(0,'../../graspologic')
Recreate fig 4 from FAQ Paper¶
Caption:¶
Relative accuracy between FAQ and GOAT, defined as y=log(\(OFV_{GOAT} \over {OFV_{FAQ}}\)). Performance is compared using the minimum objective function value over 100 random initializations, and the objective function value of a barycenter initialization with one random shuffle. Initializations and shuffles are the same across FAQ and GOAT.
from os import listdir
from os.path import isfile, join
import time
qapprob = ["bur26a", "bur26b", "bur26c", "bur26d", "bur26e", "bur26f",
              "bur26g", "bur26h", "chr12a", "chr12b", "chr12c", "chr15a",
              "chr15b", "chr15c", "chr18a", "chr18b", "chr20a", "chr20b",
              "chr20c", "chr22a", "chr22b", "chr25a",
              "els19",
              "esc16a", "esc16b", "esc16c", "esc16d", "esc16e", "esc16g",
              "esc16h", "esc16i", "esc16j", "esc32e", "esc32g", "esc128",
              "had12", "had14", "had16", "had18", "had20", "kra30a",
              "kra30b", "kra32",
              "lipa20a", "lipa20b", "lipa30a", "lipa30b", "lipa40a", "lipa40b",
              "lipa50a", "lipa50b", "lipa60a", "lipa60b", "lipa70a", "lipa70b",
              "lipa80a", "lipa90a", "lipa90b",
              "nug12", "nug14", "nug16a", "nug16b", "nug17", "nug18", "nug20",
              "nug21", "nug22", "nug24", "nug25", "nug27", "nug28", "nug30",
              "rou12", "rou15", "rou20",
              "scr12", "scr15", "scr20",
              "sko42", "sko49", "sko56", "sko64", "sko72", "sko81", "sko90",
              "sko100a", "sko100b", "sko100c", "sko100d", "sko100e", "sko100f",
              "ste36b", "ste36c",
              "tai12a", "tai12b", "tai15a", "tai15b", "tai17a", "tai20a",
              "tai20b", "tai25a", "tai25b", "tai30a", "tai30b", "tai35a",
              "tai40a", "tai40b", "tai50a", "tai50b", "tai60a", "tai60b",
              "tai64c", "tai80a", "tai100a", "tai100b", "tai150b", "tai256c",
              "tho30", "tho40", "tho150", "wil50", "wil100"]
n_qap = len(qapprob)
slnfile = np.load("../data/qaplib/qap_sols.npz",allow_pickle=True)
datafile = np.load("../data/qaplib/qap_probs.npz",allow_pickle=True)
sizes = np.zeros(n_qap)
logofv = np.zeros(n_qap)
n_init = 100
scores_faq_r = np.zeros((n_qap,n_init))
scores_goat_r = np.zeros((n_qap,n_init))
times_faq_r = np.zeros(n_qap)
times_goat_r = np.zeros(n_qap)
for i in range(n_qap):
    A = datafile[qapprob[i]][0]
    B = datafile[qapprob[i]][1]
    n = A.shape[0]
    sizes[i] = n
    rng = check_random_state(i)
    
    options = {'tol':1e-6,'maxiter': 50,'P0': 'randomized', 'shuffle_input':True}
    start = time.time()
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))
    times_faq_r[i] = (time.time()-start)/n_init
    res = min(results, key=lambda x: x.fun,)
    scores_faq_r[i,:] = [x.fun for x in results]
    gm_score = res.fun
    
    options = {'tol':1e-6,'maxiter': 50,'P0': 'randomized', 'shuffle_input':True, 'reg': 500, 'thr':1e-2}
    start = time.time()
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment_ot)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))
    times_goat_r[i] = (time.time()-start)/n_init
    res = min(results, key=lambda x: x.fun,)
    scores_goat_r[i,:] = [x.fun for x in results]
      
    logofv[i] = np.log10(res.fun/gm_score)
    
import matplotlib.pyplot as plt
import seaborn as sns
cb = ['#377eb8', '#ff7f00', '#4daf4a',
                  '#f781bf', '#a65628', '#984ea3',
                  '#999999', '#e41a1c', '#dede00']
fig, ax = plt.subplots()
sns.set(rc={'figure.figsize':(10,9)})
sns.set(font_scale = 2)
sns.set_style('white')
ax.hlines(0,0,np.max(sizes),linestyles='dashed', color = 'grey')
ax.scatter(sizes[logofv==0],logofv[logofv==0], color=cb[2])
ax.scatter(sizes[logofv>0],logofv[logofv>0], color = cb[1],label='FAQ better')
ax.scatter(sizes[logofv<0],logofv[logofv<0], color=cb[0],label='GOAT better')
# ax.scatter(np.mean(sizes), np.mean(logofv), color = cb[3])
ax.legend()
ax.set_xlabel('# of vertices')
ax.set_ylabel('log relative objective value')
ax.set_xscale('log')
ax.set_title('Random Initialization')
form = ScalarFormatter()
form.set_scientific(False)
ax.xaxis.set_major_formatter(form)
ax.set_xticks([25,50,100,200])
[<matplotlib.axis.XTick at 0x7f10e184b358>,
 <matplotlib.axis.XTick at 0x7f10e1836ef0>,
 <matplotlib.axis.XTick at 0x7f10e18366d8>,
 <matplotlib.axis.XTick at 0x7f10d9750f60>]
 
from scipy.stats import ranksums, mannwhitneyu, wilcoxon
print(f'p-value: {mannwhitneyu(np.min(scores_faq_r, axis=1), np.min(scores_goat_r, axis=1)).pvalue}')
p-value: 0.49963814754139707
n_qap = len(qapprob)
print(f'percent GOAT better = {np.sum(logofv < 0)/n_qap}')
print(f'percent FAQ better = {np.sum(logofv > 0)/n_qap}')
print(f'percent same = {np.sum(logofv == 0)/n_qap}')
percent GOAT better = 0.3442622950819672
percent FAQ better = 0.3360655737704918
percent same = 0.319672131147541
from os import listdir
from os.path import isfile, join
qapprob = ["bur26a", "bur26b", "bur26c", "bur26d", "bur26e", "bur26f",
              "bur26g", "bur26h", "chr12a", "chr12b", "chr12c", "chr15a",
              "chr15b", "chr15c", "chr18a", "chr18b", "chr20a", "chr20b",
              "chr20c", "chr22a", "chr22b", "chr25a",
              "els19",
              "esc16a", "esc16b", "esc16c", "esc16d", "esc16e", "esc16g",
              "esc16h", "esc16i", "esc16j", "esc32e", "esc32g", "esc128",
              "had12", "had14", "had16", "had18", "had20", "kra30a",
              "kra30b", "kra32",
              "lipa20a", "lipa20b", "lipa30a", "lipa30b", "lipa40a", "lipa40b",
              "lipa50a", "lipa50b", "lipa60a", "lipa60b", "lipa70a", "lipa70b",
              "lipa80a", "lipa90a", "lipa90b",
              "nug12", "nug14", "nug16a", "nug16b", "nug17", "nug18", "nug20",
              "nug21", "nug22", "nug24", "nug25", "nug27", "nug28", "nug30",
              "rou12", "rou15", "rou20",
              "scr12", "scr15", "scr20",
              "sko42", "sko49", "sko56", "sko64", "sko72", "sko81", "sko90",
              "sko100a", "sko100b", "sko100c", "sko100d", "sko100e", "sko100f",
              "ste36b", "ste36c",
              "tai12a", "tai12b", "tai15a", "tai15b", "tai17a", "tai20a",
              "tai20b", "tai25a", "tai25b", "tai30a", "tai30b", "tai35a",
              "tai40a", "tai40b", "tai50a", "tai50b", "tai60a", "tai60b",
              "tai64c", "tai80a", "tai100a", "tai100b", "tai150b", "tai256c",
              "tho30", "tho40", "tho150", "wil50", "wil100"]
n_qap = len(qapprob)
sizes = np.zeros(n_qap)
logofv = np.zeros(n_qap)
n_init = 1
scores_faq = np.zeros((n_qap,n_init))
scores_goat = np.zeros((n_qap,n_init))
for i in range(n_qap):
    A = datafile[qapprob[i]][0]
    B = datafile[qapprob[i]][1]
    n = A.shape[0]
    sizes[i] = n
    rng = check_random_state(None)
    
    options = {'tol':1e-6,'maxiter': 50, 'shuffle_input':True}
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))
#     scores_faq[i,:] = [x.fun for x in results]
    scores_faq[i,:] = [x.fun for x in results]
    gm_score = np.median(scores_faq[i,:])
    
    options = {'tol':1e-6,'maxiter': 100, 'shuffle_input':True, 'reg': 700, 'thr':1e-2}
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment_ot)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))
#     scores_goat[i,:] = [x.fun for x in results]
    scores_goat[i,:] = [x.fun for x in results]
    logofv[i] = np.log10(np.median(scores_goat[i,:])/gm_score)
    
fig, ax = plt.subplots()
sns.set(rc={'figure.figsize':(10,9)})
sns.set(font_scale = 2)
sns.set_style('white')
ax.hlines(0,0,np.max(sizes),linestyles='dashed', color = 'grey')
ax.scatter(sizes[logofv==0],logofv[logofv==0], color=cb[2])
ax.scatter(sizes[logofv>0],logofv[logofv>0], color = cb[1],label='FAQ better')
ax.scatter(sizes[logofv<0],logofv[logofv<0], color=cb[0],label='GOAT better')
ax.set_title('Barycenter Initialization')
# ax.scatter(np.mean(sizes), np.mean(logofv), color = cb[3])
ax.legend()
ax.set_xlabel('# of vertices')
ax.set_ylabel('log relative objective value')
ax.set_xscale('log')
form = ScalarFormatter()
form.set_scientific(False)
ax.xaxis.set_major_formatter(form)
ax.set_xticks([25,50,100,200])
[<matplotlib.axis.XTick at 0x7f10d8e997b8>,
 <matplotlib.axis.XTick at 0x7f10d8e99390>,
 <matplotlib.axis.XTick at 0x7f10d8e99048>,
 <matplotlib.axis.XTick at 0x7f10d8e5b588>]
 
from scipy.stats import ranksums, mannwhitneyu
print(f'p-value: {mannwhitneyu(np.median(scores_faq, axis=1), np.median(scores_goat, axis=1)).pvalue}')
p-value: 0.4916780371936752
print(f'percent GOAT better = {np.sum(logofv < 0)/n_qap}')
print(f'percent FAQ better = {np.sum(logofv > 0)/n_qap}')
print(f'percent same = {np.sum(logofv == 0)/n_qap}')
percent GOAT better = 0.47540983606557374
percent FAQ better = 0.4180327868852459
percent same = 0.10655737704918032
QAPLIB Benchmark with barycenter init, 50 random shuffles¶
from joblib import Parallel, delayed
from sklearn.utils import check_random_state
qapprob = ["chr12c","chr15a","chr15c","chr20b","chr22b","esc16b",
          "rou12","rou15","rou20","tai12a","tai15a","tai17a","tai20a",
          "tai30a","tai35a","tai40a"]
# qapprob = ["lipa20a", "lipa20b", "lipa30a", "lipa30b", "lipa40a", "lipa40b",
#               "lipa50a", "lipa50b", "lipa60a", "lipa60b", "lipa70a", "lipa70b",
#               "lipa80a", "lipa90a", "lipa90b"]
# qapprob =["sko100a", "sko100b", "sko100c", "sko100d", "sko100e", "sko100f",]
n_qap = len(qapprob)
slnfile = np.load("../data/qaplib/qap_sols.npz",allow_pickle=True)
datafile = np.load("../data/qaplib/qap_probs.npz",allow_pickle=True)
n_qap = len(qapprob)
gm_scores = np.zeros(n_qap)
gmot_scores = np.zeros(n_qap)
rng = check_random_state(0)
for i in range(n_qap):
    A = datafile[qapprob[i]][0]
    B = datafile[qapprob[i]][1]
    n = A.shape[0]
    n_init=1
    options={'tol':1e-6,'maxiter':100, 'shuffle_input':True}
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))
    res = min(results, key=lambda x: x.fun,)
    gm_scores[i] = res.fun
    
    options={'tol':1e-6,'maxiter':100,'shuffle_input':True, 'reg': 50, 'thr':1e-2}
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment_ot)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))  
    res = min(results, key=lambda x: x.fun,)
    gmot_scores[i] = res.fun
import pandas as pd
opt = [slnfile[i] for i in qapprob]
mat = np.zeros((n_qap,3))
mat[:,0] = opt
mat[:,1] = gm_scores
mat[:,2] = gmot_scores
mat = mat.astype(int)
df = pd.DataFrame(mat,columns=["OPT","FAQ", 'GOAT'])
df.insert(0,"QAP",qapprob,True)
df.style
| QAP | OPT | FAQ | GOAT | |
|---|---|---|---|---|
| 0 | chr12c | 11156 | 13072 | 12854 | 
| 1 | chr15a | 9896 | 19604 | 15042 | 
| 2 | chr15c | 9504 | 11936 | 13518 | 
| 3 | chr20b | 2298 | 3310 | 3530 | 
| 4 | chr22b | 6194 | 8582 | 7228 | 
| 5 | esc16b | 292 | 320 | 314 | 
| 6 | rou12 | 235528 | 245168 | 243228 | 
| 7 | rou15 | 354210 | 369342 | 381582 | 
| 8 | rou20 | 725522 | 743884 | 746348 | 
| 9 | tai12a | 224416 | 244672 | 224416 | 
| 10 | tai15a | 388214 | 397376 | 399096 | 
| 11 | tai17a | 491812 | 516644 | 524010 | 
| 12 | tai20a | 703482 | 734276 | 747146 | 
| 13 | tai30a | 1818146 | 1874428 | 1946560 | 
| 14 | tai35a | 2422002 | 2460940 | 2592986 | 
| 15 | tai40a | 3139370 | 3225948 | 3432564 | 
QAPLIB with Random Inits¶
100 random inits, 1 shuffle per init¶
qapprob = ["chr12c","chr15a","chr15c","chr20b","chr22b","esc16b",
          "rou12","rou15","rou20","tai12a","tai15a","tai17a","tai20a",
          "tai30a","tai35a","tai40a"]
# qapprob = ["lipa20a", "lipa20b", "lipa30a", "lipa30b", "lipa40a", "lipa40b",
#               "lipa50a", "lipa50b", "lipa60a", "lipa60b", "lipa70a", "lipa70b",
#               "lipa80a", "lipa90a", "lipa90b"]
# qapprob =["sko100a", "sko100b", "sko100c", "sko100d", "sko100e", "sko100f",]
n_qap = len(qapprob)
gm_scores = np.zeros(n_qap)
gmot_scores = np.zeros(n_qap)
for i in range(n_qap):
    A = datafile[qapprob[i]][0]
    B = datafile[qapprob[i]][1]
    n = A.shape[0]
    rng = check_random_state(None)
    n_init=100
    options={'tol':1e-6,'maxiter':100, 'P0':'randomized','shuffle_input':True}
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))
    res = min(results, key=lambda x: x.fun,)
    gm_scores[i] = res.fun
    
    options={'tol':1e-6,'maxiter':100,'P0':'randomized','shuffle_input':True, 'reg': 100, 'thr':1e-2}
    results = Parallel(n_jobs=-1)(delayed(quadratic_assignment_ot)(A, B, options={**options, **{"rng": r}})
            for r in rng.randint(np.iinfo(np.int32).max, size=n_init))  
    res = min(results, key=lambda x: x.fun,)
    gmot_scores[i] = res.fun
import pandas as pd
from IPython.display import display
qapprob = ["chr12c","chr15a","chr15c","chr20b","chr22b","esc16b",
          "rou12","rou15","rou20","tai12a","tai15a","tai17a","tai20a",
          "tai30a","tai35a","tai40a"]
n_qap = len(qapprob)
opt = [slnfile[i] for i in qapprob]
mat = np.zeros((n_qap,3))
mat[:,0] = opt
mat[:,1] = gm_scores
mat[:,2] = gmot_scores
mat = mat.astype(int)
df = pd.DataFrame(mat,columns=["OPT","FAQ", 'GOAT'])
df.insert(0,"QAP",qapprob,True)
# print(df)
df
| QAP | OPT | FAQ | GOAT | |
|---|---|---|---|---|
| 0 | chr12c | 11156 | 11566 | 11808 | 
| 1 | chr15a | 9896 | 10440 | 10192 | 
| 2 | chr15c | 9504 | 12458 | 9504 | 
| 3 | chr20b | 2298 | 2760 | 2598 | 
| 4 | chr22b | 6194 | 7228 | 6888 | 
| 5 | esc16b | 292 | 292 | 292 | 
| 6 | rou12 | 235528 | 235528 | 235528 | 
| 7 | rou15 | 354210 | 354210 | 356654 | 
| 8 | rou20 | 725522 | 730240 | 731134 | 
| 9 | tai12a | 224416 | 224416 | 224416 | 
| 10 | tai15a | 388214 | 388250 | 391426 | 
| 11 | tai17a | 491812 | 493662 | 496330 | 
| 12 | tai20a | 703482 | 708198 | 705622 | 
| 13 | tai30a | 1818146 | 1837196 | 1829456 | 
| 14 | tai35a | 2422002 | 2456214 | 2431498 | 
| 15 | tai40a | 3139370 | 3177518 | 3166816 | 
Table for paper¶

Mean and variance with multiple random shuffles¶
from os import listdir
from os.path import isfile, join
qapprob = ["chr12c","chr15a","chr15c","chr20b","chr22b",
"esc16b", "rou12","rou15","rou20","tai12a","tai15a","tai17a","tai20a",
          "tai30a","tai35a","tai40a"]
# qapprob = ["lipa20a", "lipa20b", "lipa30a", "lipa30b", "lipa40a", "lipa40b",
#               "lipa50a", "lipa50b", "lipa60a", "lipa60b", "lipa70a", "lipa70b",
#               "lipa80a", "lipa90a", "lipa90b"]
# qapprob =["sko100a", "sko100b", "sko100c", "sko100d", "sko100e", "sko100f",]
n_qap = len(qapprob)
slnfile = np.load("../data/qaplib/qap_sols.npz",allow_pickle=True)
datafile = np.load("../data/qaplib/qap_probs.npz",allow_pickle=True)
n_qap = len(qapprob)
reps = 50
gm_bary = np.zeros((n_qap, reps))
gmot_bary = np.zeros((n_qap,reps))
gm_rand = np.zeros((n_qap, reps))
gmot_rand = np.zeros((n_qap,reps))
for i in range(n_qap):
    A = datafile[qapprob[i]][0]
    B = datafile[qapprob[i]][1]
    n = A.shape[0]
    for j in range(reps):
        res = quadratic_assignment(A,B,options={'maximize':False, 'rng':i*30+j, 'tol':1e-6,'maxiter':100, 'shuffle_input':True})          
        gm_bary[i,j] = res.fun
        res = quadratic_assignment(A,B,options={'maximize':False, 'rng':i*30+j,'P0': 'randomized','tol':1e-6,'maxiter':100, 'shuffle_input':True})          
        gm_rand[i,j] = res.fun
        res = quadratic_assignment_ot(A,B,options={'maximize':False, 'rng':i*30+j, 'tol':1e-6,'maxiter':100, 'shuffle_input':True,'reg':100, 'thr':1e-3})          
        gmot_bary[i,j] = res.fun
        res = quadratic_assignment_ot(A,B,options={'maximize':False, 'rng':i*30+j,'P0': 'randomized','tol':1e-6,'maxiter':100, 'shuffle_input':True,'reg':100, 'thr':1e-3})          
        gmot_rand[i,j] = res.fun
import pandas as pd
from scipy.stats import sem
opt = [slnfile[i] for i in qapprob]
mat = np.zeros((n_qap,3))
mat[:,0] = opt
mat[:,1] = sem(gm_bary,axis=1)
mat[:,2] = sem(gmot_bary,axis=1)
mat = mat.astype(int)
df = pd.DataFrame(mat,columns=["OPT","GM", 'GM_OT'])
df.insert(0,"QAP",qapprob,True)
print(df)
       QAP      OPT    GM  GM_OT
0   chr12c    11156     0      0
1   chr15a     9896   557      0
2   chr15c     9504   433      0
3   chr20b     2298    54      0
4   chr22b     6194    43      0
5   esc16b      292     0      0
6    rou12   235528   608      0
7    rou15   354210     0      0
8    rou20   725522     0      0
9   tai12a   224416     0      0
10  tai15a   388214     0      0
11  tai17a   491812   484      0
12  tai20a   703482     0      0
13  tai30a  1818146   624      0
14  tai35a  2422002  3359      0
15  tai40a  3139370   118      0
from scipy.stats import sem
import seaborn as sns
opt = mat[:,0].reshape(-1,1)
gmot_pdiff = (gmot_rand - opt)/opt
gm_pdiff = (gm_rand - opt)/opt
gmot_pdiffb = (gmot_bary - opt)/opt
gm_pdiffb = (gm_bary - opt)/opt
sns.set_context('paper')
sns.set(rc={'figure.figsize':(15,10)})
plt.errorbar(qapprob,np.mean(gmot_pdiff,axis=1), sem(gmot_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GMOT mean +/- sem',)
plt.errorbar(qapprob,np.mean(gm_pdiff,axis=1), sem(gm_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GM mean +/- sem',)
plt.scatter(qapprob,np.min(gmot_pdiff,axis=1), color='blue', label = "GMOT min")
plt.scatter(qapprob,np.min(gm_pdiff,axis=1), color='orange', label='GM min')
plt.xlabel("QAPLIB problem")
plt.ylabel("percent difference from optimal objective function value")
plt.title('random intitialization')
plt.legend()
<matplotlib.legend.Legend at 0x7f3578ab5f98>
 
opt = mat[:,0].reshape(-1,1)
gmot_pdiff = (gmot_rand - opt)/opt
gm_pdiff = (gm_rand - opt)/opt
gmot_pdiffb = (gmot_bary - opt)/opt
gm_pdiffb = (gm_bary - opt)/opt
sns.set_context('paper')
sns.set(rc={'figure.figsize':(15,10)})
plt.errorbar(qapprob,np.mean(gmot_pdiff,axis=1), sem(gmot_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GMOT rand',)
plt.errorbar(qapprob,np.mean(gm_pdiff,axis=1), sem(gm_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GM rand',color='r')
plt.errorbar(qapprob,np.mean(gmot_pdiffb,axis=1), sem(gmot_pdiffb,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GMOT barycenter',color='blue')
plt.errorbar(qapprob,np.mean(gm_pdiffb,axis=1), sem(gm_pdiffb,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GM barycenter',color='red')
plt.scatter(qapprob,np.min(gmot_pdiff,axis=1), color='black', label = "GMOT min")
plt.scatter(qapprob,np.min(gm_pdiff,axis=1), color='orange', label='GM min')
plt.legend()
plt.xlabel("QAPLIB problem")
plt.ylabel("percent difference from optimal objective function value")
Text(0, 0.5, 'percent difference from optimal objective function value')
 
from scipy.stats import sem
import seaborn as sns
opt = mat[:,0].reshape(-1,1)
gmot_pdiff = (gmot_rand - opt)/opt
gm_pdiff = (gm_rand - opt)/opt
gmot_pdiffb = (gmot_bary - opt)/opt
gm_pdiffb = (gm_bary - opt)/opt
sns.set_context('paper')
sns.set(rc={'figure.figsize':(15,10)})
plt.errorbar(qapprob,np.mean(gmot_pdiff,axis=1), sem(gmot_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GMOT mean +/- sem',)
plt.errorbar(qapprob,np.mean(gm_pdiff,axis=1), sem(gm_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GM mean +/- sem',)
plt.scatter(qapprob,np.min(gmot_pdiff,axis=1), color='blue', label = "GMOT min")
plt.scatter(qapprob,np.min(gm_pdiff,axis=1), color='orange', label='GM min')
plt.xlabel("QAPLIB problem")
plt.ylabel("percent difference from optimal objective function value")
plt.title('random intitialization')
plt.legend()
<matplotlib.legend.Legend at 0x7f3578971860>
 
opt = mat[:,0].reshape(-1,1)
gmot_pdiff = (gmot_rand - opt)/opt
gm_pdiff = (gm_rand - opt)/opt
gmot_pdiffb = (gmot_bary - opt)/opt
gm_pdiffb = (gm_bary - opt)/opt
sns.set_context('paper')
sns.set(rc={'figure.figsize':(15,10)})
# plt.errorbar(qapprob,np.mean(gmot_pdiff,axis=1), sem(gmot_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GMOT rand',alpha=0.75,)
# plt.errorbar(qapprob,np.mean(gm_pdiff,axis=1), sem(gm_pdiff,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GM rand',alpha=0.75,color='r')
plt.errorbar(qapprob,np.mean(gmot_pdiffb,axis=1), sem(gmot_pdiffb,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GMOT barycenter',alpha=0.75,color='blue')
plt.errorbar(qapprob,np.mean(gm_pdiffb,axis=1), sem(gm_pdiffb,axis=1),fmt='o',capsize=3, elinewidth=1, markeredgewidth=1, label='GM barycenter',alpha=0.75,color='red')
# plt.scatter(qapprob,np.min(gmot_pdiff,axis=1), color='black', alpha=0.75,label = "GMOT min")
# plt.scatter(qapprob,np.min(gm_pdiff,axis=1), color='orange', alpha=0.75,label='GM min')
plt.legend()
plt.xlabel("QAPLIB problem")
plt.ylabel("percent difference from optimal objective function value")
Text(0, 0.5, 'percent difference from optimal objective function value')
 
def _doubly_stochastic(P, tol=1e-3, max_iter=1000):
    # Adapted from @btaba implementation
    # https://github.com/btaba/sinkhorn_knopp
    # of Sinkhorn-Knopp algorithm
    # https://projecteuclid.org/euclid.pjm/1102992505
    c = 1 / P.sum(axis=0)
    r = 1 / (P @ c)
    P_eps = P
    for it in range(max_iter):
        if it % 100 == 0:  # only check every so often to speed up
            if (np.abs(P_eps.sum(axis=1) - 1) < tol).all() and (
                np.abs(P_eps.sum(axis=0) - 1) < tol
            ).all():
                # All column/row sums ~= 1 within threshold
                break
        c = 1 / (r @ P)
        r = 1 / (P @ c)
        P_eps = r[:, None] * P * c
    return P_eps
