Optimized Resolvent Splitting Examples¶

This notebook generates the figures in our paper, which outlines the use of a semi-definite programming framework for optimizing splitting algorithms which solve the following monotone inclusion problem:

\begin{equation} 0 \in \sum_{i=1}^{n} A_{i}(x). \end{equation}

It does so by finding valid matrices $L$ and $W$ for the following set of iterations, where bolded entries are lifted, i.e. $\mathrm{x} = (x_1, \dots, x_n)$:

\begin{align} \mathrm{x} &= J_{\mathrm{A}}\left(\mathrm{v}^{k} + \mathrm{L} \mathrm{x}\right)\\ \mathrm{v}^{k+1} &= \mathrm{v}^{k} - \gamma \mathrm{W} \mathrm{x}. \end{align}

$L$ is lower diagonal, so we work with a symmetrized matrix $Z = 2I - L - L^T$

In [2]:
import numpy as np
import oars
from oars.matrices import *
from oars.utils import *
from oars.pep import *
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
# matplotlib.use('nbagg')
import seaborn as sns
sns.set()
from matplotlib.colors import CenteredNorm
import cvxpy as cvx
from collections import defaultdict

Our first example builds the matrices, which can be thought of as the graph Laplacians of communication graphs for the nodes in a distributed setting, to avoid specific communication paths.

We suppose a set of two clusters (0-2) and (3-5) which can only communicate within clusters and via a link between 0-3.

We then plot a Gantt chart for the distributed execution of the resulting algorithm.

We take as our objective function here the spectral norm of $Z-W$, which promotes graph similarity.

In [3]:
# Data for matrices in cluster example (6x6)
n = 6
Z_fixed = {(r,c):0 for r in range(4,6) for c in range(3)}
Z_fixed[(3,1)] = 0
Z_fixed[(3,2)] = 0

Z, W = getMinSpectralDifference(n, fixed_Z=Z_fixed, fixed_W=Z_fixed)
In [4]:
# Figure 3
t = 0.016*np.ones(n)
l = 0.00025*np.ones((n, n))
l[0, 3] = 0.01
l[3, 0] = 0.01  
fig = getGantt(t, l, Z, W, title="Cluster Algorithm Parallelism", itrs=5)
fig.show()
#if you want to save the figure as a separate file
saving = False # set to True to save the figures
if saving:
    import os
    if ~os.path.exists('figs'): os.makedirs('figs')
    fig.write_image("figs/fig_gantt.pdf")
No description has been provided for this image

In this example, we visually depict the different matrices generates by changing the objective function between maximizing algebraic connectivity, minimizing SLEM, minimizing total effective resistance, and minimizing the spectral norm of the difference of the matrices.

We also demonstrate the use of the getBlockMin function to build the constraint set for the SDP to guarantee that the nodes can execute in blocks. If the compute and communication times are constant and uniform, this guarantees that the algorithm can execute with the highest possible degree of parallelism possible for this type of splitting.

In [5]:
# Figure 4 helper
def cplot(W,Z):
    vmin = np.floor(np.min(np.minimum(W, Z)))
    cm = plt.cm.coolwarm
    fig, ax = plt.subplots(1, 2, figsize=(12, 6))
    x = -np.arange(n)
    y = np.arange(n)
    ax[0].pcolormesh(x, y, W, norm=CenteredNorm(), cmap=cm) #, vmin=vmin, vmax=2)
    ax[0].set_title(r"$W$")
    ax[0].axis('off')
    ax[0].set_aspect('equal')

    pc = ax[1].pcolormesh(x, y, Z, norm=CenteredNorm(), cmap=cm)
    ax[1].set_title(r"$Z$")
    ax[1].axis('off')
    ax[1].set_aspect('equal')

    # Add colorbar
    plt.tight_layout()
    
    fig.colorbar(pc, ax=ax.ravel().tolist())
    return fig
In [6]:
# Figure 4
n = 10
m = 2
Z, W = getBlockMin(n, m, builder=getMaxConnectivity)

fig = cplot(W, Z)

# Save as pdf
if saving: fig.savefig("figs/fig_block_fiedler.pdf")
No description has been provided for this image
In [7]:
# Figure 4
Z, W = getBlockMin(n, m, builder=getMinSLEM)

fig = cplot(W, Z)
if saving: fig.savefig("figs/fig_block_slem.pdf")
No description has been provided for this image
In [8]:
# Figure 4
Z, W = getBlockMin(n, m, builder=getMinResist)

fig = cplot(W, Z)
if saving: fig.savefig("figs/fig_block_resist.pdf")
No description has been provided for this image
In [9]:
# Figure 4
Z, W = getBlockMin(n, m, builder=getMinSpectralDifference)

fig = cplot(W, Z)
if saving: fig.savefig("figs/fig_block_lw.pdf")
No description has been provided for this image

This example shows a comparison of the execution of the block designs when the computation times are not uniform, and the use of the getMinIteration function to generate designs which minimize the iteration time.

In [10]:
# Figure 5 (hangs if executed in Windows using Kaleido 0.1.0post1)
# try pip install kaleido==0.1.0post1
n = 6
t = np.ones(n)
l = np.ones((n,n))/10
t[0] = 6
t[2] = 6
t[3] = 6

for i in range(1, n//2+1):
    Zb, Wb = getBlockMin(n, i, builder=getMinResist)
    if i == 1:
        itrs = 6
    else:
        itrs = 7
    fig = getGantt(t, l, Zb, Wb, title=str(n//i)+"-Block", itrs=itrs)
    
    if saving: fig.write_image("figs/fig_misdp"+str(n//i)+"block.pdf")
    fig.show()

Z, W = getMinIteration(n, t=t, l=l, builder=getMinResist)

fig = getGantt(t, l, Z, W, title="Minimum Iteration", itrs=12)

if saving: fig.write_image("figs/fig_misdp_min_cycle.pdf")
fig.show()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

In several of the following examples, we use the PEP formulation to find the contraction factor for the algorithm designs in two scenarios:

  1. $(n)$ 2-Lipschitz 1-strongly monotone operators

  2. $(n-1)$ 2-Lipschitz 1-strongly monotone operators, and 1 unrestricted maximal monotone operator (this simulates having the subdifferential of an indicator function over some convex set)

In the figure 6 example, we use a fixed step size of 0.5.

We then compare the different algorithm designs, including the spectral objectives using our SDP, and some existing designs in the literature.

In [11]:
from warnings import warn
if 'MOSEK' not in cvx.installed_solvers():
    warn('''These experiments were conducted with Mosek as the underlying conic solver for CVXPY.  Mosek was not detected on your system. Running without Mosek will generate different results than those in the paper, including lack of convergence on larger problems.''')
In [12]:
# Figure 6 - contraction rate results
# fig_smoothstronglyconvex.ipynb
# Function to generate list of all test matrices
def getTestMatrices(n):
    cases = []
    Ws = []
    names = ['Full', 'MT']
    Lf, Wf = getFull(n)
    Mf = getMfromWCholesky(Wf)
    cases.append((Lf, Mf))
    Ws.append(Wf)
    Lmt, Wmt = getMT(n)
    Mmt = getMfromWCholesky(Wmt)
    cases.append((Lmt, Mmt))
    Ws.append(Wmt)
    i = n//2
    for obj in [getMinSLEM, getMinResist, getMaxConnectivity]:
        L, W = getBlockMin(n, i, builder=obj)
        M = getMfromWCholesky(W)
        cases.append((L, M))
        Ws.append(W)
        title = f"2-Block "+ obj.__name__
        names.append(title)
        
    return cases, names, Ws
    
def getMatrixContraction(cases, names, Lc=2, mu=1, gamma=0.5):
    '''Get contraction factors for matrix cases

    Args:
        cases (list): list of cases with L and M
        names (list): list of names
        Lc (float): Lipschitz constant
        mu (float): strong convexity parameter
        gamma (float): step size

    Returns:
        taus (dict): dictionary of contraction factors
    '''

    taus = {}
    for i, (L, M) in enumerate(cases):
        n = L.shape[0]
        
        ls = np.ones(n)*Lc
        mus = np.ones(n)*mu
        
        tau = getReducedContractionFactor(L, M, ls, mus)
        taus[names[i]] = tau
        print(names[i], tau)
    return taus
In [13]:
# Figure 6 helper
def testFixedRate(start=4, end=31, lc=2, mc=1):
    tau_results = defaultdict(list) 
    for n in range(start, end, 2):
        print(f"Testing optimal rate on {n} nodes")
        ls = np.ones(n) * lc
        mus = np.ones(n) * mc
        cases, names, Ws = getTestMatrices(n)
        for i, (L, M) in enumerate(cases):
            tau = getReducedContractionFactor(L, M, ls, mus)
            tau_results[names[i]].append(tau)


    # Convert results to df
    tau_df = pd.DataFrame(tau_results)
    tau_df.index = range(start, end, 2)

    return tau_df
In [14]:
# Figure 6a
tau_df = testFixedRate(start=6, end=31)
Testing optimal rate on 6 nodes
Testing optimal rate on 8 nodes
Testing optimal rate on 10 nodes
Testing optimal rate on 12 nodes
Testing optimal rate on 14 nodes
Testing optimal rate on 16 nodes
Testing optimal rate on 18 nodes
Testing optimal rate on 20 nodes
Testing optimal rate on 22 nodes
Testing optimal rate on 24 nodes
Testing optimal rate on 26 nodes
Testing optimal rate on 28 nodes
Testing optimal rate on 30 nodes
In [15]:
# Plot figure 6a
fig, ax = plt.subplots()
tau_df.plot(ax=ax)

ax.set_xlabel("n")
ax.set_ylabel("Contraction")
ax.set_title(r"Fixed step size contraction with $n$ Lipschitz strongly monotone operators")
ax.legend(['Full', 'MT', '2-Block Min SLEM', r'2-Block Min Resistance (also min $\|Z-W\|$)', '2-Block Max Fiedler'], loc=(0.25,0.4))
if saving: fig.savefig("figs/fig6a.pdf", format="pdf", bbox_inches="tight")
No description has been provided for this image
In [16]:
# Figure 6b helper
def testFixedRateProj(start=4, end=31, lc=2, mc=1):
    tau_results = defaultdict(list) 
    for n in range(start, end, 2):
        print(f"Testing optimal rate on {n} nodes")
        ls = np.ones(n) * lc
        ls[n-1] = np.inf
        mus = np.ones(n) * mc
        mus[n-1] = 0
        cases, names, Ws = getTestMatrices(n)
        for i, (Z, M) in enumerate(cases):
            tau = getReducedContractionFactor(Z, M, ls, mus)
            tau_results[names[i]].append(tau)


    # Convert results to df
    tau_df = pd.DataFrame(tau_results)
    tau_df.index = range(start, end, 2)

    return tau_df
In [17]:
# Figure 6b
tau_df = testFixedRateProj(start=6, end=31)
Testing optimal rate on 6 nodes
Testing optimal rate on 8 nodes
Testing optimal rate on 10 nodes
Testing optimal rate on 12 nodes
Testing optimal rate on 14 nodes
Testing optimal rate on 16 nodes
Testing optimal rate on 18 nodes
Testing optimal rate on 20 nodes
Testing optimal rate on 22 nodes
Testing optimal rate on 24 nodes
Testing optimal rate on 26 nodes
Testing optimal rate on 28 nodes
Testing optimal rate on 30 nodes
In [18]:
# Plot figure 6b
fig, ax = plt.subplots()
tau_df.plot(ax=ax)

ax.set_xlabel("n")
ax.set_ylabel("Contraction")
ax.set_title("Fixed step size contraction with an unrestricted monotone operator")
ax.legend(['Full', 'MT', '2-Block Min SLEM', r'2-Block Min Resistance (also min $\|Z-W\|$)', '2-Block Max Fiedler'], loc="lower right")
if saving: fig.savefig("figs/fig6b.pdf", format="pdf", bbox_inches="tight")
No description has been provided for this image

In figure 7 we repeat the analysis, but using an optimal step size we derive from an extension of the dual of the PEP. This also demonstrates the use of the getReducedContractionOptGamma function, which generates a step size which minimizes the contraction factor for the reduced version of the algorithm:

\begin{align} \mathrm{x} &= J_{\mathrm{A}}\left(-\mathrm{M}^{T} \mathrm{z}^{k} + \mathrm{L} \mathrm{x}\right)\\ \mathrm{z}^{k+1} &= \mathrm{z}^{k} + \gamma \mathrm{M} \mathrm{x}. \end{align}

where $M^T M = W$

In [19]:
# Figure 7 helper
def testOptimalRate(start=4, end=31, lc=2, mc=1):
    tau_results = defaultdict(list) 
    for n in range(start, end, 2):
        print(f"Testing optimal rate on {n} nodes")
        ls = np.ones(n) * lc
        ms = np.ones(n) * mc
        cases, names, Ws = getTestMatrices(n)
        for i, (Z, M) in enumerate(cases):
            tau, gamma = getReducedContractionOptGamma(Z, M, ls, ms)
            tau_results[names[i]].append(tau)


    # Convert results to df
    tau_df = pd.DataFrame(tau_results)
    tau_df.index = range(start, end, 2)

    return tau_df
In [20]:
# Figure 7 helper
def plotTau(tau_df, title):
    fig, ax = plt.subplots()
    tau_df.plot(ax=ax)
    ax.set_xlabel("n")
    ax.set_ylabel("Contraction") #$\\tau$
    ax.set_title(title)
    ax.legend(['Full', 'MT', '2-Block Min SLEM', r'2-Block Min Resistance (also min $\|Z-W\|$)', '2-Block Max Fiedler'], loc="center right")
    #ax.legend(loc='center right')
    #plt.show()
    return fig
In [21]:
# Figure 7
tau_df = testOptimalRate(start=4, end=31)

if saving: tau_df.to_csv("figs/fig_opt_gamma_strong.csv", index=False)
Testing optimal rate on 4 nodes
Testing optimal rate on 6 nodes
Testing optimal rate on 8 nodes
Testing optimal rate on 10 nodes
Testing optimal rate on 12 nodes
Testing optimal rate on 14 nodes
Testing optimal rate on 16 nodes
Testing optimal rate on 18 nodes
Testing optimal rate on 20 nodes
Testing optimal rate on 22 nodes
Testing optimal rate on 24 nodes
Testing optimal rate on 26 nodes
Testing optimal rate on 28 nodes
Testing optimal rate on 30 nodes
In [22]:
# Figure 7
fig = plotTau(tau_df, "Contraction over $n$ Lipschitz strongly monotone operators")
if saving: fig.savefig("figs/fig_opt_gamma_strong.pdf", format="pdf", bbox_inches="tight")
No description has been provided for this image
In [23]:
# Figure 7 helper
def testOptimalRateProj(start=4, end=31, lc=2, mc=1):
    tau_results = defaultdict(list) 
    for n in range(start, end, 2):
        print(f"Testing optimal rate on {n} nodes")
        ls = np.ones(n) * lc
        ls[n-1] = np.inf
        mus = np.ones(n) * mc
        mus[n-1] = 0
        cases, names, Ws = getTestMatrices(n)
        for i, (Z, M) in enumerate(cases):
            tau, _ = getReducedContractionOptGamma(Z, M, ls, mus)
            tau_results[names[i]].append(tau)


    # Convert results to df
    tau_df = pd.DataFrame(tau_results)
    tau_df.index = range(start, end, 2)

    return tau_df
In [24]:
# Figure 7b
tau_df = testOptimalRateProj(start=4, end=31)

if saving: tau_df.to_csv("figs/fig_opt_gamma_proj.csv", index=False)
Testing optimal rate on 4 nodes
Testing optimal rate on 6 nodes
Testing optimal rate on 8 nodes
Testing optimal rate on 10 nodes
Testing optimal rate on 12 nodes
Testing optimal rate on 14 nodes
Testing optimal rate on 16 nodes
Testing optimal rate on 18 nodes
Testing optimal rate on 20 nodes
Testing optimal rate on 22 nodes
Testing optimal rate on 24 nodes
Testing optimal rate on 26 nodes
Testing optimal rate on 28 nodes
Testing optimal rate on 30 nodes
In [25]:
# Figure 7b
fig = plotTau(tau_df, "Contraction with an unrestricted monotone operator")

if saving: fig.savefig("figs/fig7b.pdf", format="pdf", bbox_inches="tight")
No description has been provided for this image

In figure 8 we examine the impact of operator ordering on the contraction factor. In this example (and previous ones), we illustrate the use of some of the prebuilt matrix functions.

getMT(n) returns the Malitsky-Tam algorithm design over $n$ operators

getRyu(n) returns the Tam extension of the Ryu algorithm design over $n$ operators

getFull(n) returns the fully connected algorithm with equal weights over $n$ operators

We also use a helper function getMfromWCholesky to return a valid $M \in \mathbf{R}^{n-1 \times n}$ such that $M^T M = W$

In [26]:
# Figure 8 - operator ordering
Lc=2
mu=1


taus = defaultdict(list)
for n in range(4, 31, 2):
    print(f"Testing optimal rate on {n} nodes")
    Lb, Wb = getBlockMin(n, n//2)
    Mb = getMfromWCholesky(Wb)
    Lmt, Wmt = getMT(n)
    Mmt = getMfromWCholesky(Wmt)
    Lr, Wr = getRyu(n)
    Mr = getMfromWCholesky(Wr)
    Lmax, Wmax = getFull(n)
    Mmax = getMfromWCholesky(Wmax)

    cases = [(Lb, Mb), (Lmt, Mmt), (Lr, Mr), (Lmax, Mmax)]
    names = ["2-Block", "MT", "Ryu", "Full"]
    ls = np.ones(n)*Lc
    ls[n-1] = np.inf
    mus = np.ones(n)*mu
    mus[n-1] = 0
    for i, (Z, M) in enumerate(cases):
        tau, _ = getReducedContractionOptGamma(Z, M, ls, mus)
        taus[names[i]].append(tau)

    ls = np.ones(n)*Lc
    ls[0] = np.inf
    mus = np.ones(n)*mu
    mus[0] = 0
    for i, (Z, M) in enumerate(cases):
        tau, _ = getReducedContractionOptGamma(Z, M, ls, mus)        
        taus[names[i]+" reverse"].append(tau)
Testing optimal rate on 4 nodes
Testing optimal rate on 6 nodes
Testing optimal rate on 8 nodes
Testing optimal rate on 10 nodes
Testing optimal rate on 12 nodes
Testing optimal rate on 14 nodes
Testing optimal rate on 16 nodes
Testing optimal rate on 18 nodes
Testing optimal rate on 20 nodes
Testing optimal rate on 22 nodes
Testing optimal rate on 24 nodes
Testing optimal rate on 26 nodes
Testing optimal rate on 28 nodes
Testing optimal rate on 30 nodes
In [27]:
# Figure 8 - operator ordering
df = pd.DataFrame(taus)
df.index = range(4, 31, 2)

# Plot the results
colors = ['blue', 'green', 'red', 'purple']
styles = ['b-', 'g-', 'k-', 'm-', 'y--', 'c--', 'r--', 'p--']
styles = ['b-', 'g-', 'k-', 'm-', 'b*-', 'g*-', 'k*-', 'm*-']

if saving: df.to_csv("figs/fig_function_ordering_opt.csv", index=False)
df.plot(style=styles)
plt.xlabel("Number of nodes")
plt.ylabel("Contraction")
plt.title("Operator Ordering and Splitting Performance")

if saving: plt.savefig("figs/fig_function_order_opt.pdf", format="pdf", bbox_inches="tight")
plt.show()
No description has been provided for this image

Figure 9 examines the impact of block count in the $d$-Block designs on the reduced contraction factor.

In [28]:
# Figure 9 - block size

# Function to generate list of all test matrices
def getTestMatricesBlocks(n):
    cases = []
    names = ['Full', 'MT']
    objs = ['Full', 'MT']
    blocksizes = ['', '']
    blocklist = ['', '']
    Lf, Wf = getFull(n)
    Mf = getMfromWCholesky(Wf)
    cases.append((Lf, Mf))
    Lmt, Wmt = getMT(n)
    Mmt = getMfromWCholesky(Wmt)
    cases.append((Lmt, Mmt))
    objstring = ['MinSLEM', 'MinResist', 'getMaxConnectivity', 'Min |Z-W|']
    for i in range(2, n//2+1):
        if n % i != 0:
            continue
        for j, obj in enumerate([getMinSLEM, getMinResist, getMaxConnectivity, getMinSpectralDifference]):
            L, W = getBlockMin(n, i, builder=obj)
            M = getMfromWCholesky(W)
            cases.append((L, M))
            objs.append(objstring[j])
            blocksizes.append(i)
            blocklist.append(n//i)
            title = f"{n//i}-Block "+objstring[j]
            names.append(title)
        
    return cases, names, objs, blocksizes, blocklist

# Test function
def testMatrices(cases, names, lc=2, mu=1):
        
    taus = {}
    for i, (L, M) in enumerate(cases):
        ls = np.ones(len(L))*lc
        mus = np.ones(len(L))*mu
        
        tau, _ = getReducedContractionOptGamma(L, M, ls, mus)
        print(names[i], tau)
        taus[names[i]] = tau

    return taus

    
In [29]:
# Figure 9
results = []
for n in range(4, 25): #t < 120:
    print(n)
    cases, names, objs, blocksizes, blocks = getTestMatricesBlocks(n)
    taus = testMatrices(cases, names)
    # Each key in taus is a column, the row is the value of n
    for i in range(len(names)):
        k = names[i]
        v = taus[k]
        results.append({"n": n, "name": k, "obj": objs[i], "blocksize": blocksizes[i], "blocks":blocks[i], "tau": v})

df = pd.DataFrame(results)

if saving: df.to_csv("figs/taus_plus.csv", index=False)
df.set_index('n', inplace=True)
4
Full 0.42757264243870163
MT 0.8002281453197669
2-Block MinSLEM 0.5571563320360297
2-Block MinResist 0.42857143084394755
2-Block getMaxConnectivity 0.4723279099751601
2-Block Min |Z-W| 0.42857142974428214
5
Full 0.4476922209675467
MT 0.8613717840444194
6
Full 0.4592582042344319
MT 0.8973983347682897
3-Block MinSLEM 0.7135848361436024
3-Block MinResist 0.7182631442291106
3-Block getMaxConnectivity 0.7125769075299765
3-Block Min |Z-W| 0.7146237387649743
2-Block MinSLEM 0.5571562848352016
2-Block MinResist 0.4285714345044067
2-Block getMaxConnectivity 0.4884713576568497
2-Block Min |Z-W| 0.4285714294945957
7
Full 0.4667573414540386
MT 0.9210285463263077
8
Full 0.47200715470169285
MT 0.9373167138798192
4-Block MinSLEM 0.830902661865993
4-Block MinResist 0.8108953222170883
4-Block getMaxConnectivity 0.8002350026587245
4-Block Min |Z-W| 0.9414775041852568
2-Block MinSLEM 0.5571562864004252
2-Block MinResist 0.42857143242269075
2-Block getMaxConnectivity 0.4971297780170147
2-Block Min |Z-W| 0.42857157367446364
9
Full 0.47588407918368236
MT 0.9490542144444052
3-Block MinSLEM 0.7139323261605606
3-Block MinResist 0.7182631341824356
3-Block getMaxConnectivity 0.7138583593909309
3-Block Min |Z-W| 0.7154474793706733
10
Full 0.47886238699142825
MT 0.9578086304484189
5-Block MinSLEM 0.8909710612103936
5-Block MinResist 0.8675177048793344
5-Block getMaxConnectivity 0.869466506289027
5-Block Min |Z-W| 0.8841703860126198
2-Block MinSLEM 0.5571562868119783
2-Block MinResist 0.4285714375495388
2-Block getMaxConnectivity 0.5007530033325157
2-Block Min |Z-W| 0.4285714341245416
11
Full 0.48122091775576215
MT 0.9645090300428389
12
Full 0.4831342670605387
MT 0.9697458591678797
6-Block MinSLEM 0.9274863709906866
6-Block MinResist 0.9043223463177122
6-Block getMaxConnectivity 0.9144355840496884
6-Block Min |Z-W| 0.9723015042825072
4-Block MinSLEM 0.8306043397184802
4-Block MinResist 0.8108995469242436
4-Block getMaxConnectivity 0.8002302736642987
4-Block Min |Z-W| 0.9732200751628457
3-Block MinSLEM 0.7138823830882524
3-Block MinResist 0.7182631630830557
3-Block getMaxConnectivity 0.7152305558438894
3-Block Min |Z-W| 0.7154244052790969
2-Block MinSLEM 0.557156288107003
2-Block MinResist 0.4285714382735192
2-Block getMaxConnectivity 0.5048842320957917
2-Block Min |Z-W| 0.42857143414684185
13
Full 0.48471718030959554
MT 0.973913351855411
14
Full 0.4860481904482468
MT 0.9772819066072854
7-Block MinSLEM 0.9487402257486269
7-Block MinResist 0.9275962948707096
7-Block getMaxConnectivity 0.9415108622982323
7-Block Min |Z-W| 0.9379760461799428
2-Block MinSLEM 0.5571563188192495
2-Block MinResist 0.42857144512733913
2-Block getMaxConnectivity 0.5053543890781282
2-Block Min |Z-W| 0.4285714453701384
15
Full 0.4871828194233887
MT 0.9800422357402336
5-Block MinSLEM 0.8909885739345229
5-Block MinResist 0.8675200794119812
5-Block getMaxConnectivity 0.8694664535695392
5-Block Min |Z-W| 0.8841741753141091
3-Block MinSLEM 0.7141463212211673
3-Block MinResist 0.718263141982153
3-Block getMaxConnectivity 0.715183390367131
3-Block Min |Z-W| 0.7154940848780356
16
Full 0.4881613958305979
MT 0.982331559673419
8-Block MinSLEM 0.9617907227705366
8-Block MinResist 0.9432016873516004
8-Block getMaxConnectivity 0.9547829224218511
8-Block Min |Z-W| 0.984315427519989
4-Block MinSLEM 0.8305473874473303
4-Block MinResist 0.8108999202040502
4-Block getMaxConnectivity 0.8002305185657219
4-Block Min |Z-W| 0.9847811629632465
2-Block MinSLEM 0.5571562810349651
2-Block MinResist 0.42857145418996156
2-Block getMaxConnectivity 0.5061192608525976
2-Block Min |Z-W| 0.4285714564445944
17
Full 0.48901400167960424
MT 0.9842506483711779
18
Full 0.48976341389760036
MT 0.9858748663019703
9-Block MinSLEM 0.9703808981664126
9-Block MinResist 0.9543244228002966
9-Block getMaxConnectivity 0.9652620346221316
9-Block Min |Z-W| 0.9609559413299223
6-Block MinSLEM 0.9274863340746433
6-Block MinResist 0.904322100241284
6-Block getMaxConnectivity 0.9144368470036185
6-Block Min |Z-W| 0.9877641370733509
3-Block MinSLEM 0.7137591263145242
3-Block MinResist 0.7182631394317455
3-Block getMaxConnectivity 0.7156777756442414
3-Block Min |Z-W| 0.7151300210105594
2-Block MinSLEM 0.5571562751599648
2-Block MinResist 0.42857145889844994
2-Block getMaxConnectivity 0.5065757352882716
2-Block Min |Z-W| 0.428571459613919
19
Full 0.49042725685598576
MT 0.9872613997720258
20
Full 0.49101936604430657
MT 0.98845429318482
10-Block MinSLEM 0.9764918850332077
10-Block MinResist 0.9624236295054766
10-Block getMaxConnectivity 0.9726918301243737
10-Block Min |Z-W| 0.9899039312310299
5-Block MinSLEM 0.8909604820256735
5-Block MinResist 0.8675196430797856
5-Block getMaxConnectivity 0.8694657973902343
5-Block Min |Z-W| 0.884178006461683
4-Block MinSLEM 0.8306546228248091
4-Block MinResist 0.8108995981777251
4-Block getMaxConnectivity 0.8002313721274206
4-Block Min |Z-W| 0.9902135583151264
2-Block MinSLEM 0.5571562921308666
2-Block MinResist 0.42857146164342896
2-Block getMaxConnectivity 0.5073479496225984
2-Block Min |Z-W| 0.4285714623264254
21
Full 0.4915507533342952
MT 0.9894878242785429
7-Block MinSLEM 0.9487432477656033
7-Block MinResist 0.9275963069810571
7-Block getMaxConnectivity 0.9415195185314065
7-Block Min |Z-W| 0.9379767047811336
3-Block MinSLEM 0.7135615903082121
3-Block MinResist 0.7182631426601115
3-Block getMaxConnectivity 0.7154026655455449
3-Block Min |Z-W| 0.7151513652959529
22
Full 0.49203028591117437
MT 0.9903890671242299
11-Block MinSLEM 0.980965610799092
11-Block MinResist 0.9685141496628001
11-Block getMaxConnectivity 0.9778676717877701
11-Block Min |Z-W| 0.9734129802155151
2-Block MinSLEM 0.5571562777399365
2-Block MinResist 0.4285714662419582
2-Block getMaxConnectivity 0.5091397539683903
2-Block Min |Z-W| 0.428571466254424
23
Full 0.4924651929745758
MT 0.9911795563889043
24
Full 0.49286136387229174
MT 0.9918767125518874
12-Block MinSLEM 0.9842233582587118
12-Block MinResist 0.9732178088159736
12-Block getMaxConnectivity 0.9816646292439926
12-Block Min |Z-W| 0.9929855790344766
8-Block MinSLEM 0.9617899146861579
8-Block MinResist 0.9432016721407476
8-Block getMaxConnectivity 0.95478284148592
8-Block Min |Z-W| 0.9930940221197248
6-Block MinSLEM 0.9274864246060913
6-Block MinResist 0.904322406355109
6-Block getMaxConnectivity 0.9144367580545995
6-Block Min |Z-W| 0.9931276194555293
4-Block MinSLEM 0.8310241284105948
4-Block MinResist 0.8108982477563402
4-Block getMaxConnectivity 0.8002305221536402
4-Block Min |Z-W| 0.9931862824346592
3-Block MinSLEM 0.713933211150172
3-Block MinResist 0.7182631402120045
3-Block getMaxConnectivity 0.7152482065677889
3-Block Min |Z-W| 0.7152800293010432
2-Block MinSLEM 0.5571562808431788
2-Block MinResist 0.4285714310144653
2-Block getMaxConnectivity 0.5099386146815007
2-Block Min |Z-W| 0.42857147069660706
In [30]:
# Figure 9
df[df["obj"].isin(["MinResist", "Full", "MT"])].groupby(['obj', 'blocks'])['tau'].plot(marker='o', linestyle='-', figsize=(10, 6))
keys = ['Full', 'MT', '2-Block', '3-Block', '4-Block', '5-Block', '6-Block', '7-Block', '8-Block', '9-Block', '10-Block', '11-Block', '12-Block']
plt.legend(keys, bbox_to_anchor=(1, 1))

# Make x axis integer
plt.xticks(np.arange(4, 25, 2))
plt.xlabel(r"$n$")
plt.title("Min Resistance Contraction over $n$ Lipschitz Strongly Monotone Operators by Block Number")
if saving: plt.savefig("figs/fig_block_count.pdf", format="pdf", bbox_inches="tight")
No description has been provided for this image
In [31]:
# Figure 9 - Test function
def testMatricesProj(n, cases, names, lc=2, mu=1):
    ls = np.ones(n)*lc
    mus = np.ones(n)*mu
    ls[n-1] = np.inf
    mus[n-1] = 0
    taus = {}
    for i, (Z, M) in enumerate(cases):
        tau, _ = getReducedContractionOptGamma(Z, M, ls, mus)
        print(names[i], tau)
        taus[names[i]] = tau

    return taus
In [32]:
# Figure 9
projresults = []
for n in range(4,26): #t < 120:
    print(n)
    cases, names, objs, blocksizes, blocks = getTestMatricesBlocks(n)
    taus = testMatricesProj(n, cases, names)
    # Each key in taus is a column, the row is the value of n
    for i in range(len(names)):
        k = names[i]
        v = taus[k]
        
        projresults.append({"n": n, "name": k, "obj": objs[i], "blocksize": blocksizes[i], "blocks":blocks[i], "tau": v})

projdf = pd.DataFrame(projresults)
if saving: projdf.to_csv("figs/taus_proj.csv", index=False)
projdf.set_index('n', inplace=True)
4
Full 0.7521521274547781
MT 0.9177841369745806
2-Block MinSLEM 0.8191387832636592
2-Block MinResist 0.7870338922102957
2-Block getMaxConnectivity 0.8005884054570187
2-Block Min |Z-W| 0.7870338929300079
5
Full 0.804479212788819
MT 0.9475773165769151
6
Full 0.8385587406685645
MT 0.9636790407235943
3-Block MinSLEM 0.9045292083157187
3-Block MinResist 0.898926309334002
3-Block getMaxConnectivity 0.9031665202361303
3-Block Min |Z-W| 0.9058115649311607
2-Block MinSLEM 0.8708680920365539
2-Block MinResist 0.8616700832093386
2-Block getMaxConnectivity 0.8648381115685787
2-Block Min |Z-W| 0.861670081386794
7
Full 0.8625324131656764
MT 0.9733944272799407
8
Full 0.8803148080938081
MT 0.9796953548701692
4-Block MinSLEM 0.9477391187338774
4-Block MinResist 0.9366150047224902
4-Block getMaxConnectivity 0.9409099369418765
4-Block Min |Z-W| 0.9733653147481017
2-Block MinSLEM 0.8996656566051273
2-Block MinResist 0.8973584358184201
2-Block getMaxConnectivity 0.8970613583905448
2-Block Min |Z-W| 0.8973584363621916
9
Full 0.8940287042166508
MT 0.9840061423604585
3-Block MinSLEM 0.9310037419769321
3-Block MinResist 0.9226238048817228
3-Block getMaxConnectivity 0.9308683371516419
3-Block Min |Z-W| 0.9329275875236587
10
Full 0.9049261834616941
MT 0.987082059420084
5-Block MinSLEM 0.9690123236522284
5-Block MinResist 0.9580312775971841
5-Block getMaxConnectivity 0.962997391632803
5-Block Min |Z-W| 0.962987675833271
2-Block MinSLEM 0.9180267565103377
2-Block MinResist 0.9183673760071445
2-Block getMaxConnectivity 0.9166915390957012
2-Block Min |Z-W| 0.9183673754845927
11
Full 0.9137934450814728
MT 0.9893521326450776
12
Full 0.9211491280506132
MT 0.9910743537751785
6-Block MinSLEM 0.9794380910215909
6-Block MinResist 0.9701555310272644
6-Block getMaxConnectivity 0.9756973867550393
6-Block Min |Z-W| 0.99010537100968
4-Block MinSLEM 0.9594824501758149
4-Block MinResist 0.9489711986483735
4-Block getMaxConnectivity 0.9564358341424667
4-Block Min |Z-W| 0.9875641253599383
3-Block MinSLEM 0.9461116981534052
3-Block MinResist 0.9376136641003483
3-Block getMaxConnectivity 0.9476885966471409
3-Block Min |Z-W| 0.9478983876056438
2-Block MinSLEM 0.9307344399513203
2-Block MinResist 0.9322246586548163
2-Block getMaxConnectivity 0.9300141956611677
2-Block Min |Z-W| 0.932224658678786
13
Full 0.9273491859704465
MT 0.992411364833255
14
Full 0.932645842257762
MT 0.993469781964156
7-Block MinSLEM 0.9854895007855449
7-Block MinResist 0.9778942634910617
7-Block getMaxConnectivity 0.9826255537601088
7-Block Min |Z-W| 0.9813969384739117
2-Block MinSLEM 0.9400431051319242
2-Block MinResist 0.942055224496676
2-Block getMaxConnectivity 0.9396299797588917
2-Block Min |Z-W| 0.9420552246279732
15
Full 0.937223186841485
MT 0.9943217922540158
5-Block MinSLEM 0.974590401353922
5-Block MinResist 0.9649800729630257
5-Block getMaxConnectivity 0.9710959252251317
5-Block Min |Z-W| 0.9698525014507775
3-Block MinSLEM 0.9561864907177353
3-Block MinResist 0.9478753095789055
3-Block getMaxConnectivity 0.9572607197744706
3-Block Min |Z-W| 0.9575677751989082
16
Full 0.9412182809698121
MT 0.9950176830138516
8-Block MinSLEM 0.989233292652846
8-Block MinResist 0.9829428678589387
8-Block getMaxConnectivity 0.9871235601177183
8-Block Min |Z-W| 0.9951900480677953
4-Block MinSLEM 0.9670904965450355
4-Block MinResist 0.9575260060505665
4-Block getMaxConnectivity 0.9660447128654579
4-Block Min |Z-W| 0.992835672581666
2-Block MinSLEM 0.9471521763588353
2-Block MinResist 0.9493931058277882
2-Block getMaxConnectivity 0.9469224619297711
2-Block Min |Z-W| 0.9493931076789691
17
Full 0.9447354996217051
MT 0.9955932803549359
18
Full 0.947855785340868
MT 0.996074790975494
9-Block MinSLEM 0.9917523326892693
9-Block MinResist 0.9865002011040845
9-Block getMaxConnectivity 0.9901485632323862
9-Block Min |Z-W| 0.9891810853182708
6-Block MinSLEM 0.9825422672544786
6-Block MinResist 0.9744372782097804
6-Block getMaxConnectivity 0.9802334300928883
6-Block Min |Z-W| 0.9955573342110063
3-Block MinSLEM 0.9625973759072839
3-Block MinResist 0.9552965512070167
3-Block getMaxConnectivity 0.9643509557610295
3-Block Min |Z-W| 0.9639152802684406
2-Block MinSLEM 0.9527572967367829
2-Block MinResist 0.955080203083856
2-Block getMaxConnectivity 0.9526415889171332
2-Block Min |Z-W| 0.9550802035807573
19
Full 0.9506426888675692
MT 0.996481611885768
20
Full 0.9531469126958941
MT 0.9968284121901984
10-Block MinSLEM 0.9933658104372783
10-Block MinResist 0.989021596450872
10-Block getMaxConnectivity 0.9921891728606781
10-Block Min |Z-W| 0.9972491010019479
5-Block MinSLEM 0.9784205059914235
5-Block MinResist 0.9700027732901295
5-Block getMaxConnectivity 0.9767083161681916
5-Block Min |Z-W| 0.9748735206170638
4-Block MinSLEM 0.9721919454461948
4-Block MinResist 0.9637516383754409
4-Block getMaxConnectivity 0.9724264674719896
4-Block Min |Z-W| 0.995348815017694
2-Block MinSLEM 0.9572893031112173
2-Block MinResist 0.9596176455086766
2-Block getMaxConnectivity 0.9572470127241994
2-Block Min |Z-W| 0.9596176491745421
21
Full 0.9554093767969243
MT 0.9971264271830746
7-Block MinSLEM 0.9874743330706199
7-Block MinResist 0.9805966970219246
7-Block getMaxConnectivity 0.9859754616666889
7-Block Min |Z-W| 0.983739405930636
3-Block MinSLEM 0.9674384858406184
3-Block MinResist 0.9608952673738557
3-Block getMaxConnectivity 0.9689905900505172
3-Block Min |Z-W| 0.9688040622222985
22
Full 0.9574634693504498
MT 0.9973843798894533
11-Block MinSLEM 0.9945861578488714
11-Block MinResist 0.9908850425394582
11-Block getMaxConnectivity 0.9936949377169232
11-Block Min |Z-W| 0.9930500080406014
2-Block MinSLEM 0.9610289962695155
2-Block MinResist 0.9633222012558504
2-Block getMaxConnectivity 0.9610325830839557
2-Block Min |Z-W| 0.9633222012846975
23
Full 0.9593367015363286
MT 0.997609135727751
24
Full 0.9610519693853471
MT 0.9978061502071545
12-Block MinSLEM 0.9954966213190756
12-Block MinResist 0.992309516621772
12-Block getMaxConnectivity 0.9947939665976838
12-Block Min |Z-W| 0.9982502783079058
8-Block MinSLEM 0.9904306964795818
8-Block MinResist 0.9847609731860296
8-Block getMaxConnectivity 0.9894469413820468
8-Block Min |Z-W| 0.9978752519048323
6-Block MinSLEM 0.9855246976114859
6-Block MinResist 0.9776570058927866
6-Block getMaxConnectivity 0.9841645839948792
6-Block Min |Z-W| 0.9974805118666883
4-Block MinSLEM 0.9756430722135762
4-Block MinResist 0.9684466642076521
4-Block getMaxConnectivity 0.9763035559878469
4-Block Min |Z-W| 0.996738808067415
3-Block MinSLEM 0.9715913532679965
3-Block MinResist 0.9652615861029722
3-Block getMaxConnectivity 0.972578833986059
3-Block Min |Z-W| 0.9726116359656548
2-Block MinSLEM 0.9641672314385882
2-Block MinResist 0.96640390378116
2-Block getMaxConnectivity 0.9642023236849637
2-Block Min |Z-W| 0.9664039049574353
25
Full 0.9626284123300337
MT 0.9979798028060392
5-Block MinSLEM 0.9811923650459194
5-Block MinResist 0.9738455481222618
5-Block getMaxConnectivity 0.9805674471032336
5-Block Min |Z-W| 0.9784107033246009
In [33]:
# Figure 9 Class 2 

projdf[projdf["obj"].isin(["MinResist", "Full", "MT"])].groupby(['obj', 'blocks'])['tau'].plot(marker='o', linestyle='-', figsize=(10, 6))

keys = ['Full', 'MT', '2-Block', '3-Block', '4-Block', '5-Block', '6-Block', '7-Block', '8-Block', '9-Block', '10-Block', '11-Block', '12-Block'] # If using df directly
plt.legend(keys, bbox_to_anchor=(1, 1))
plt.title("Min Resistance Contraction over $n-1$ Lipschitz Strongly Monotone Operators")
if saving: plt.savefig("figs/fig_block_count_proj.pdf", format="pdf", bbox_inches="tight")
No description has been provided for this image

Figure 10 combines the iteration time and contraction factor to depict how removing edges impacts algorithm design. We see that the 2-Block design strikes the optimal balance between connectivity (for faster contraction) and sparseness (for parallelism and faster iteration times)

This uses the getIterationTime function to return the iteration time.

In [34]:
# Figure 10 - pareto curves

from matplotlib.colors import CenteredNorm
def getTaus(Z, W, l=None, mu=None):

    M = getMfromWCholesky(W)
    h = getReducedContractionFactor(Z, M, l, mu, gamma=0.5)
    m, _ = getReducedContractionOptGamma(Z, M, l, mu)
    return h, m

def getContractTime(n, l, mu, builder=None, tol=0.5):
    Z_fixed = {}

    t = np.ones(n)
    ll = np.ones((n,n))
    results = {}
    for i in range(n//2):
        print(i)
        start = 0
        for k in range(2):
            for j in range(start, i + k*(n//2)):
                Z_fixed[(i + k*(n//2),j)] = 0
            Zs, Ws = builder(n, fixed_Z=Z_fixed)
            h, m = getTaus(Zs, Ws, l, mu)
            tt, _, _ = getIterationTime(t, ll, Zs, Ws, itrs=2)
            # r is number of entries in Z_fixed
            r = len(Z_fixed)
            tif = np.ceil(np.log(tol)/np.log(h)) # Total iterations fixed
            tio = np.ceil(np.log(tol)/np.log(m)) # Total iterations opt step
            ttf = tif*tt
            tto = tio*tt
            results[r] = {'Fixed':h , 'M Opt': m, 'Time': tt, 'Removed Edges': r, 'Fixed Total Iterations': tif, 'Opt Step Total Iterations': tio, 'Fixed Total Time': ttf, 'Opt Step Total Time': tto}
            print(results[r])
            start = n//2

    counter = 0
    for i in range(n//2 - 2):
        for j in range(i+1):
            r = n//2 + j
            c = n//2 - 1 - i + j
            Z_fixed[(r, c)] = 0
            counter += 1
            if counter % 10 == 0:
                Ls, Ws = builder(n, fixed_Z=Z_fixed)
                h, m = getTaus(Ls, Ws, l, mu)
                tt = 4
                # r is number of entries in Z_fixed
                rem = len(Z_fixed)    
                tif = np.ceil(np.log(tol)/np.log(h)) # Total iterations fixed
                tio = np.ceil(np.log(tol)/np.log(m)) # Total iterations opt step
                ttf = tif*tt
                tto = tio*tt
                results[rem] = {'Fixed':h , 'M Opt': m, 'Time': tt, 'Removed Edges': rem, 'Fixed Total Iterations': tif, 'Opt Step Total Iterations': tio, 'Fixed Total Time': ttf, 'Opt Step Total Time': tto}
                print(results[rem])
    # Create dataframe of taus and times
    df = pd.DataFrame(results)

    return df
In [35]:
# Figure 10
n = 24
l = np.ones(n)*2
l[n-1] = np.inf
mu = np.ones(n)
mu[n-1]= 0

df = getContractTime(n, l, mu, builder=getMaxConnectivity)
df2 = df.T
0
{'Fixed': 0.9798415277460015, 'M Opt': 0.9610519693852897, 'Time': 47.99999999999555, 'Removed Edges': 0, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1679.9999999998442, 'Opt Step Total Time': 863.99999999992}
{'Fixed': 0.9798415277460015, 'M Opt': 0.9610519693852897, 'Time': 47.99999999999555, 'Removed Edges': 0, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1679.9999999998442, 'Opt Step Total Time': 863.99999999992}
1
{'Fixed': 0.9802934217043753, 'M Opt': 0.9611344874981325, 'Time': 46.00000000002653, 'Removed Edges': 1, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1610.0000000009286, 'Opt Step Total Time': 828.0000000004776}
{'Fixed': 0.9802906549740917, 'M Opt': 0.9612008911742602, 'Time': 44.00000000001397, 'Removed Edges': 2, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1540.0000000004889, 'Opt Step Total Time': 792.0000000002515}
2
{'Fixed': 0.9803115291134975, 'M Opt': 0.9612841961148996, 'Time': 41.999999999993534, 'Removed Edges': 4, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1469.9999999997738, 'Opt Step Total Time': 755.9999999998836}
{'Fixed': 0.9803217937756855, 'M Opt': 0.9613404323358163, 'Time': 40.00000000033529, 'Removed Edges': 6, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1400.0000000117352, 'Opt Step Total Time': 720.0000000060352}
3
{'Fixed': 0.9803594774713668, 'M Opt': 0.9614511691184635, 'Time': 38.00000000019668, 'Removed Edges': 9, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1330.0000000068837, 'Opt Step Total Time': 684.0000000035402}
{'Fixed': 0.9803725407513265, 'M Opt': 0.9615160721244879, 'Time': 36.00000000005643, 'Removed Edges': 12, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1260.0000000019752, 'Opt Step Total Time': 648.0000000010158}
4
{'Fixed': 0.9804160035586761, 'M Opt': 0.9616398317573042, 'Time': 34.00000000000089, 'Removed Edges': 16, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1224.000000000032, 'Opt Step Total Time': 612.000000000016}
{'Fixed': 0.9803159903286937, 'M Opt': 0.9616501789931347, 'Time': 32.00000000018983, 'Removed Edges': 20, 'Fixed Total Iterations': 35.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1120.000000006644, 'Opt Step Total Time': 576.000000003417}
5
{'Fixed': 0.9805064778081075, 'M Opt': 0.9618143984054425, 'Time': 29.99999999993441, 'Removed Edges': 25, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1079.9999999976387, 'Opt Step Total Time': 539.9999999988194}
{'Fixed': 0.9805369849103691, 'M Opt': 0.9618911233999475, 'Time': 28.000000000015845, 'Removed Edges': 30, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 1008.0000000005705, 'Opt Step Total Time': 504.00000000028524}
6
{'Fixed': 0.980558744118224, 'M Opt': 0.9619696358581257, 'Time': 26.00000000018838, 'Removed Edges': 36, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 936.0000000067816, 'Opt Step Total Time': 468.0000000033908}
{'Fixed': 0.9806165695795973, 'M Opt': 0.9620812351429494, 'Time': 23.999999999924594, 'Removed Edges': 42, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 18.0, 'Fixed Total Time': 863.9999999972854, 'Opt Step Total Time': 431.9999999986427}
7
{'Fixed': 0.9805803035543116, 'M Opt': 0.9622244218633337, 'Time': 22.000000000001247, 'Removed Edges': 49, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 792.0000000000449, 'Opt Step Total Time': 418.0000000000237}
{'Fixed': 0.980609771943829, 'M Opt': 0.9623042101456656, 'Time': 19.999999999880224, 'Removed Edges': 56, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 719.9999999956881, 'Opt Step Total Time': 379.9999999977243}
8
{'Fixed': 0.9806705602427209, 'M Opt': 0.962424427613141, 'Time': 17.99999999994352, 'Removed Edges': 64, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 647.9999999979667, 'Opt Step Total Time': 341.99999999892685}
{'Fixed': 0.9807014558127024, 'M Opt': 0.9624855242813694, 'Time': 15.999999999994683, 'Removed Edges': 72, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 575.9999999998086, 'Opt Step Total Time': 303.999999999899}
9
{'Fixed': 0.9808093208410873, 'M Opt': 0.9627105025538466, 'Time': 14.000000000000362, 'Removed Edges': 81, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 504.0000000000131, 'Opt Step Total Time': 266.0000000000069}
{'Fixed': 0.9808410857473983, 'M Opt': 0.9627679103019492, 'Time': 11.9999999999999, 'Removed Edges': 90, 'Fixed Total Iterations': 36.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 431.9999999999964, 'Opt Step Total Time': 227.99999999999812}
10
{'Fixed': 0.9810231148410529, 'M Opt': 0.96304306184268, 'Time': 10.000000000165414, 'Removed Edges': 100, 'Fixed Total Iterations': 37.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 370.00000000612033, 'Opt Step Total Time': 190.00000000314287}
{'Fixed': 0.9810393061615912, 'M Opt': 0.9630413776592729, 'Time': 7.999999999999933, 'Removed Edges': 110, 'Fixed Total Iterations': 37.0, 'Opt Step Total Iterations': 19.0, 'Fixed Total Time': 295.99999999999756, 'Opt Step Total Time': 151.99999999999872}
11
{'Fixed': 0.9813641777345405, 'M Opt': 0.9642038633930519, 'Time': 3.9999999999999907, 'Removed Edges': 121, 'Fixed Total Iterations': 37.0, 'Opt Step Total Iterations': 20.0, 'Fixed Total Time': 147.99999999999966, 'Opt Step Total Time': 79.99999999999982}
{'Fixed': 0.9813651787490266, 'M Opt': 0.9642023236823605, 'Time': 3.9999999999999907, 'Removed Edges': 132, 'Fixed Total Iterations': 37.0, 'Opt Step Total Iterations': 20.0, 'Fixed Total Time': 147.99999999999966, 'Opt Step Total Time': 79.99999999999982}
{'Fixed': 0.9838400213581495, 'M Opt': 0.9652843225004955, 'Time': 4, 'Removed Edges': 142, 'Fixed Total Iterations': 43.0, 'Opt Step Total Iterations': 20.0, 'Fixed Total Time': 172.0, 'Opt Step Total Time': 80.0}
{'Fixed': 0.9853883421029684, 'M Opt': 0.9669002363662484, 'Time': 4, 'Removed Edges': 152, 'Fixed Total Iterations': 48.0, 'Opt Step Total Iterations': 21.0, 'Fixed Total Time': 192.0, 'Opt Step Total Time': 84.0}
{'Fixed': 0.9868013528993385, 'M Opt': 0.968647136449619, 'Time': 4, 'Removed Edges': 162, 'Fixed Total Iterations': 53.0, 'Opt Step Total Iterations': 22.0, 'Fixed Total Time': 212.0, 'Opt Step Total Time': 88.0}
{'Fixed': 0.9886689502714882, 'M Opt': 0.9699045194765014, 'Time': 4, 'Removed Edges': 172, 'Fixed Total Iterations': 61.0, 'Opt Step Total Iterations': 23.0, 'Fixed Total Time': 244.0, 'Opt Step Total Time': 92.0}
{'Fixed': 0.9912682146833666, 'M Opt': 0.9724128400046071, 'Time': 4, 'Removed Edges': 182, 'Fixed Total Iterations': 80.0, 'Opt Step Total Iterations': 25.0, 'Fixed Total Time': 320.0, 'Opt Step Total Time': 100.0}
In [36]:
if saving: df.to_csv('figs/n24.csv', index=False)

# Plot total time vs removed edges
plt.plot(df.iloc[3], df.iloc[6], df.iloc[3], df.iloc[7])
# Subtitle
plt.suptitle('Time Units to 0.5 Contraction vs Removed Edges, $n=$'+str(n))


plt.legend( ['Fixed Step Size', 'Optimal Step Size'])
plt.xlabel('Removed Edges')
plt.ylabel('Time Units')
if saving: plt.savefig("figs/fig_optimal_sparsity.pdf", format="pdf", bbox_inches="tight")
plt.show()
No description has been provided for this image
In [37]:
# Figure 10
# Plot the top three rows of df as a function of time with points annotated
plt.plot(df.iloc[2], df.iloc[0], marker='<')
plt.plot(df.iloc[2], df.iloc[1], marker='<')

plt.title('Contraction vs Time as Edges are Removed')
# Add legend
plt.legend( ['Fixed Step Size', 'Optimal Step Size'])
# Annotate points with number of removed edges
lx, ly = (0,0)
right = 0
up = 10
for j in range(len(df.columns)):
        print(j,(df.iloc[2,j], df.iloc[1,j]))
        if df.iloc[2,j] < 4:
                right = 10
                up = 1
        if df.iloc[2,j] == 4.0:
                up = 0
        if abs(lx - df.iloc[2,j]) > 1 or abs(ly - df.iloc[1,j]) > 0.001:
                plt.annotate(df.columns[j], (df.iloc[2,j], df.iloc[0,j]), textcoords="offset points", xytext=(right,up), ha='center', fontsize=8)
                plt.annotate(df.columns[j], (df.iloc[2,j], df.iloc[1,j]), textcoords="offset points", xytext=(right,up), ha='center', fontsize=8)
                lx = df.iloc[2,j]
                ly = df.iloc[1,j]
        
# Annotate with points

plt.xlabel('Average Iteration Time')
plt.ylabel(r'Contraction Rate ($\tau$)')

if saving: plt.savefig("figs/fig_pareto.pdf", format="pdf", bbox_inches="tight")
plt.show()
0 (47.99999999999555, 0.9610519693852897)
1 (46.00000000002653, 0.9611344874981325)
2 (44.00000000001397, 0.9612008911742602)
3 (41.999999999993534, 0.9612841961148996)
4 (40.00000000033529, 0.9613404323358163)
5 (38.00000000019668, 0.9614511691184635)
6 (36.00000000005643, 0.9615160721244879)
7 (34.00000000000089, 0.9616398317573042)
8 (32.00000000018983, 0.9616501789931347)
9 (29.99999999993441, 0.9618143984054425)
10 (28.000000000015845, 0.9618911233999475)
11 (26.00000000018838, 0.9619696358581257)
12 (23.999999999924594, 0.9620812351429494)
13 (22.000000000001247, 0.9622244218633337)
14 (19.999999999880224, 0.9623042101456656)
15 (17.99999999994352, 0.962424427613141)
16 (15.999999999994683, 0.9624855242813694)
17 (14.000000000000362, 0.9627105025538466)
18 (11.9999999999999, 0.9627679103019492)
19 (10.000000000165414, 0.96304306184268)
20 (7.999999999999933, 0.9630413776592729)
21 (3.9999999999999907, 0.9642038633930519)
22 (3.9999999999999907, 0.9642023236823605)
23 (4.0, 0.9652843225004955)
24 (4.0, 0.9669002363662484)
25 (4.0, 0.968647136449619)
26 (4.0, 0.9699045194765014)
27 (4.0, 0.9724128400046071)
No description has been provided for this image

Figure 11 just shows how we removed the edges

In [38]:
# Figure 11 - edge deletion ordering

def cplot(M, c, title=''):
    vmin = 1
    vmax = np.max(ordermat)
    cm = plt.cm.viridis #coolwarm
    fig, ax = plt.subplots(1, 1, figsize=(12, 6))
    x = np.arange(n)
    y = -np.arange(n)
    pc = ax.pcolormesh(x, y, M, cmap=cm , vmin=vmin, vmax=vmax)
    ax.set_title(title) #'Edge Removal Ordering'
    ax.axis('off')
    ax.set_aspect('equal')

    # Add colorbar
    plt.tight_layout()
    
    cbar = fig.colorbar(pc) 
    cbar.set_ticks(np.arange(1, c, 4)) 
    return fig

# Display edge removal ordering
def order_graph(n):
    order_matrix = np.zeros((n,n)) 
    counter = 1
    for i in range(n//2):
        start = 0
        for k in range(2):
            for j in range(start, i + k*(n//2)):
                r = i + k*(n//2)
                c = j
                order_matrix[(r,j)] = counter
                order_matrix[(c,r)] = counter
            
            counter += 1
            start = n//2

    ccounter = 0
    for i in range(n//2 - 2):
        for j in range(i+1):
            r = n//2 + j
            c = n//2 - 1 - i + j
            order_matrix[(r, c)] = counter
            order_matrix[(c, r)] = counter
            ccounter += 1
            if ccounter % 10 == 0:
                counter += 1
            
    return order_matrix, counter
ordermat, c = order_graph(24)
ordermat = np.ma.masked_array(ordermat, ordermat < 1)

fig = cplot(ordermat, c, 'Edge Removal Ordering')
if saving: fig.savefig("figs/fig_edge_removal.pdf")
No description has been provided for this image

Figure 12 then combines the iteration time and contraction factor to find the total time required for a given contraction level, and compares the 2-Block design with the constrained minimum iteration time design, using the minimum total effective resistance objective for each.

It demonstrates some additional parameters in the getMinIteration function. minW=n//2 sets the minimum number of edges for each node in the graph of $W$ to be $\frac{n}{2}$, which we call the constrained minimum iteration time design.

We also introduce the getMetrics function, which returns the iteration time, contraction factor, total cycles, and total time for a given contraction target, over a given design ($Z, W$), compute and communication times ($t, l$), and operator parameters (using the default values in Class 1).

In [39]:
# Figure 12
block_results = []
min_results = []
for n in range(6,10):
    for i in range(40):
        t = np.random.rand(n)*10+1

        # Communication time
        l = np.random.rand(n, n)*1.5 + 0.5
        l = np.tril(l, -1) + np.tril(l, -1).T
        Zb, Wb = getBlockMin(n, n//2, builder=getMinResist)
        c, tau, cc, tt = getMetrics(Zb, Wb, t, l,contraction_target=0.01)
        block_results.append((n, i, c, tau, cc, tt))
        Z, W = getMinIteration(n, builder=getMinResist, t=t, l=l, c=0.01, r=n, minW=n//2)
        if Z is not None:
            c, tau, cc, ttc = getMetrics(Z, W, t, l,contraction_target=0.01)
        else:
            c, tau, cc, ttc = (None, None, None, None)
        min_results.append((n, i, c, tau, cc, ttc))
        print(n,i,tt,ttc)
        
6 0 670.4886897131029 670.4886897131029
6 1 778.643903904538 694.5692581525664
6 2 615.006840052717 615.006840052717
6 3 664.7031827966202 664.7031827966202
6 4 698.4652093107794 609.2499864585676
6 5 688.0880207701939 688.0880207701939
6 6 577.4186832479074 513.2587602400457
6 7 675.5954285310031 675.5954285310031
6 8 652.2238505242201 632.6068381216719
6 9 623.2432588359057 498.47284290251457
6 10 530.4714698292019 530.4714698292019
6 11 487.89630928740723 487.89630928740723
6 12 616.5828737639896 616.5828737639896
6 13 545.1163811472464 496.95239405209304
6 14 715.8385535884668 544.7866595980308
6 15 718.7565870708886 718.7565870708886
6 16 508.98055829220084 508.98055829220084
6 17 618.5273437625365 618.5273437625365
6 18 587.1497931809487 587.1497931809487
6 19 697.2152163421836 697.2152163421836
6 20 525.217813021972 525.217813021972
6 21 653.3343949915621 653.3343949915621
6 22 451.8401413427987 395.53697807569
6 23 541.1292509237803 541.1292509237803
6 24 560.1621320320938 560.1621320320938
6 25 627.8152551777415 513.6085171905685
6 26 697.0303838769128 415.72627354570216
6 27 591.7380582303297 591.7380582303297
6 28 643.5697463454466 579.1653239472738
6 29 570.225004093676 570.225004093676
6 30 670.7815318254211 553.1210091819509
6 31 651.4000885000901 651.4000885000901
6 32 590.7057065157435 590.7057065157435
6 33 501.7307153879898 501.7307153879898
6 34 562.4305705164893 562.4305705164893
6 35 610.6595096137099 610.6595096137099
6 36 571.2032212576437 464.3189390758997
6 37 517.0737763095983 466.544290865819
6 38 377.0452637567923 351.44461502719867
6 39 689.041606842278 577.3529920169221
7 0 981.2245958002236 786.427289915642
7 1 940.6699817649405 647.5730411744605
7 2 925.0920189003568 785.2373220527802
7 3 857.3204311391953 745.4147206690646
7 4 982.8055531664709 870.8995244936355
7 5 1053.766136245001 724.8240692802201
7 6 1129.0206508574934 769.8780816183216
7 7 1091.3057839459616 1024.4911440881733
7 8 626.6460464052768 562.7025723831766
7 9 997.8021089014212 685.620755299691
7 10 797.2032611075188 585.7003551257465
7 11 885.0031300908411 848.880553339001
7 12 1058.9747887818658 706.7751498158004
7 13 842.7418733900938 619.1572947659758
7 14 818.8331804928644 718.5678931618287
7 15 987.3290374765884 866.4316043159722
7 16 1064.5623716096825 719.9327341961316
7 17 976.8999143479339 671.1810208221348
7 18 914.6632549494241 1119.9958223882777
7 19 808.3796553566091 530.2767466364537
7 20 1034.275498773276 759.8758766500566
7 21 927.6688513933602 692.8621625075766
7 22 1060.2882154509803 784.9831485046384
7 23 1012.2134651303912 777.0082395230768
7 24 1195.958656756382 1003.1196132371452
7 25 1148.8716751623185 645.0757853899174
7 26 1115.9148391788121 670.7122101748075
7 27 1029.6629370800192 792.2840369171759
7 28 880.0399189098284 622.0091332190075
7 29 907.056906275165 795.988713669901
7 30 1096.0949150977958 777.5918321005179
7 31 840.4031523977338 617.4390507417304
7 32 920.9986365840482 808.2232933097077
7 33 1056.4003240787945 1293.5514171010198
7 34 1147.7506188719708 750.0765387475235
7 35 1075.8273218346242 844.2669768069983
7 36 955.2703771781606 734.3842685437616
7 37 1115.1376903156365 577.3904988889897
7 38 980.5479232805474 694.7159873902991
7 39 1131.1777553101992 725.4714377472677
8 0 911.6232630181286 810.4387510039699
8 1 891.9799263850759 891.9799263850759
8 2 920.179239297414 920.179239297414
8 3 800.2383349299959 800.2383349299959
8 4 753.3587758016674 753.3587758016674
8 5 845.0517049325248 845.0517049325248
8 6 912.1179851660208 912.1179851660208
8 7 848.446268018055 848.446268018055
8 8 982.3775931007713 982.3775931007713
8 9 952.1745880593768 952.1745880593768
8 10 950.707346055344 950.707346055344
8 11 829.9867654940377 633.3932317934864
8 12 969.4493413955097 736.1760875191544
8 13 997.2671015244088 864.122605905095
8 14 1018.3202726756092 1018.3202726756092
8 15 1046.8438441968804 1046.8438441968804
8 16 861.2354279979197 861.2354279979197
8 17 811.3450272417898 811.3450272417898
8 18 1036.2270906794056 821.6057232227172
8 19 939.266566851289 835.6024580003277
8 20 994.7175797539742 765.0848878706779
8 21 877.9064353334034 877.9064353334034
8 22 982.6989485839769 982.6989485839769
8 23 991.3768071185148 755.2427074708362
8 24 855.6159120155098 855.6159120155098
8 25 982.8271720948637 882.7642218776714
8 26 829.3763935963367 829.3763935963367
8 27 893.5883959113827 676.0339410506026
8 28 865.4880113161685 865.4880113161685
8 29 892.4905049124536 794.4842759862287
8 30 971.8327334063216 800.8026999372078
8 31 1008.9261947189451 826.3379529075881
8 32 894.7718786666485 752.2926906433577
8 33 815.7798898160743 815.7798898160743
8 34 992.1038858840896 992.1038858840896
8 35 691.1516078532711 691.1516078532711
8 36 947.354286830722 947.354286830722
8 37 922.6948858772778 922.6948858772778
8 38 918.150100608076 728.1685261482883
8 39 947.8385952610337 774.5080911243963
9 0 1478.2742502043352 979.6073962049029
9 1 1093.6531782621405 684.9243844953108
9 2 1201.525123664246 828.9801754145494
9 3 1364.5336587289812 950.0396165707325
9 4 1413.3915046389948 1005.4663986748551
9 5 974.688508500644 640.1167130385393
9 6 1350.6261230564066 862.4545701796865
9 7 1162.8223692152496 1016.324466625392
9 8 1210.9060082553626 806.1813811375092
9 9 1423.4552052809431 1103.312451259093
9 10 1291.5338676719557 791.3902376658899
9 11 1205.7916929464434 975.5444833475439
9 12 1451.529222078253 1107.8159920741818
9 13 1386.8755933773932 1005.4398941073596
9 14 1258.419176099138 912.2887549393351
9 15 1392.3203182854224 928.9888255176635
9 16 1360.4958752153861 1070.5541313171288
9 17 1037.1756829668498 793.579455126998
9 18 1294.3366325644306 1121.158048648846
9 19 1311.584916674905 987.2253639656058
9 20 1203.5323775901584 898.7089991280843
9 21 1129.3903829021258 1203.448768732348
9 22 1307.7908372303818 1082.822479286563
9 23 1271.0210381687546 796.4761526137635
9 24 1327.68395677353 759.956492346676
9 25 1290.9681193745478 836.009573751264
9 26 1312.1585307875869 815.8914406834145
9 27 1017.3591417545098 574.882217494349
9 28 912.1199881927741 801.5857158873254
9 29 1350.7925484160241 969.13105880696
9 30 1402.3920226256741 1075.8709172135295
9 31 1247.046436299857 975.9273880798273
9 32 1236.073399741868 720.2962432598588
9 33 1413.9913547720375 1159.009308067732
9 34 1430.4663131494335 1004.469912472709
9 35 1368.3719247419199 1054.319352635388
9 36 1149.2680010915517 906.3371960222526
9 37 1293.6039989563678 938.7706549615914
9 38 1402.9186006253822 1075.4741357450423
9 39 1144.0111659936217 849.204131805314
In [40]:
# Figure 12
block_df = pd.DataFrame(block_results)
min_df = pd.DataFrame(min_results)

if saving: 
    block_df.to_csv('figs/block_df2.csv')
    min_df.to_csv('figs/min_cycle_min_edge.csv')
In [41]:
# Figure 12
# Paired density chart for block vs min cycle

fig, axs = plt.subplots(2, 2, sharey=True)
n = 6
key = 5 #'5' #use string if loading from csv
start = 0
for i in range(2):
    for j in range(2):
        end = 40 + start
        axs[i,j] = block_df[key][start:end].plot.kde(ax=axs[i,j], color='blue')
        min_df[key][start:end].plot.kde(ax=axs[i,j], color='red')
        start += 40
        axs[i,j].set_title(r"$n=$"+str(n))
        n += 1

fig.legend([r'$d$-Block Design', 'Con. Min Iter Time'], loc=(.65,.8))

for ax in axs.flat:
    ax.set(xlabel='Time')
for ax in fig.get_axes():
    ax.label_outer()
if saving: fig.savefig("figs/fig_constrained_mincycle_histogram.pdf", format="pdf", bbox_inches="tight")
No description has been provided for this image