Spaces:
Runtime error
Runtime error
Upload 41 files
Browse files- analysis/.DS_Store +0 -0
- analysis/__init__.py +0 -0
- analysis/__pycache__/__init__.cpython-39 (nds4's conflicted copy 2024-05-30).pyc +0 -0
- analysis/__pycache__/__init__.cpython-39.pyc +0 -0
- analysis/__pycache__/dist_helper.cpython-39.pyc +0 -0
- analysis/__pycache__/spectre_utils.cpython-39 (nds4's conflicted copy 2024-05-30).pyc +0 -0
- analysis/__pycache__/spectre_utils.cpython-39.pyc +0 -0
- analysis/dist_helper.py +156 -0
- analysis/orca/orca +0 -0
- analysis/orca/orca.cpp +1532 -0
- analysis/orca/orca.h +1488 -0
- analysis/orca/tmp_JJOX0U87.txt +25 -0
- analysis/orca/tmp_YX4O2JRL.txt +3269 -0
- analysis/rdkit_functions.py +334 -0
- analysis/spectre_utils.py +928 -0
- analysis/visualization.py +221 -0
- app.py +89 -0
- config.yaml +53 -0
- dataset.py +395 -0
- demo_model.py +214 -0
- diffusion/__init__.py +0 -0
- diffusion/__pycache__/__init__.cpython-39.pyc +0 -0
- diffusion/__pycache__/diffusion_utils.cpython-39.pyc +0 -0
- diffusion/__pycache__/noise_schedule.cpython-39.pyc +0 -0
- diffusion/diffusion_utils.py +437 -0
- diffusion/distributions.py +32 -0
- diffusion/extra_features.py +275 -0
- diffusion/extra_features_molecular.py +57 -0
- diffusion/layers.py +19 -0
- diffusion/noise_schedule.py +225 -0
- diffusion/utils.py +137 -0
- distributions.py +37 -0
- extra_features.py +275 -0
- models/__init__.py +0 -0
- models/__pycache__/__init__.cpython-39.pyc +0 -0
- models/__pycache__/layers.cpython-39.pyc +0 -0
- models/__pycache__/transformer_model.cpython-39.pyc +0 -0
- models/layers.py +46 -0
- models/transformer_model.py +285 -0
- requirements.txt +15 -0
- utils.py +137 -0
analysis/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
analysis/__init__.py
ADDED
|
File without changes
|
analysis/__pycache__/__init__.cpython-39 (nds4's conflicted copy 2024-05-30).pyc
ADDED
|
Binary file (149 Bytes). View file
|
|
|
analysis/__pycache__/__init__.cpython-39.pyc
ADDED
|
Binary file (165 Bytes). View file
|
|
|
analysis/__pycache__/dist_helper.cpython-39.pyc
ADDED
|
Binary file (4.57 kB). View file
|
|
|
analysis/__pycache__/spectre_utils.cpython-39 (nds4's conflicted copy 2024-05-30).pyc
ADDED
|
Binary file (23.5 kB). View file
|
|
|
analysis/__pycache__/spectre_utils.cpython-39.pyc
ADDED
|
Binary file (23.5 kB). View file
|
|
|
analysis/dist_helper.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
###############################################################################
|
| 2 |
+
#
|
| 3 |
+
# Adapted from https://github.com/lrjconan/GRAN/ which in turn is adapted from https://github.com/JiaxuanYou/graph-generation
|
| 4 |
+
#
|
| 5 |
+
###############################################################################
|
| 6 |
+
import pyemd
|
| 7 |
+
import numpy as np
|
| 8 |
+
import concurrent.futures
|
| 9 |
+
from functools import partial
|
| 10 |
+
from scipy.linalg import toeplitz
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def emd(x, y, distance_scaling=1.0):
|
| 14 |
+
support_size = max(len(x), len(y))
|
| 15 |
+
d_mat = toeplitz(range(support_size)).astype(float)
|
| 16 |
+
distance_mat = d_mat / distance_scaling
|
| 17 |
+
|
| 18 |
+
# convert histogram values x and y to float, and make them equal len
|
| 19 |
+
x = x.astype(float)
|
| 20 |
+
y = y.astype(float)
|
| 21 |
+
if len(x) < len(y):
|
| 22 |
+
x = np.hstack((x, [0.0] * (support_size - len(x))))
|
| 23 |
+
elif len(y) < len(x):
|
| 24 |
+
y = np.hstack((y, [0.0] * (support_size - len(y))))
|
| 25 |
+
|
| 26 |
+
emd = pyemd.emd(x, y, distance_mat)
|
| 27 |
+
return emd
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def l2(x, y):
|
| 32 |
+
dist = np.linalg.norm(x - y, 2)
|
| 33 |
+
return dist
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def emd(x, y, sigma=1.0, distance_scaling=1.0):
|
| 37 |
+
''' EMD
|
| 38 |
+
Args:
|
| 39 |
+
x, y: 1D pmf of two distributions with the same support
|
| 40 |
+
sigma: standard deviation
|
| 41 |
+
'''
|
| 42 |
+
support_size = max(len(x), len(y))
|
| 43 |
+
d_mat = toeplitz(range(support_size)).astype(float)
|
| 44 |
+
distance_mat = d_mat / distance_scaling
|
| 45 |
+
|
| 46 |
+
# convert histogram values x and y to float, and make them equal len
|
| 47 |
+
x = x.astype(float)
|
| 48 |
+
y = y.astype(float)
|
| 49 |
+
if len(x) < len(y):
|
| 50 |
+
x = np.hstack((x, [0.0] * (support_size - len(x))))
|
| 51 |
+
elif len(y) < len(x):
|
| 52 |
+
y = np.hstack((y, [0.0] * (support_size - len(y))))
|
| 53 |
+
|
| 54 |
+
return np.abs(pyemd.emd(x, y, distance_mat))
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def gaussian_emd(x, y, sigma=1.0, distance_scaling=1.0):
|
| 58 |
+
''' Gaussian kernel with squared distance in exponential term replaced by EMD
|
| 59 |
+
Args:
|
| 60 |
+
x, y: 1D pmf of two distributions with the same support
|
| 61 |
+
sigma: standard deviation
|
| 62 |
+
'''
|
| 63 |
+
support_size = max(len(x), len(y))
|
| 64 |
+
d_mat = toeplitz(range(support_size)).astype(float)
|
| 65 |
+
distance_mat = d_mat / distance_scaling
|
| 66 |
+
|
| 67 |
+
# convert histogram values x and y to float, and make them equal len
|
| 68 |
+
x = x.astype(float)
|
| 69 |
+
y = y.astype(float)
|
| 70 |
+
if len(x) < len(y):
|
| 71 |
+
x = np.hstack((x, [0.0] * (support_size - len(x))))
|
| 72 |
+
elif len(y) < len(x):
|
| 73 |
+
y = np.hstack((y, [0.0] * (support_size - len(y))))
|
| 74 |
+
|
| 75 |
+
emd = pyemd.emd(x, y, distance_mat)
|
| 76 |
+
return np.exp(-emd * emd / (2 * sigma * sigma))
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def gaussian(x, y, sigma=1.0):
|
| 80 |
+
support_size = max(len(x), len(y))
|
| 81 |
+
# convert histogram values x and y to float, and make them equal len
|
| 82 |
+
x = x.astype(float)
|
| 83 |
+
y = y.astype(float)
|
| 84 |
+
if len(x) < len(y):
|
| 85 |
+
x = np.hstack((x, [0.0] * (support_size - len(x))))
|
| 86 |
+
elif len(y) < len(x):
|
| 87 |
+
y = np.hstack((y, [0.0] * (support_size - len(y))))
|
| 88 |
+
|
| 89 |
+
dist = np.linalg.norm(x - y, 2)
|
| 90 |
+
return np.exp(-dist * dist / (2 * sigma * sigma))
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def gaussian_tv(x, y, sigma=1.0):
|
| 94 |
+
support_size = max(len(x), len(y))
|
| 95 |
+
# convert histogram values x and y to float, and make them equal len
|
| 96 |
+
x = x.astype(float)
|
| 97 |
+
y = y.astype(float)
|
| 98 |
+
if len(x) < len(y):
|
| 99 |
+
x = np.hstack((x, [0.0] * (support_size - len(x))))
|
| 100 |
+
elif len(y) < len(x):
|
| 101 |
+
y = np.hstack((y, [0.0] * (support_size - len(y))))
|
| 102 |
+
|
| 103 |
+
dist = np.abs(x - y).sum() / 2.0
|
| 104 |
+
return np.exp(-dist * dist / (2 * sigma * sigma))
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def kernel_parallel_unpacked(x, samples2, kernel):
|
| 108 |
+
d = 0
|
| 109 |
+
for s2 in samples2:
|
| 110 |
+
d += kernel(x, s2)
|
| 111 |
+
return d
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def kernel_parallel_worker(t):
|
| 115 |
+
return kernel_parallel_unpacked(*t)
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def disc(samples1, samples2, kernel, is_parallel=True, *args, **kwargs):
|
| 119 |
+
''' Discrepancy between 2 samples '''
|
| 120 |
+
d = 0
|
| 121 |
+
|
| 122 |
+
if not is_parallel:
|
| 123 |
+
for s1 in samples1:
|
| 124 |
+
for s2 in samples2:
|
| 125 |
+
d += kernel(s1, s2, *args, **kwargs)
|
| 126 |
+
else:
|
| 127 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 128 |
+
for dist in executor.map(kernel_parallel_worker, [
|
| 129 |
+
(s1, samples2, partial(kernel, *args, **kwargs)) for s1 in samples1
|
| 130 |
+
]):
|
| 131 |
+
d += dist
|
| 132 |
+
if len(samples1) * len(samples2) > 0:
|
| 133 |
+
d /= len(samples1) * len(samples2)
|
| 134 |
+
else:
|
| 135 |
+
d = 1e+6
|
| 136 |
+
return d
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def compute_mmd(samples1, samples2, kernel, is_hist=True, *args, **kwargs):
|
| 140 |
+
''' MMD between two samples '''
|
| 141 |
+
# normalize histograms into pmf
|
| 142 |
+
if is_hist:
|
| 143 |
+
samples1 = [s1 / (np.sum(s1) + 1e-6) for s1 in samples1]
|
| 144 |
+
samples2 = [s2 / (np.sum(s2) + 1e-6) for s2 in samples2]
|
| 145 |
+
return disc(samples1, samples1, kernel, *args, **kwargs) + disc(samples2, samples2, kernel, *args, **kwargs) - \
|
| 146 |
+
2 * disc(samples1, samples2, kernel, *args, **kwargs)
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
def compute_emd(samples1, samples2, kernel, is_hist=True, *args, **kwargs):
|
| 150 |
+
''' EMD between average of two samples '''
|
| 151 |
+
# normalize histograms into pmf
|
| 152 |
+
if is_hist:
|
| 153 |
+
samples1 = [np.mean(samples1)]
|
| 154 |
+
samples2 = [np.mean(samples2)]
|
| 155 |
+
return disc(samples1, samples2, kernel, *args,
|
| 156 |
+
**kwargs), [samples1[0], samples2[0]]
|
analysis/orca/orca
ADDED
|
Binary file (95.5 kB). View file
|
|
|
analysis/orca/orca.cpp
ADDED
|
@@ -0,0 +1,1532 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <cstdio>
|
| 2 |
+
#include <cstdlib>
|
| 3 |
+
#include <cstring>
|
| 4 |
+
#include <cassert>
|
| 5 |
+
#include <ctime>
|
| 6 |
+
#include <iostream>
|
| 7 |
+
#include <fstream>
|
| 8 |
+
#include <set>
|
| 9 |
+
#include <sstream>
|
| 10 |
+
#include <unordered_map>
|
| 11 |
+
#include <algorithm>
|
| 12 |
+
|
| 13 |
+
using namespace std;
|
| 14 |
+
|
| 15 |
+
typedef long long int64;
|
| 16 |
+
typedef pair<int,int> PII;
|
| 17 |
+
typedef struct { int first, second, third; } TIII;
|
| 18 |
+
|
| 19 |
+
struct PAIR {
|
| 20 |
+
int a, b;
|
| 21 |
+
PAIR(int a0, int b0) { a=min(a0,b0); b=max(a0,b0); }
|
| 22 |
+
};
|
| 23 |
+
bool operator<(const PAIR &x, const PAIR &y) {
|
| 24 |
+
if (x.a==y.a) return x.b<y.b;
|
| 25 |
+
else return x.a<y.a;
|
| 26 |
+
}
|
| 27 |
+
bool operator==(const PAIR &x, const PAIR &y) {
|
| 28 |
+
return x.a==y.a && x.b==y.b;
|
| 29 |
+
}
|
| 30 |
+
struct hash_PAIR {
|
| 31 |
+
size_t operator()(const PAIR &x) const {
|
| 32 |
+
return (x.a<<8) ^ (x.b<<0);
|
| 33 |
+
}
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
struct TRIPLE {
|
| 37 |
+
int a, b, c;
|
| 38 |
+
TRIPLE(int a0, int b0, int c0) {
|
| 39 |
+
a=a0; b=b0; c=c0;
|
| 40 |
+
if (a>b) swap(a,b);
|
| 41 |
+
if (b>c) swap(b,c);
|
| 42 |
+
if (a>b) swap(a,b);
|
| 43 |
+
}
|
| 44 |
+
};
|
| 45 |
+
bool operator<(const TRIPLE &x, const TRIPLE &y) {
|
| 46 |
+
if (x.a==y.a) {
|
| 47 |
+
if (x.b==y.b) return x.c<y.c;
|
| 48 |
+
else return x.b<y.b;
|
| 49 |
+
} else return x.a<y.a;
|
| 50 |
+
}
|
| 51 |
+
bool operator==(const TRIPLE &x, const TRIPLE &y) {
|
| 52 |
+
return x.a==y.a && x.b==y.b && x.c==y.c;
|
| 53 |
+
}
|
| 54 |
+
struct hash_TRIPLE {
|
| 55 |
+
size_t operator()(const TRIPLE &x) const {
|
| 56 |
+
return (x.a<<16) ^ (x.b<<8) ^ (x.c<<0);
|
| 57 |
+
}
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
unordered_map<PAIR, int, hash_PAIR> common2;
|
| 61 |
+
unordered_map<TRIPLE, int, hash_TRIPLE> common3;
|
| 62 |
+
unordered_map<PAIR, int, hash_PAIR>::iterator common2_it;
|
| 63 |
+
unordered_map<TRIPLE, int, hash_TRIPLE>::iterator common3_it;
|
| 64 |
+
|
| 65 |
+
#define common3_get(x) (((common3_it=common3.find(x))!=common3.end())?(common3_it->second):0)
|
| 66 |
+
#define common2_get(x) (((common2_it=common2.find(x))!=common2.end())?(common2_it->second):0)
|
| 67 |
+
|
| 68 |
+
int n,m; // n = number of nodes, m = number of edges
|
| 69 |
+
int *deg; // degrees of individual nodes
|
| 70 |
+
PAIR *edges; // list of edges
|
| 71 |
+
|
| 72 |
+
int **adj; // adj[x] - adjacency list of node x
|
| 73 |
+
PII **inc; // inc[x] - incidence list of node x: (y, edge id)
|
| 74 |
+
bool adjacent_list(int x, int y) { return binary_search(adj[x],adj[x]+deg[x],y); }
|
| 75 |
+
int *adj_matrix; // compressed adjacency matrix
|
| 76 |
+
const int adj_chunk = 8*sizeof(int);
|
| 77 |
+
bool adjacent_matrix(int x, int y) { return adj_matrix[(x*n+y)/adj_chunk]&(1<<((x*n+y)%adj_chunk)); }
|
| 78 |
+
bool (*adjacent)(int,int);
|
| 79 |
+
int getEdgeId(int x, int y) { return inc[x][lower_bound(adj[x],adj[x]+deg[x],y)-adj[x]].second; }
|
| 80 |
+
|
| 81 |
+
int64 **orbit; // orbit[x][o] - how many times does node x participate in orbit o
|
| 82 |
+
int64 **eorbit; // eorbit[x][o] - how many times does node x participate in edge orbit o
|
| 83 |
+
|
| 84 |
+
/** count graphlets on max 4 nodes */
|
| 85 |
+
void count4() {
|
| 86 |
+
clock_t startTime, endTime;
|
| 87 |
+
startTime = clock();
|
| 88 |
+
clock_t startTime_all, endTime_all;
|
| 89 |
+
startTime_all = startTime;
|
| 90 |
+
int frac,frac_prev;
|
| 91 |
+
|
| 92 |
+
// precompute triangles that span over edges
|
| 93 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 94 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 95 |
+
frac_prev=-1;
|
| 96 |
+
for (int i=0;i<m;i++) {
|
| 97 |
+
frac = 100LL*i/m;
|
| 98 |
+
if (frac!=frac_prev) {
|
| 99 |
+
printf("%d%%\r",frac);
|
| 100 |
+
frac_prev=frac;
|
| 101 |
+
}
|
| 102 |
+
int x=edges[i].a, y=edges[i].b;
|
| 103 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 104 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 105 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 106 |
+
else { yi++; }
|
| 107 |
+
}
|
| 108 |
+
}
|
| 109 |
+
endTime = clock();
|
| 110 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 111 |
+
startTime = endTime;
|
| 112 |
+
|
| 113 |
+
// count full graphlets
|
| 114 |
+
printf("stage 2 - counting full graphlets\n");
|
| 115 |
+
int64 *C4 = (int64*)calloc(n,sizeof(int64));
|
| 116 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn;
|
| 117 |
+
frac_prev=-1;
|
| 118 |
+
for (int x=0;x<n;x++) {
|
| 119 |
+
frac = 100LL*x/n;
|
| 120 |
+
if (frac!=frac_prev) {
|
| 121 |
+
printf("%d%%\r",frac);
|
| 122 |
+
frac_prev=frac;
|
| 123 |
+
}
|
| 124 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 125 |
+
int y=adj[x][nx];
|
| 126 |
+
if (y >= x) break;
|
| 127 |
+
nn=0;
|
| 128 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 129 |
+
int z=adj[y][ny];
|
| 130 |
+
if (z >= y) break;
|
| 131 |
+
if (adjacent(x,z)==0) continue;
|
| 132 |
+
neigh[nn++]=z;
|
| 133 |
+
}
|
| 134 |
+
for (int i=0;i<nn;i++) {
|
| 135 |
+
int z = neigh[i];
|
| 136 |
+
for (int j=i+1;j<nn;j++) {
|
| 137 |
+
int zz = neigh[j];
|
| 138 |
+
if (adjacent(z,zz)) {
|
| 139 |
+
C4[x]++; C4[y]++; C4[z]++; C4[zz]++;
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
+
endTime = clock();
|
| 146 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 147 |
+
startTime = endTime;
|
| 148 |
+
|
| 149 |
+
// set up a system of equations relating orbits for every node
|
| 150 |
+
printf("stage 3 - building systems of equations\n");
|
| 151 |
+
int *common = (int*)calloc(n,sizeof(int));
|
| 152 |
+
int *common_list = (int*)malloc(n*sizeof(int)), nc=0;
|
| 153 |
+
frac_prev=-1;
|
| 154 |
+
for (int x=0;x<n;x++) {
|
| 155 |
+
frac = 100LL*x/n;
|
| 156 |
+
if (frac!=frac_prev) {
|
| 157 |
+
printf("%d%%\r",frac);
|
| 158 |
+
frac_prev=frac;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
int64 f_12_14=0, f_10_13=0;
|
| 162 |
+
int64 f_13_14=0, f_11_13=0;
|
| 163 |
+
int64 f_7_11=0, f_5_8=0;
|
| 164 |
+
int64 f_6_9=0, f_9_12=0, f_4_8=0, f_8_12=0;
|
| 165 |
+
int64 f_14=C4[x];
|
| 166 |
+
|
| 167 |
+
for (int i=0;i<nc;i++) common[common_list[i]]=0;
|
| 168 |
+
nc=0;
|
| 169 |
+
|
| 170 |
+
orbit[x][0]=deg[x];
|
| 171 |
+
// x - middle node
|
| 172 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 173 |
+
int y=inc[x][nx1].first, ey=inc[x][nx1].second;
|
| 174 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 175 |
+
int z=inc[y][ny].first, ez=inc[y][ny].second;
|
| 176 |
+
if (adjacent(x,z)) { // triangle
|
| 177 |
+
if (z<y) {
|
| 178 |
+
f_12_14 += tri[ez]-1;
|
| 179 |
+
f_10_13 += (deg[y]-1-tri[ez])+(deg[z]-1-tri[ez]);
|
| 180 |
+
}
|
| 181 |
+
} else {
|
| 182 |
+
if (common[z]==0) common_list[nc++]=z;
|
| 183 |
+
common[z]++;
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 187 |
+
int z=inc[x][nx2].first, ez=inc[x][nx2].second;
|
| 188 |
+
if (adjacent(y,z)) { // triangle
|
| 189 |
+
orbit[x][3]++;
|
| 190 |
+
f_13_14 += (tri[ey]-1)+(tri[ez]-1);
|
| 191 |
+
f_11_13 += (deg[x]-1-tri[ey])+(deg[x]-1-tri[ez]);
|
| 192 |
+
} else { // path
|
| 193 |
+
orbit[x][2]++;
|
| 194 |
+
f_7_11 += (deg[x]-1-tri[ey]-1)+(deg[x]-1-tri[ez]-1);
|
| 195 |
+
f_5_8 += (deg[y]-1-tri[ey])+(deg[z]-1-tri[ez]);
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
// x - side node
|
| 200 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 201 |
+
int y=inc[x][nx1].first, ey=inc[x][nx1].second;
|
| 202 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 203 |
+
int z=inc[y][ny].first, ez=inc[y][ny].second;
|
| 204 |
+
if (x==z) continue;
|
| 205 |
+
if (!adjacent(x,z)) { // path
|
| 206 |
+
orbit[x][1]++;
|
| 207 |
+
f_6_9 += (deg[y]-1-tri[ey]-1);
|
| 208 |
+
f_9_12 += tri[ez];
|
| 209 |
+
f_4_8 += (deg[z]-1-tri[ez]);
|
| 210 |
+
f_8_12 += (common[z]-1);
|
| 211 |
+
}
|
| 212 |
+
}
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
// solve system of equations
|
| 216 |
+
orbit[x][14]=(f_14);
|
| 217 |
+
orbit[x][13]=(f_13_14-6*f_14)/2;
|
| 218 |
+
orbit[x][12]=(f_12_14-3*f_14);
|
| 219 |
+
orbit[x][11]=(f_11_13-f_13_14+6*f_14)/2;
|
| 220 |
+
orbit[x][10]=(f_10_13-f_13_14+6*f_14);
|
| 221 |
+
orbit[x][9]=(f_9_12-2*f_12_14+6*f_14)/2;
|
| 222 |
+
orbit[x][8]=(f_8_12-2*f_12_14+6*f_14)/2;
|
| 223 |
+
orbit[x][7]=(f_13_14+f_7_11-f_11_13-6*f_14)/6;
|
| 224 |
+
orbit[x][6]=(2*f_12_14+f_6_9-f_9_12-6*f_14)/2;
|
| 225 |
+
orbit[x][5]=(2*f_12_14+f_5_8-f_8_12-6*f_14);
|
| 226 |
+
orbit[x][4]=(2*f_12_14+f_4_8-f_8_12-6*f_14);
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
endTime = clock();
|
| 230 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 231 |
+
|
| 232 |
+
endTime_all = endTime;
|
| 233 |
+
printf("total: %.2f\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
/** count edge orbits of graphlets on max 4 nodes */
|
| 238 |
+
void ecount4() {
|
| 239 |
+
clock_t startTime, endTime;
|
| 240 |
+
startTime = clock();
|
| 241 |
+
clock_t startTime_all, endTime_all;
|
| 242 |
+
startTime_all = startTime;
|
| 243 |
+
int frac,frac_prev;
|
| 244 |
+
|
| 245 |
+
// precompute triangles that span over edges
|
| 246 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 247 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 248 |
+
frac_prev=-1;
|
| 249 |
+
for (int i=0;i<m;i++) {
|
| 250 |
+
frac = 100LL*i/m;
|
| 251 |
+
if (frac!=frac_prev) {
|
| 252 |
+
printf("%d%%\r",frac);
|
| 253 |
+
frac_prev=frac;
|
| 254 |
+
}
|
| 255 |
+
int x=edges[i].a, y=edges[i].b;
|
| 256 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 257 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 258 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 259 |
+
else { yi++; }
|
| 260 |
+
}
|
| 261 |
+
}
|
| 262 |
+
endTime = clock();
|
| 263 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 264 |
+
startTime = endTime;
|
| 265 |
+
|
| 266 |
+
// count full graphlets
|
| 267 |
+
printf("stage 2 - counting full graphlets\n");
|
| 268 |
+
int64 *C4 = (int64*)calloc(m,sizeof(int64));
|
| 269 |
+
int *neighx = (int*)malloc(n*sizeof(int)); // lookup table - edges to neighbors of x
|
| 270 |
+
memset(neighx,-1,n*sizeof(int));
|
| 271 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn; // lookup table - common neighbors of x and y
|
| 272 |
+
PII *neigh_edges = (PII*)malloc(n*sizeof(PII)); // list of common neighbors of x and y
|
| 273 |
+
frac_prev=-1;
|
| 274 |
+
for (int x=0;x<n;x++) {
|
| 275 |
+
frac = 100LL*x/n;
|
| 276 |
+
if (frac!=frac_prev) {
|
| 277 |
+
printf("%d%%\r",frac);
|
| 278 |
+
frac_prev=frac;
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 282 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 283 |
+
neighx[y]=xy;
|
| 284 |
+
}
|
| 285 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 286 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 287 |
+
if (y >= x) break;
|
| 288 |
+
nn=0;
|
| 289 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 290 |
+
int z=inc[y][ny].first, yz=inc[y][ny].second;
|
| 291 |
+
if (z >= y) break;
|
| 292 |
+
if (neighx[z]==-1) continue;
|
| 293 |
+
int xz=neighx[z];
|
| 294 |
+
neigh[nn]=z;
|
| 295 |
+
neigh_edges[nn]={xz, yz};
|
| 296 |
+
nn++;
|
| 297 |
+
}
|
| 298 |
+
for (int i=0;i<nn;i++) {
|
| 299 |
+
int z = neigh[i], xz = neigh_edges[i].first, yz = neigh_edges[i].second;
|
| 300 |
+
for (int j=i+1;j<nn;j++) {
|
| 301 |
+
int w = neigh[j], xw = neigh_edges[j].first, yw = neigh_edges[j].second;
|
| 302 |
+
if (adjacent(z,w)) {
|
| 303 |
+
C4[xy]++;
|
| 304 |
+
C4[xz]++; C4[yz]++;
|
| 305 |
+
C4[xw]++; C4[yw]++;
|
| 306 |
+
// another iteration to count this last(smallest) edge instead of calling getEdgeId
|
| 307 |
+
//int zw=getEdgeId(z,w); C4[zw]++;
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
}
|
| 312 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 313 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 314 |
+
neighx[y]=-1;
|
| 315 |
+
}
|
| 316 |
+
}
|
| 317 |
+
endTime = clock();
|
| 318 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 319 |
+
startTime = endTime;
|
| 320 |
+
|
| 321 |
+
// count full graphlets for the smallest edge
|
| 322 |
+
for (int x=0;x<n;x++) {
|
| 323 |
+
frac = 100LL*x/n;
|
| 324 |
+
if (frac!=frac_prev) {
|
| 325 |
+
printf("%d%%\r",frac);
|
| 326 |
+
frac_prev=frac;
|
| 327 |
+
}
|
| 328 |
+
for (int nx=deg[x]-1;nx>=0;nx--) {
|
| 329 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 330 |
+
if (y <= x) break;
|
| 331 |
+
nn=0;
|
| 332 |
+
for (int ny=deg[y]-1;ny>=0;ny--) {
|
| 333 |
+
int z=adj[y][ny];
|
| 334 |
+
if (z <= y) break;
|
| 335 |
+
if (adjacent(x,z)==0) continue;
|
| 336 |
+
neigh[nn++]=z;
|
| 337 |
+
}
|
| 338 |
+
for (int i=0;i<nn;i++) {
|
| 339 |
+
int z = neigh[i];
|
| 340 |
+
for (int j=i+1;j<nn;j++) {
|
| 341 |
+
int zz = neigh[j];
|
| 342 |
+
if (adjacent(z,zz)) {
|
| 343 |
+
C4[xy]++;
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
endTime = clock();
|
| 350 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 351 |
+
startTime = endTime;
|
| 352 |
+
|
| 353 |
+
// set up a system of equations relating orbits for every node
|
| 354 |
+
printf("stage 3 - building systems of equations\n");
|
| 355 |
+
int *common = (int*)calloc(n,sizeof(int));
|
| 356 |
+
int *common_list = (int*)malloc(n*sizeof(int)), nc=0;
|
| 357 |
+
frac_prev=-1;
|
| 358 |
+
|
| 359 |
+
for (int x=0;x<n;x++) {
|
| 360 |
+
frac = 100LL*x/n;
|
| 361 |
+
if (frac!=frac_prev) {
|
| 362 |
+
printf("%d%%\r",frac);
|
| 363 |
+
frac_prev=frac;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
// common nodes of x and some other node
|
| 367 |
+
for (int i=0;i<nc;i++) common[common_list[i]]=0;
|
| 368 |
+
nc=0;
|
| 369 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 370 |
+
int y=adj[x][nx];
|
| 371 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 372 |
+
int z=adj[y][ny];
|
| 373 |
+
if (z==x) continue;
|
| 374 |
+
if (common[z]==0) common_list[nc++]=z;
|
| 375 |
+
common[z]++;
|
| 376 |
+
}
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 380 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 381 |
+
int e=xy;
|
| 382 |
+
for (int n1=0;n1<deg[x];n1++) {
|
| 383 |
+
int z=inc[x][n1].first, xz=inc[x][n1].second;
|
| 384 |
+
if (z==y) continue;
|
| 385 |
+
if (adjacent(y,z)) { // triangle
|
| 386 |
+
if (x<y) {
|
| 387 |
+
eorbit[e][1]++;
|
| 388 |
+
eorbit[e][10] += tri[xy]-1;
|
| 389 |
+
eorbit[e][7] += deg[z]-2;
|
| 390 |
+
}
|
| 391 |
+
eorbit[e][9] += tri[xz]-1;
|
| 392 |
+
eorbit[e][8] += deg[x]-2;
|
| 393 |
+
}
|
| 394 |
+
}
|
| 395 |
+
for (int n1=0;n1<deg[y];n1++) {
|
| 396 |
+
int z=inc[y][n1].first, yz=inc[y][n1].second;
|
| 397 |
+
if (z==x) continue;
|
| 398 |
+
if (!adjacent(x,z)) { // path x-y-z
|
| 399 |
+
eorbit[e][0]++;
|
| 400 |
+
eorbit[e][6] += tri[yz];
|
| 401 |
+
eorbit[e][5] += common[z]-1;
|
| 402 |
+
eorbit[e][4] += deg[y]-2;
|
| 403 |
+
eorbit[e][3] += deg[x]-1;
|
| 404 |
+
eorbit[e][2] += deg[z]-1;
|
| 405 |
+
}
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
// solve system of equations
|
| 410 |
+
for (int e=0;e<m;e++) {
|
| 411 |
+
eorbit[e][11]=C4[e];
|
| 412 |
+
eorbit[e][10]=(eorbit[e][10]-2*eorbit[e][11])/2;
|
| 413 |
+
eorbit[e][9]=(eorbit[e][9]-4*eorbit[e][11]);
|
| 414 |
+
eorbit[e][8]=(eorbit[e][8]-eorbit[e][9]-4*eorbit[e][10]-4*eorbit[e][11]);
|
| 415 |
+
eorbit[e][7]=(eorbit[e][7]-eorbit[e][9]-2*eorbit[e][11]);
|
| 416 |
+
eorbit[e][6]=(eorbit[e][6]-eorbit[e][9])/2;
|
| 417 |
+
eorbit[e][5]=(eorbit[e][5]-eorbit[e][9])/2;
|
| 418 |
+
eorbit[e][4]=(eorbit[e][4]-2*eorbit[e][6]-eorbit[e][8]-eorbit[e][9])/2;
|
| 419 |
+
eorbit[e][3]=(eorbit[e][3]-2*eorbit[e][5]-eorbit[e][8]-eorbit[e][9])/2;
|
| 420 |
+
eorbit[e][2]=(eorbit[e][2]-2*eorbit[e][5]-2*eorbit[e][6]-eorbit[e][9]);
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
endTime = clock();
|
| 424 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 425 |
+
|
| 426 |
+
endTime_all = endTime;
|
| 427 |
+
printf("total: %.2f\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
|
| 431 |
+
/** count graphlets on max 5 nodes */
|
| 432 |
+
void count5() {
|
| 433 |
+
clock_t startTime, endTime;
|
| 434 |
+
startTime = clock();
|
| 435 |
+
clock_t startTime_all, endTime_all;
|
| 436 |
+
startTime_all = startTime;
|
| 437 |
+
int frac,frac_prev;
|
| 438 |
+
|
| 439 |
+
// precompute common nodes
|
| 440 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 441 |
+
frac_prev=-1;
|
| 442 |
+
for (int x=0;x<n;x++) {
|
| 443 |
+
frac = 100LL*x/n;
|
| 444 |
+
if (frac!=frac_prev) {
|
| 445 |
+
printf("%d%%\r",frac);
|
| 446 |
+
frac_prev=frac;
|
| 447 |
+
}
|
| 448 |
+
for (int n1=0;n1<deg[x];n1++) {
|
| 449 |
+
int a=adj[x][n1];
|
| 450 |
+
for (int n2=n1+1;n2<deg[x];n2++) {
|
| 451 |
+
int b=adj[x][n2];
|
| 452 |
+
PAIR ab=PAIR(a,b);
|
| 453 |
+
common2[ab]++;
|
| 454 |
+
for (int n3=n2+1;n3<deg[x];n3++) {
|
| 455 |
+
int c=adj[x][n3];
|
| 456 |
+
int st = adjacent(a,b)+adjacent(a,c)+adjacent(b,c);
|
| 457 |
+
if (st<2) continue;
|
| 458 |
+
TRIPLE abc=TRIPLE(a,b,c);
|
| 459 |
+
common3[abc]++;
|
| 460 |
+
}
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
}
|
| 464 |
+
// precompute triangles that span over edges
|
| 465 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 466 |
+
for (int i=0;i<m;i++) {
|
| 467 |
+
int x=edges[i].a, y=edges[i].b;
|
| 468 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 469 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 470 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 471 |
+
else { yi++; }
|
| 472 |
+
}
|
| 473 |
+
}
|
| 474 |
+
endTime = clock();
|
| 475 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 476 |
+
startTime = endTime;
|
| 477 |
+
|
| 478 |
+
// count full graphlets
|
| 479 |
+
printf("stage 2 - counting full graphlets\n");
|
| 480 |
+
int64 *C5 = (int64*)calloc(n,sizeof(int64));
|
| 481 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn;
|
| 482 |
+
int *neigh2 = (int*)malloc(n*sizeof(int)), nn2;
|
| 483 |
+
frac_prev=-1;
|
| 484 |
+
for (int x=0;x<n;x++) {
|
| 485 |
+
frac = 100LL*x/n;
|
| 486 |
+
if (frac!=frac_prev) {
|
| 487 |
+
printf("%d%%\r",frac);
|
| 488 |
+
frac_prev=frac;
|
| 489 |
+
}
|
| 490 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 491 |
+
int y=adj[x][nx];
|
| 492 |
+
if (y >= x) break;
|
| 493 |
+
nn=0;
|
| 494 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 495 |
+
int z=adj[y][ny];
|
| 496 |
+
if (z >= y) break;
|
| 497 |
+
if (adjacent(x,z)) {
|
| 498 |
+
neigh[nn++]=z;
|
| 499 |
+
}
|
| 500 |
+
}
|
| 501 |
+
for (int i=0;i<nn;i++) {
|
| 502 |
+
int z = neigh[i];
|
| 503 |
+
nn2=0;
|
| 504 |
+
for (int j=i+1;j<nn;j++) {
|
| 505 |
+
int zz = neigh[j];
|
| 506 |
+
if (adjacent(z,zz)) {
|
| 507 |
+
neigh2[nn2++]=zz;
|
| 508 |
+
}
|
| 509 |
+
}
|
| 510 |
+
for (int i2=0;i2<nn2;i2++) {
|
| 511 |
+
int zz = neigh2[i2];
|
| 512 |
+
for (int j2=i2+1;j2<nn2;j2++) {
|
| 513 |
+
int zzz = neigh2[j2];
|
| 514 |
+
if (adjacent(zz,zzz)) {
|
| 515 |
+
C5[x]++; C5[y]++; C5[z]++; C5[zz]++; C5[zzz]++;
|
| 516 |
+
}
|
| 517 |
+
}
|
| 518 |
+
}
|
| 519 |
+
}
|
| 520 |
+
}
|
| 521 |
+
}
|
| 522 |
+
endTime = clock();
|
| 523 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 524 |
+
startTime = endTime;
|
| 525 |
+
|
| 526 |
+
int *common_x = (int*)calloc(n,sizeof(int));
|
| 527 |
+
int *common_x_list = (int*)malloc(n*sizeof(int)), ncx=0;
|
| 528 |
+
int *common_a = (int*)calloc(n,sizeof(int));
|
| 529 |
+
int *common_a_list = (int*)malloc(n*sizeof(int)), nca=0;
|
| 530 |
+
|
| 531 |
+
// set up a system of equations relating orbit counts
|
| 532 |
+
printf("stage 3 - building systems of equations\n");
|
| 533 |
+
frac_prev=-1;
|
| 534 |
+
for (int x=0;x<n;x++) {
|
| 535 |
+
frac = 100LL*x/n;
|
| 536 |
+
if (frac!=frac_prev) {
|
| 537 |
+
printf("%d%%\r",frac);
|
| 538 |
+
frac_prev=frac;
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
for (int i=0;i<ncx;i++) common_x[common_x_list[i]]=0;
|
| 542 |
+
ncx=0;
|
| 543 |
+
|
| 544 |
+
// smaller graphlets
|
| 545 |
+
orbit[x][0] = deg[x];
|
| 546 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 547 |
+
int a=adj[x][nx1];
|
| 548 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 549 |
+
int b=adj[x][nx2];
|
| 550 |
+
if (adjacent(a,b)) orbit[x][3]++;
|
| 551 |
+
else orbit[x][2]++;
|
| 552 |
+
}
|
| 553 |
+
for (int na=0;na<deg[a];na++) {
|
| 554 |
+
int b=adj[a][na];
|
| 555 |
+
if (b!=x && !adjacent(x,b)) {
|
| 556 |
+
orbit[x][1]++;
|
| 557 |
+
if (common_x[b]==0) common_x_list[ncx++]=b;
|
| 558 |
+
common_x[b]++;
|
| 559 |
+
}
|
| 560 |
+
}
|
| 561 |
+
}
|
| 562 |
+
|
| 563 |
+
int64 f_71=0, f_70=0, f_67=0, f_66=0, f_58=0, f_57=0; // 14
|
| 564 |
+
int64 f_69=0, f_68=0, f_64=0, f_61=0, f_60=0, f_55=0, f_48=0, f_42=0, f_41=0; // 13
|
| 565 |
+
int64 f_65=0, f_63=0, f_59=0, f_54=0, f_47=0, f_46=0, f_40=0; // 12
|
| 566 |
+
int64 f_62=0, f_53=0, f_51=0, f_50=0, f_49=0, f_38=0, f_37=0, f_36=0; // 8
|
| 567 |
+
int64 f_44=0, f_33=0, f_30=0, f_26=0; // 11
|
| 568 |
+
int64 f_52=0, f_43=0, f_32=0, f_29=0, f_25=0; // 10
|
| 569 |
+
int64 f_56=0, f_45=0, f_39=0, f_31=0, f_28=0, f_24=0; // 9
|
| 570 |
+
int64 f_35=0, f_34=0, f_27=0, f_18=0, f_16=0, f_15=0; // 4
|
| 571 |
+
int64 f_17=0; // 5
|
| 572 |
+
int64 f_22=0, f_20=0, f_19=0; // 6
|
| 573 |
+
int64 f_23=0, f_21=0; // 7
|
| 574 |
+
|
| 575 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 576 |
+
int a=inc[x][nx1].first, xa=inc[x][nx1].second;
|
| 577 |
+
|
| 578 |
+
for (int i=0;i<nca;i++) common_a[common_a_list[i]]=0;
|
| 579 |
+
nca=0;
|
| 580 |
+
for (int na=0;na<deg[a];na++) {
|
| 581 |
+
int b=adj[a][na];
|
| 582 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 583 |
+
int c=adj[b][nb];
|
| 584 |
+
if (c==a || adjacent(a,c)) continue;
|
| 585 |
+
if (common_a[c]==0) common_a_list[nca++]=c;
|
| 586 |
+
common_a[c]++;
|
| 587 |
+
}
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
// x = orbit-14 (tetrahedron)
|
| 591 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 592 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 593 |
+
if (!adjacent(a,b)) continue;
|
| 594 |
+
for (int nx3=nx2+1;nx3<deg[x];nx3++) {
|
| 595 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 596 |
+
if (!adjacent(a,c) || !adjacent(b,c)) continue;
|
| 597 |
+
orbit[x][14]++;
|
| 598 |
+
f_70 += common3_get(TRIPLE(a,b,c))-1;
|
| 599 |
+
f_71 += (tri[xa]>2 && tri[xb]>2)?(common3_get(TRIPLE(x,a,b))-1):0;
|
| 600 |
+
f_71 += (tri[xa]>2 && tri[xc]>2)?(common3_get(TRIPLE(x,a,c))-1):0;
|
| 601 |
+
f_71 += (tri[xb]>2 && tri[xc]>2)?(common3_get(TRIPLE(x,b,c))-1):0;
|
| 602 |
+
f_67 += tri[xa]-2+tri[xb]-2+tri[xc]-2;
|
| 603 |
+
f_66 += common2_get(PAIR(a,b))-2;
|
| 604 |
+
f_66 += common2_get(PAIR(a,c))-2;
|
| 605 |
+
f_66 += common2_get(PAIR(b,c))-2;
|
| 606 |
+
f_58 += deg[x]-3;
|
| 607 |
+
f_57 += deg[a]-3+deg[b]-3+deg[c]-3;
|
| 608 |
+
}
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
// x = orbit-13 (diamond)
|
| 612 |
+
for (int nx2=0;nx2<deg[x];nx2++) {
|
| 613 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 614 |
+
if (!adjacent(a,b)) continue;
|
| 615 |
+
for (int nx3=nx2+1;nx3<deg[x];nx3++) {
|
| 616 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 617 |
+
if (!adjacent(a,c) || adjacent(b,c)) continue;
|
| 618 |
+
orbit[x][13]++;
|
| 619 |
+
f_69 += (tri[xb]>1 && tri[xc]>1)?(common3_get(TRIPLE(x,b,c))-1):0;
|
| 620 |
+
f_68 += common3_get(TRIPLE(a,b,c))-1;
|
| 621 |
+
f_64 += common2_get(PAIR(b,c))-2;
|
| 622 |
+
f_61 += tri[xb]-1+tri[xc]-1;
|
| 623 |
+
f_60 += common2_get(PAIR(a,b))-1;
|
| 624 |
+
f_60 += common2_get(PAIR(a,c))-1;
|
| 625 |
+
f_55 += tri[xa]-2;
|
| 626 |
+
f_48 += deg[b]-2+deg[c]-2;
|
| 627 |
+
f_42 += deg[x]-3;
|
| 628 |
+
f_41 += deg[a]-3;
|
| 629 |
+
}
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
// x = orbit-12 (diamond)
|
| 633 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 634 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 635 |
+
if (!adjacent(a,b)) continue;
|
| 636 |
+
for (int na=0;na<deg[a];na++) {
|
| 637 |
+
int c=inc[a][na].first, ac=inc[a][na].second;
|
| 638 |
+
if (c==x || adjacent(x,c) || !adjacent(b,c)) continue;
|
| 639 |
+
orbit[x][12]++;
|
| 640 |
+
f_65 += (tri[ac]>1)?common3_get(TRIPLE(a,b,c)):0;
|
| 641 |
+
f_63 += common_x[c]-2;
|
| 642 |
+
f_59 += tri[ac]-1+common2_get(PAIR(b,c))-1;
|
| 643 |
+
f_54 += common2_get(PAIR(a,b))-2;
|
| 644 |
+
f_47 += deg[x]-2;
|
| 645 |
+
f_46 += deg[c]-2;
|
| 646 |
+
f_40 += deg[a]-3+deg[b]-3;
|
| 647 |
+
}
|
| 648 |
+
}
|
| 649 |
+
|
| 650 |
+
// x = orbit-8 (cycle)
|
| 651 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 652 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 653 |
+
if (adjacent(a,b)) continue;
|
| 654 |
+
for (int na=0;na<deg[a];na++) {
|
| 655 |
+
int c=inc[a][na].first, ac=inc[a][na].second;
|
| 656 |
+
if (c==x || adjacent(x,c) || !adjacent(b,c)) continue;
|
| 657 |
+
orbit[x][8]++;
|
| 658 |
+
f_62 += (tri[ac]>0)?common3_get(TRIPLE(a,b,c)):0;
|
| 659 |
+
f_53 += tri[xa]+tri[xb];
|
| 660 |
+
f_51 += tri[ac]+common2_get(PAIR(c,b));
|
| 661 |
+
f_50 += common_x[c]-2;
|
| 662 |
+
f_49 += common_a[b]-2;
|
| 663 |
+
f_38 += deg[x]-2;
|
| 664 |
+
f_37 += deg[a]-2+deg[b]-2;
|
| 665 |
+
f_36 += deg[c]-2;
|
| 666 |
+
}
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
// x = orbit-11 (paw)
|
| 670 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 671 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 672 |
+
if (!adjacent(a,b)) continue;
|
| 673 |
+
for (int nx3=0;nx3<deg[x];nx3++) {
|
| 674 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 675 |
+
if (c==a || c==b || adjacent(a,c) || adjacent(b,c)) continue;
|
| 676 |
+
orbit[x][11]++;
|
| 677 |
+
f_44 += tri[xc];
|
| 678 |
+
f_33 += deg[x]-3;
|
| 679 |
+
f_30 += deg[c]-1;
|
| 680 |
+
f_26 += deg[a]-2+deg[b]-2;
|
| 681 |
+
}
|
| 682 |
+
}
|
| 683 |
+
|
| 684 |
+
// x = orbit-10 (paw)
|
| 685 |
+
for (int nx2=0;nx2<deg[x];nx2++) {
|
| 686 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 687 |
+
if (!adjacent(a,b)) continue;
|
| 688 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 689 |
+
int c=inc[b][nb].first, bc=inc[b][nb].second;
|
| 690 |
+
if (c==x || c==a || adjacent(a,c) || adjacent(x,c)) continue;
|
| 691 |
+
orbit[x][10]++;
|
| 692 |
+
f_52 += common_a[c]-1;
|
| 693 |
+
f_43 += tri[bc];
|
| 694 |
+
f_32 += deg[b]-3;
|
| 695 |
+
f_29 += deg[c]-1;
|
| 696 |
+
f_25 += deg[a]-2;
|
| 697 |
+
}
|
| 698 |
+
}
|
| 699 |
+
|
| 700 |
+
// x = orbit-9 (paw)
|
| 701 |
+
for (int na1=0;na1<deg[a];na1++) {
|
| 702 |
+
int b=inc[a][na1].first, ab=inc[a][na1].second;
|
| 703 |
+
if (b==x || adjacent(x,b)) continue;
|
| 704 |
+
for (int na2=na1+1;na2<deg[a];na2++) {
|
| 705 |
+
int c=inc[a][na2].first, ac=inc[a][na2].second;
|
| 706 |
+
if (c==x || !adjacent(b,c) || adjacent(x,c)) continue;
|
| 707 |
+
orbit[x][9]++;
|
| 708 |
+
f_56 += (tri[ab]>1 && tri[ac]>1)?common3_get(TRIPLE(a,b,c)):0;
|
| 709 |
+
f_45 += common2_get(PAIR(b,c))-1;
|
| 710 |
+
f_39 += tri[ab]-1+tri[ac]-1;
|
| 711 |
+
f_31 += deg[a]-3;
|
| 712 |
+
f_28 += deg[x]-1;
|
| 713 |
+
f_24 += deg[b]-2+deg[c]-2;
|
| 714 |
+
}
|
| 715 |
+
}
|
| 716 |
+
|
| 717 |
+
// x = orbit-4 (path)
|
| 718 |
+
for (int na=0;na<deg[a];na++) {
|
| 719 |
+
int b=inc[a][na].first, ab=inc[a][na].second;
|
| 720 |
+
if (b==x || adjacent(x,b)) continue;
|
| 721 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 722 |
+
int c=inc[b][nb].first, bc=inc[b][nb].second;
|
| 723 |
+
if (c==a || adjacent(a,c) || adjacent(x,c)) continue;
|
| 724 |
+
orbit[x][4]++;
|
| 725 |
+
f_35 += common_a[c]-1;
|
| 726 |
+
f_34 += common_x[c];
|
| 727 |
+
f_27 += tri[bc];
|
| 728 |
+
f_18 += deg[b]-2;
|
| 729 |
+
f_16 += deg[x]-1;
|
| 730 |
+
f_15 += deg[c]-1;
|
| 731 |
+
}
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
// x = orbit-5 (path)
|
| 735 |
+
for (int nx2=0;nx2<deg[x];nx2++) {
|
| 736 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 737 |
+
if (b==a || adjacent(a,b)) continue;
|
| 738 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 739 |
+
int c=inc[b][nb].first, bc=inc[b][nb].second;
|
| 740 |
+
if (c==x || adjacent(a,c) || adjacent(x,c)) continue;
|
| 741 |
+
orbit[x][5]++;
|
| 742 |
+
f_17 += deg[a]-1;
|
| 743 |
+
}
|
| 744 |
+
}
|
| 745 |
+
|
| 746 |
+
// x = orbit-6 (claw)
|
| 747 |
+
for (int na1=0;na1<deg[a];na1++) {
|
| 748 |
+
int b=inc[a][na1].first, ab=inc[a][na1].second;
|
| 749 |
+
if (b==x || adjacent(x,b)) continue;
|
| 750 |
+
for (int na2=na1+1;na2<deg[a];na2++) {
|
| 751 |
+
int c=inc[a][na2].first, ac=inc[a][na2].second;
|
| 752 |
+
if (c==x || adjacent(x,c) || adjacent(b,c)) continue;
|
| 753 |
+
orbit[x][6]++;
|
| 754 |
+
f_22 += deg[a]-3;
|
| 755 |
+
f_20 += deg[x]-1;
|
| 756 |
+
f_19 += deg[b]-1+deg[c]-1;
|
| 757 |
+
}
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
// x = orbit-7 (claw)
|
| 761 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 762 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 763 |
+
if (adjacent(a,b)) continue;
|
| 764 |
+
for (int nx3=nx2+1;nx3<deg[x];nx3++) {
|
| 765 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 766 |
+
if (adjacent(a,c) || adjacent(b,c)) continue;
|
| 767 |
+
orbit[x][7]++;
|
| 768 |
+
f_23 += deg[x]-3;
|
| 769 |
+
f_21 += deg[a]-1+deg[b]-1+deg[c]-1;
|
| 770 |
+
}
|
| 771 |
+
}
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
// solve equations
|
| 775 |
+
orbit[x][72] = C5[x];
|
| 776 |
+
orbit[x][71] = (f_71-12*orbit[x][72])/2;
|
| 777 |
+
orbit[x][70] = (f_70-4*orbit[x][72]);
|
| 778 |
+
orbit[x][69] = (f_69-2*orbit[x][71])/4;
|
| 779 |
+
orbit[x][68] = (f_68-2*orbit[x][71]);
|
| 780 |
+
orbit[x][67] = (f_67-12*orbit[x][72]-4*orbit[x][71]);
|
| 781 |
+
orbit[x][66] = (f_66-12*orbit[x][72]-2*orbit[x][71]-3*orbit[x][70]);
|
| 782 |
+
orbit[x][65] = (f_65-3*orbit[x][70])/2;
|
| 783 |
+
orbit[x][64] = (f_64-2*orbit[x][71]-4*orbit[x][69]-1*orbit[x][68]);
|
| 784 |
+
orbit[x][63] = (f_63-3*orbit[x][70]-2*orbit[x][68]);
|
| 785 |
+
orbit[x][62] = (f_62-1*orbit[x][68])/2;
|
| 786 |
+
orbit[x][61] = (f_61-4*orbit[x][71]-8*orbit[x][69]-2*orbit[x][67])/2;
|
| 787 |
+
orbit[x][60] = (f_60-4*orbit[x][71]-2*orbit[x][68]-2*orbit[x][67]);
|
| 788 |
+
orbit[x][59] = (f_59-6*orbit[x][70]-2*orbit[x][68]-4*orbit[x][65]);
|
| 789 |
+
orbit[x][58] = (f_58-4*orbit[x][72]-2*orbit[x][71]-1*orbit[x][67]);
|
| 790 |
+
orbit[x][57] = (f_57-12*orbit[x][72]-4*orbit[x][71]-3*orbit[x][70]-1*orbit[x][67]-2*orbit[x][66]);
|
| 791 |
+
orbit[x][56] = (f_56-2*orbit[x][65])/3;
|
| 792 |
+
orbit[x][55] = (f_55-2*orbit[x][71]-2*orbit[x][67])/3;
|
| 793 |
+
orbit[x][54] = (f_54-3*orbit[x][70]-1*orbit[x][66]-2*orbit[x][65])/2;
|
| 794 |
+
orbit[x][53] = (f_53-2*orbit[x][68]-2*orbit[x][64]-2*orbit[x][63]);
|
| 795 |
+
orbit[x][52] = (f_52-2*orbit[x][66]-2*orbit[x][64]-1*orbit[x][59])/2;
|
| 796 |
+
orbit[x][51] = (f_51-2*orbit[x][68]-2*orbit[x][63]-4*orbit[x][62]);
|
| 797 |
+
orbit[x][50] = (f_50-1*orbit[x][68]-2*orbit[x][63])/3;
|
| 798 |
+
orbit[x][49] = (f_49-1*orbit[x][68]-1*orbit[x][64]-2*orbit[x][62])/2;
|
| 799 |
+
orbit[x][48] = (f_48-4*orbit[x][71]-8*orbit[x][69]-2*orbit[x][68]-2*orbit[x][67]-2*orbit[x][64]-2*orbit[x][61]-1*orbit[x][60]);
|
| 800 |
+
orbit[x][47] = (f_47-3*orbit[x][70]-2*orbit[x][68]-1*orbit[x][66]-1*orbit[x][63]-1*orbit[x][60]);
|
| 801 |
+
orbit[x][46] = (f_46-3*orbit[x][70]-2*orbit[x][68]-2*orbit[x][65]-1*orbit[x][63]-1*orbit[x][59]);
|
| 802 |
+
orbit[x][45] = (f_45-2*orbit[x][65]-2*orbit[x][62]-3*orbit[x][56]);
|
| 803 |
+
orbit[x][44] = (f_44-1*orbit[x][67]-2*orbit[x][61])/4;
|
| 804 |
+
orbit[x][43] = (f_43-2*orbit[x][66]-1*orbit[x][60]-1*orbit[x][59])/2;
|
| 805 |
+
orbit[x][42] = (f_42-2*orbit[x][71]-4*orbit[x][69]-2*orbit[x][67]-2*orbit[x][61]-3*orbit[x][55]);
|
| 806 |
+
orbit[x][41] = (f_41-2*orbit[x][71]-1*orbit[x][68]-2*orbit[x][67]-1*orbit[x][60]-3*orbit[x][55]);
|
| 807 |
+
orbit[x][40] = (f_40-6*orbit[x][70]-2*orbit[x][68]-2*orbit[x][66]-4*orbit[x][65]-1*orbit[x][60]-1*orbit[x][59]-4*orbit[x][54]);
|
| 808 |
+
orbit[x][39] = (f_39-4*orbit[x][65]-1*orbit[x][59]-6*orbit[x][56])/2;
|
| 809 |
+
orbit[x][38] = (f_38-1*orbit[x][68]-1*orbit[x][64]-2*orbit[x][63]-1*orbit[x][53]-3*orbit[x][50]);
|
| 810 |
+
orbit[x][37] = (f_37-2*orbit[x][68]-2*orbit[x][64]-2*orbit[x][63]-4*orbit[x][62]-1*orbit[x][53]-1*orbit[x][51]-4*orbit[x][49]);
|
| 811 |
+
orbit[x][36] = (f_36-1*orbit[x][68]-2*orbit[x][63]-2*orbit[x][62]-1*orbit[x][51]-3*orbit[x][50]);
|
| 812 |
+
orbit[x][35] = (f_35-1*orbit[x][59]-2*orbit[x][52]-2*orbit[x][45])/2;
|
| 813 |
+
orbit[x][34] = (f_34-1*orbit[x][59]-2*orbit[x][52]-1*orbit[x][51])/2;
|
| 814 |
+
orbit[x][33] = (f_33-1*orbit[x][67]-2*orbit[x][61]-3*orbit[x][58]-4*orbit[x][44]-2*orbit[x][42])/2;
|
| 815 |
+
orbit[x][32] = (f_32-2*orbit[x][66]-1*orbit[x][60]-1*orbit[x][59]-2*orbit[x][57]-2*orbit[x][43]-2*orbit[x][41]-1*orbit[x][40])/2;
|
| 816 |
+
orbit[x][31] = (f_31-2*orbit[x][65]-1*orbit[x][59]-3*orbit[x][56]-1*orbit[x][43]-2*orbit[x][39]);
|
| 817 |
+
orbit[x][30] = (f_30-1*orbit[x][67]-1*orbit[x][63]-2*orbit[x][61]-1*orbit[x][53]-4*orbit[x][44]);
|
| 818 |
+
orbit[x][29] = (f_29-2*orbit[x][66]-2*orbit[x][64]-1*orbit[x][60]-1*orbit[x][59]-1*orbit[x][53]-2*orbit[x][52]-2*orbit[x][43]);
|
| 819 |
+
orbit[x][28] = (f_28-2*orbit[x][65]-2*orbit[x][62]-1*orbit[x][59]-1*orbit[x][51]-1*orbit[x][43]);
|
| 820 |
+
orbit[x][27] = (f_27-1*orbit[x][59]-1*orbit[x][51]-2*orbit[x][45])/2;
|
| 821 |
+
orbit[x][26] = (f_26-2*orbit[x][67]-2*orbit[x][63]-2*orbit[x][61]-6*orbit[x][58]-1*orbit[x][53]-2*orbit[x][47]-2*orbit[x][42]);
|
| 822 |
+
orbit[x][25] = (f_25-2*orbit[x][66]-2*orbit[x][64]-1*orbit[x][59]-2*orbit[x][57]-2*orbit[x][52]-1*orbit[x][48]-1*orbit[x][40])/2;
|
| 823 |
+
orbit[x][24] = (f_24-4*orbit[x][65]-4*orbit[x][62]-1*orbit[x][59]-6*orbit[x][56]-1*orbit[x][51]-2*orbit[x][45]-2*orbit[x][39]);
|
| 824 |
+
orbit[x][23] = (f_23-1*orbit[x][55]-1*orbit[x][42]-2*orbit[x][33])/4;
|
| 825 |
+
orbit[x][22] = (f_22-2*orbit[x][54]-1*orbit[x][40]-1*orbit[x][39]-1*orbit[x][32]-2*orbit[x][31])/3;
|
| 826 |
+
orbit[x][21] = (f_21-3*orbit[x][55]-3*orbit[x][50]-2*orbit[x][42]-2*orbit[x][38]-2*orbit[x][33]);
|
| 827 |
+
orbit[x][20] = (f_20-2*orbit[x][54]-2*orbit[x][49]-1*orbit[x][40]-1*orbit[x][37]-1*orbit[x][32]);
|
| 828 |
+
orbit[x][19] = (f_19-4*orbit[x][54]-4*orbit[x][49]-1*orbit[x][40]-2*orbit[x][39]-1*orbit[x][37]-2*orbit[x][35]-2*orbit[x][31]);
|
| 829 |
+
orbit[x][18] = (f_18-1*orbit[x][59]-1*orbit[x][51]-2*orbit[x][46]-2*orbit[x][45]-2*orbit[x][36]-2*orbit[x][27]-1*orbit[x][24])/2;
|
| 830 |
+
orbit[x][17] = (f_17-1*orbit[x][60]-1*orbit[x][53]-1*orbit[x][51]-1*orbit[x][48]-1*orbit[x][37]-2*orbit[x][34]-2*orbit[x][30])/2;
|
| 831 |
+
orbit[x][16] = (f_16-1*orbit[x][59]-2*orbit[x][52]-1*orbit[x][51]-2*orbit[x][46]-2*orbit[x][36]-2*orbit[x][34]-1*orbit[x][29]);
|
| 832 |
+
orbit[x][15] = (f_15-1*orbit[x][59]-2*orbit[x][52]-1*orbit[x][51]-2*orbit[x][45]-2*orbit[x][35]-2*orbit[x][34]-2*orbit[x][27]);
|
| 833 |
+
}
|
| 834 |
+
endTime = clock();
|
| 835 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 836 |
+
|
| 837 |
+
endTime_all = endTime;
|
| 838 |
+
printf("total: %.2f sec\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
|
| 842 |
+
/** count edge orbits of graphlets on max 5 nodes */
|
| 843 |
+
void ecount5() {
|
| 844 |
+
clock_t startTime, endTime;
|
| 845 |
+
startTime = clock();
|
| 846 |
+
clock_t startTime_all, endTime_all;
|
| 847 |
+
startTime_all = startTime;
|
| 848 |
+
int frac,frac_prev;
|
| 849 |
+
|
| 850 |
+
// precompute common nodes
|
| 851 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 852 |
+
frac_prev=-1;
|
| 853 |
+
for (int x=0;x<n;x++) {
|
| 854 |
+
frac = 100LL*x/n;
|
| 855 |
+
if (frac!=frac_prev) {
|
| 856 |
+
printf("%d%%\r",frac);
|
| 857 |
+
frac_prev=frac;
|
| 858 |
+
}
|
| 859 |
+
for (int n1=0;n1<deg[x];n1++) {
|
| 860 |
+
int a=adj[x][n1];
|
| 861 |
+
for (int n2=n1+1;n2<deg[x];n2++) {
|
| 862 |
+
int b=adj[x][n2];
|
| 863 |
+
PAIR ab=PAIR(a,b);
|
| 864 |
+
common2[ab]++;
|
| 865 |
+
for (int n3=n2+1;n3<deg[x];n3++) {
|
| 866 |
+
int c=adj[x][n3];
|
| 867 |
+
int st = adjacent(a,b)+adjacent(a,c)+adjacent(b,c);
|
| 868 |
+
if (st<2) continue;
|
| 869 |
+
TRIPLE abc=TRIPLE(a,b,c);
|
| 870 |
+
common3[abc]++;
|
| 871 |
+
}
|
| 872 |
+
}
|
| 873 |
+
}
|
| 874 |
+
}
|
| 875 |
+
// precompute triangles that span over edges
|
| 876 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 877 |
+
for (int i=0;i<m;i++) {
|
| 878 |
+
int x=edges[i].a, y=edges[i].b;
|
| 879 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 880 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 881 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 882 |
+
else { yi++; }
|
| 883 |
+
}
|
| 884 |
+
}
|
| 885 |
+
endTime = clock();
|
| 886 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 887 |
+
startTime = endTime;
|
| 888 |
+
|
| 889 |
+
// count full graphlets
|
| 890 |
+
printf("stage 2 - counting full graphlets\n");
|
| 891 |
+
int64 *C5 = (int64*)calloc(m,sizeof(int64));
|
| 892 |
+
int *neighx = (int*)malloc(n*sizeof(int)); // lookup table - edges to neighbors of x
|
| 893 |
+
memset(neighx,-1,n*sizeof(int));
|
| 894 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn; // lookup table - common neighbors of x and y
|
| 895 |
+
PII *neigh_edges = (PII*)malloc(n*sizeof(PII)); // list of common neighbors of x and y
|
| 896 |
+
int *neigh2 = (int*)malloc(n*sizeof(int)), nn2;
|
| 897 |
+
TIII *neigh2_edges = (TIII*)malloc(n*sizeof(TIII));
|
| 898 |
+
frac_prev=-1;
|
| 899 |
+
for (int x=0;x<n;x++) {
|
| 900 |
+
frac = 100LL*x/n;
|
| 901 |
+
if (frac!=frac_prev) {
|
| 902 |
+
printf("%d%%\r",frac);
|
| 903 |
+
frac_prev=frac;
|
| 904 |
+
}
|
| 905 |
+
|
| 906 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 907 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 908 |
+
neighx[y]=xy;
|
| 909 |
+
}
|
| 910 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 911 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 912 |
+
if (y >= x) break;
|
| 913 |
+
nn=0;
|
| 914 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 915 |
+
int z=inc[y][ny].first, yz=inc[y][ny].second;
|
| 916 |
+
if (z >= y) break;
|
| 917 |
+
if (neighx[z]==-1) continue;
|
| 918 |
+
int xz=neighx[z];
|
| 919 |
+
neigh[nn]=z;
|
| 920 |
+
neigh_edges[nn]={xz, yz};
|
| 921 |
+
nn++;
|
| 922 |
+
}
|
| 923 |
+
for (int i=0;i<nn;i++) {
|
| 924 |
+
int z = neigh[i], xz = neigh_edges[i].first, yz = neigh_edges[i].second;
|
| 925 |
+
nn2 = 0;
|
| 926 |
+
for (int j=i+1;j<nn;j++) {
|
| 927 |
+
int w = neigh[j], xw = neigh_edges[j].first, yw = neigh_edges[j].second;
|
| 928 |
+
if (adjacent(z,w)) {
|
| 929 |
+
neigh2[nn2]=w;
|
| 930 |
+
int zw=getEdgeId(z,w);
|
| 931 |
+
neigh2_edges[nn2]={xw,yw,zw};
|
| 932 |
+
nn2++;
|
| 933 |
+
}
|
| 934 |
+
}
|
| 935 |
+
for (int i2=0;i2<nn2;i2++) {
|
| 936 |
+
int z2 = neigh2[i2];
|
| 937 |
+
int z2x=neigh2_edges[i2].first, z2y=neigh2_edges[i2].second, z2z=neigh2_edges[i2].third;
|
| 938 |
+
for (int j2=i2+1;j2<nn2;j2++) {
|
| 939 |
+
int z3 = neigh2[j2];
|
| 940 |
+
int z3x=neigh2_edges[j2].first, z3y=neigh2_edges[j2].second, z3z=neigh2_edges[j2].third;
|
| 941 |
+
if (adjacent(z2,z3)) {
|
| 942 |
+
int zid=getEdgeId(z2,z3);
|
| 943 |
+
C5[xy]++; C5[xz]++; C5[yz]++;
|
| 944 |
+
C5[z2x]++; C5[z2y]++; C5[z2z]++;
|
| 945 |
+
C5[z3x]++; C5[z3y]++; C5[z3z]++;
|
| 946 |
+
C5[zid]++;
|
| 947 |
+
}
|
| 948 |
+
}
|
| 949 |
+
}
|
| 950 |
+
}
|
| 951 |
+
}
|
| 952 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 953 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 954 |
+
neighx[y]=-1;
|
| 955 |
+
}
|
| 956 |
+
}
|
| 957 |
+
endTime = clock();
|
| 958 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 959 |
+
startTime = endTime;
|
| 960 |
+
|
| 961 |
+
// set up a system of equations relating orbits for every node
|
| 962 |
+
printf("stage 3 - building systems of equations\n");
|
| 963 |
+
int *common_x = (int*)calloc(n,sizeof(int));
|
| 964 |
+
int *common_x_list = (int*)malloc(n*sizeof(int)), nc_x=0;
|
| 965 |
+
int *common_y = (int*)calloc(n,sizeof(int));
|
| 966 |
+
int *common_y_list = (int*)malloc(n*sizeof(int)), nc_y=0;
|
| 967 |
+
frac_prev=-1;
|
| 968 |
+
|
| 969 |
+
for (int x=0;x<n;x++) {
|
| 970 |
+
frac = 100LL*x/n;
|
| 971 |
+
if (frac!=frac_prev) {
|
| 972 |
+
printf("%d%%\r",frac);
|
| 973 |
+
frac_prev=frac;
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
// common nodes of x and some other node
|
| 977 |
+
for (int i=0;i<nc_x;i++) common_x[common_x_list[i]]=0;
|
| 978 |
+
nc_x=0;
|
| 979 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 980 |
+
int a=adj[x][nx];
|
| 981 |
+
for (int na=0;na<deg[a];na++) {
|
| 982 |
+
int z=adj[a][na];
|
| 983 |
+
if (z==x) continue;
|
| 984 |
+
if (common_x[z]==0) common_x_list[nc_x++]=z;
|
| 985 |
+
common_x[z]++;
|
| 986 |
+
}
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 990 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 991 |
+
int e=xy;
|
| 992 |
+
if (y>=x) break;
|
| 993 |
+
|
| 994 |
+
// common nodes of y and some other node
|
| 995 |
+
for (int i=0;i<nc_y;i++) common_y[common_y_list[i]]=0;
|
| 996 |
+
nc_y=0;
|
| 997 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 998 |
+
int a=adj[y][ny];
|
| 999 |
+
for (int na=0;na<deg[a];na++) {
|
| 1000 |
+
int z=adj[a][na];
|
| 1001 |
+
if (z==y) continue;
|
| 1002 |
+
if (common_y[z]==0) common_y_list[nc_y++]=z;
|
| 1003 |
+
common_y[z]++;
|
| 1004 |
+
}
|
| 1005 |
+
}
|
| 1006 |
+
|
| 1007 |
+
int64 f_66=0, f_65=0, f_62=0, f_61=0, f_60=0, f_51=0, f_50=0; // 11
|
| 1008 |
+
int64 f_64=0, f_58=0, f_55=0, f_48=0, f_41=0, f_35=0; // 10
|
| 1009 |
+
int64 f_63=0, f_59=0, f_57=0, f_54=0, f_53=0, f_52=0, f_47=0, f_40=0, f_39=0, f_34=0, f_33=0; // 9
|
| 1010 |
+
int64 f_45=0, f_36=0, f_26=0, f_23=0, f_19=0; // 7
|
| 1011 |
+
int64 f_49=0, f_38=0, f_37=0, f_32=0, f_25=0, f_22=0, f_18=0; // 6
|
| 1012 |
+
int64 f_56=0, f_46=0, f_44=0, f_43=0, f_42=0, f_31=0, f_30=0; // 5
|
| 1013 |
+
int64 f_27=0, f_17=0, f_15=0; // 4
|
| 1014 |
+
int64 f_20=0, f_16=0, f_13=0; // 3
|
| 1015 |
+
int64 f_29=0, f_28=0, f_24=0, f_21=0, f_14=0, f_12=0; // 2
|
| 1016 |
+
|
| 1017 |
+
// smaller (3-node) graphlets
|
| 1018 |
+
orbit[x][0] = deg[x];
|
| 1019 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1020 |
+
int z=adj[x][nx1];
|
| 1021 |
+
if (z==y) continue;
|
| 1022 |
+
if (adjacent(y,z)) eorbit[e][1]++;
|
| 1023 |
+
else eorbit[e][0]++;
|
| 1024 |
+
}
|
| 1025 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1026 |
+
int z=adj[y][ny];
|
| 1027 |
+
if (z==x) continue;
|
| 1028 |
+
if (!adjacent(x,z)) eorbit[e][0]++;
|
| 1029 |
+
}
|
| 1030 |
+
|
| 1031 |
+
// edge-orbit 11 = (14,14)
|
| 1032 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1033 |
+
int a=adj[x][nx1], xa=inc[x][nx1].second;
|
| 1034 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1035 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1036 |
+
int b=adj[x][nx2], xb=inc[x][nx2].second;
|
| 1037 |
+
if (b==y || !adjacent(y,b) || !adjacent(a,b)) continue;
|
| 1038 |
+
int ya=getEdgeId(y,a), yb=getEdgeId(y,b), ab=getEdgeId(a,b);
|
| 1039 |
+
eorbit[e][11]++;
|
| 1040 |
+
f_66 += common3_get(TRIPLE(x,y,a))-1;
|
| 1041 |
+
f_66 += common3_get(TRIPLE(x,y,b))-1;
|
| 1042 |
+
f_65 += common3_get(TRIPLE(a,b,x))-1;
|
| 1043 |
+
f_65 += common3_get(TRIPLE(a,b,y))-1;
|
| 1044 |
+
f_62 += tri[xy]-2;
|
| 1045 |
+
f_61 += (tri[xa]-2)+(tri[xb]-2)+(tri[ya]-2)+(tri[yb]-2);
|
| 1046 |
+
f_60 += tri[ab]-2;
|
| 1047 |
+
f_51 += (deg[x]-3)+(deg[y]-3);
|
| 1048 |
+
f_50 += (deg[a]-3)+(deg[b]-3);
|
| 1049 |
+
}
|
| 1050 |
+
}
|
| 1051 |
+
|
| 1052 |
+
// edge-orbit 10 = (13,13)
|
| 1053 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1054 |
+
int a=adj[x][nx1], xa=inc[x][nx1].second;
|
| 1055 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1056 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1057 |
+
int b=adj[x][nx2], xb=inc[x][nx2].second;
|
| 1058 |
+
if (b==y || !adjacent(y,b) || adjacent(a,b)) continue;
|
| 1059 |
+
int ya=getEdgeId(y,a), yb=getEdgeId(y,b);
|
| 1060 |
+
eorbit[e][10]++;
|
| 1061 |
+
f_64 += common3_get(TRIPLE(a,b,x))-1;
|
| 1062 |
+
f_64 += common3_get(TRIPLE(a,b,y))-1;
|
| 1063 |
+
f_58 += common2_get(PAIR(a,b))-2;
|
| 1064 |
+
f_55 += (tri[xa]-1)+(tri[xb]-1)+(tri[ya]-1)+(tri[yb]-1);
|
| 1065 |
+
f_48 += tri[xy]-2;
|
| 1066 |
+
f_41 += (deg[a]-2)+(deg[b]-2);
|
| 1067 |
+
f_35 += (deg[x]-3)+(deg[y]-3);
|
| 1068 |
+
}
|
| 1069 |
+
}
|
| 1070 |
+
|
| 1071 |
+
// edge-orbit 9 = (12,13)
|
| 1072 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1073 |
+
int a=adj[x][nx], xa=inc[x][nx].second;
|
| 1074 |
+
if (a==y) continue;
|
| 1075 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1076 |
+
int b=adj[y][ny], yb=inc[y][ny].second;
|
| 1077 |
+
if (b==x || !adjacent(a,b)) continue;
|
| 1078 |
+
int adj_ya=adjacent(y,a), adj_xb=adjacent(x,b);
|
| 1079 |
+
if (adj_ya+adj_xb!=1) continue;
|
| 1080 |
+
int ab=getEdgeId(a,b);
|
| 1081 |
+
eorbit[e][9]++;
|
| 1082 |
+
if (adj_xb) {
|
| 1083 |
+
int xb=getEdgeId(x,b);
|
| 1084 |
+
f_63 += common3_get(TRIPLE(a,b,y))-1;
|
| 1085 |
+
f_59 += common3_get(TRIPLE(a,b,x));
|
| 1086 |
+
f_57 += common_y[a]-2;
|
| 1087 |
+
f_54 += tri[yb]-1;
|
| 1088 |
+
f_53 += tri[xa]-1;
|
| 1089 |
+
f_47 += tri[xb]-2;
|
| 1090 |
+
f_40 += deg[y]-2;
|
| 1091 |
+
f_39 += deg[a]-2;
|
| 1092 |
+
f_34 += deg[x]-3;
|
| 1093 |
+
f_33 += deg[b]-3;
|
| 1094 |
+
} else if (adj_ya) {
|
| 1095 |
+
int ya=getEdgeId(y,a);
|
| 1096 |
+
f_63 += common3_get(TRIPLE(a,b,x))-1;
|
| 1097 |
+
f_59 += common3_get(TRIPLE(a,b,y));
|
| 1098 |
+
f_57 += common_x[b]-2;
|
| 1099 |
+
f_54 += tri[xa]-1;
|
| 1100 |
+
f_53 += tri[yb]-1;
|
| 1101 |
+
f_47 += tri[ya]-2;
|
| 1102 |
+
f_40 += deg[x]-2;
|
| 1103 |
+
f_39 += deg[b]-2;
|
| 1104 |
+
f_34 += deg[y]-3;
|
| 1105 |
+
f_33 += deg[a]-3;
|
| 1106 |
+
}
|
| 1107 |
+
f_52 += tri[ab]-1;
|
| 1108 |
+
}
|
| 1109 |
+
}
|
| 1110 |
+
|
| 1111 |
+
// edge-orbit 8 = (10,11)
|
| 1112 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1113 |
+
int a=adj[x][nx];
|
| 1114 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1115 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1116 |
+
int b=adj[x][nx1];
|
| 1117 |
+
if (b==y || b==a || adjacent(y,b) || adjacent(a,b)) continue;
|
| 1118 |
+
eorbit[e][8]++;
|
| 1119 |
+
}
|
| 1120 |
+
for (int ny1=0;ny1<deg[y];ny1++) {
|
| 1121 |
+
int b=adj[y][ny1];
|
| 1122 |
+
if (b==x || b==a || adjacent(x,b) || adjacent(a,b)) continue;
|
| 1123 |
+
eorbit[e][8]++;
|
| 1124 |
+
}
|
| 1125 |
+
}
|
| 1126 |
+
|
| 1127 |
+
// edge-orbit 7 = (10,10)
|
| 1128 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1129 |
+
int a=adj[x][nx];
|
| 1130 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1131 |
+
for (int na=0;na<deg[a];na++) {
|
| 1132 |
+
int b=adj[a][na], ab=inc[a][na].second;
|
| 1133 |
+
if (b==x || b==y || adjacent(x,b) || adjacent(y,b)) continue;
|
| 1134 |
+
eorbit[e][7]++;
|
| 1135 |
+
f_45 += common_x[b]-1;
|
| 1136 |
+
f_45 += common_y[b]-1;
|
| 1137 |
+
f_36 += tri[ab];
|
| 1138 |
+
f_26 += deg[a]-3;
|
| 1139 |
+
f_23 += deg[b]-1;
|
| 1140 |
+
f_19 += (deg[x]-2)+(deg[y]-2);
|
| 1141 |
+
}
|
| 1142 |
+
}
|
| 1143 |
+
|
| 1144 |
+
// edge-orbit 6 = (9,11)
|
| 1145 |
+
for (int ny1=0;ny1<deg[y];ny1++) {
|
| 1146 |
+
int a=adj[y][ny1], ya=inc[y][ny1].second;
|
| 1147 |
+
if (a==x || adjacent(x,a)) continue;
|
| 1148 |
+
for (int ny2=ny1+1;ny2<deg[y];ny2++) {
|
| 1149 |
+
int b=adj[y][ny2], yb=inc[y][ny2].second;
|
| 1150 |
+
if (b==x || adjacent(x,b) || !adjacent(a,b)) continue;
|
| 1151 |
+
int ab=getEdgeId(a,b);
|
| 1152 |
+
eorbit[e][6]++;
|
| 1153 |
+
f_49 += common3_get(TRIPLE(y,a,b));
|
| 1154 |
+
f_38 += tri[ab]-1;
|
| 1155 |
+
f_37 += tri[xy];
|
| 1156 |
+
f_32 += (tri[ya]-1)+(tri[yb]-1);
|
| 1157 |
+
f_25 += deg[y]-3;
|
| 1158 |
+
f_22 += deg[x]-1;
|
| 1159 |
+
f_18 += (deg[a]-2)+(deg[b]-2);
|
| 1160 |
+
}
|
| 1161 |
+
}
|
| 1162 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1163 |
+
int a=adj[x][nx1], xa=inc[x][nx1].second;
|
| 1164 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1165 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1166 |
+
int b=adj[x][nx2], xb=inc[x][nx2].second;
|
| 1167 |
+
if (b==y || adjacent(y,b) || !adjacent(a,b)) continue;
|
| 1168 |
+
int ab=getEdgeId(a,b);
|
| 1169 |
+
eorbit[e][6]++;
|
| 1170 |
+
f_49 += common3_get(TRIPLE(x,a,b));
|
| 1171 |
+
f_38 += tri[ab]-1;
|
| 1172 |
+
f_37 += tri[xy];
|
| 1173 |
+
f_32 += (tri[xa]-1)+(tri[xb]-1);
|
| 1174 |
+
f_25 += deg[x]-3;
|
| 1175 |
+
f_22 += deg[y]-1;
|
| 1176 |
+
f_18 += (deg[a]-2)+(deg[b]-2);
|
| 1177 |
+
}
|
| 1178 |
+
}
|
| 1179 |
+
|
| 1180 |
+
// edge-orbit 5 = (8,8)
|
| 1181 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1182 |
+
int a=adj[x][nx], xa=inc[x][nx].second;
|
| 1183 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1184 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1185 |
+
int b=adj[y][ny], yb=inc[y][ny].second;
|
| 1186 |
+
if (b==x || adjacent(x,b) || !adjacent(a,b)) continue;
|
| 1187 |
+
int ab=getEdgeId(a,b);
|
| 1188 |
+
eorbit[e][5]++;
|
| 1189 |
+
f_56 += common3_get(TRIPLE(x,a,b));
|
| 1190 |
+
f_56 += common3_get(TRIPLE(y,a,b));
|
| 1191 |
+
f_46 += tri[xy];
|
| 1192 |
+
f_44 += tri[xa]+tri[yb];
|
| 1193 |
+
f_43 += tri[ab];
|
| 1194 |
+
f_42 += common_x[b]-2;
|
| 1195 |
+
f_42 += common_y[a]-2;
|
| 1196 |
+
f_31 += (deg[x]-2)+(deg[y]-2);
|
| 1197 |
+
f_30 += (deg[a]-2)+(deg[b]-2);
|
| 1198 |
+
}
|
| 1199 |
+
}
|
| 1200 |
+
|
| 1201 |
+
// edge-orbit 4 = (6,7)
|
| 1202 |
+
for (int ny1=0;ny1<deg[y];ny1++) {
|
| 1203 |
+
int a=adj[y][ny1];
|
| 1204 |
+
if (a==x || adjacent(x,a)) continue;
|
| 1205 |
+
for (int ny2=ny1+1;ny2<deg[y];ny2++) {
|
| 1206 |
+
int b=adj[y][ny2];
|
| 1207 |
+
if (b==x || adjacent(x,b) || adjacent(a,b)) continue;
|
| 1208 |
+
eorbit[e][4]++;
|
| 1209 |
+
f_27 += tri[xy];
|
| 1210 |
+
f_17 += deg[y]-3;
|
| 1211 |
+
f_15 += (deg[a]-1)+(deg[b]-1);
|
| 1212 |
+
}
|
| 1213 |
+
}
|
| 1214 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1215 |
+
int a=adj[x][nx1];
|
| 1216 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1217 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1218 |
+
int b=adj[x][nx2];
|
| 1219 |
+
if (b==y || adjacent(y,b) || adjacent(a,b)) continue;
|
| 1220 |
+
eorbit[e][4]++;
|
| 1221 |
+
f_27 += tri[xy];
|
| 1222 |
+
f_17 += deg[x]-3;
|
| 1223 |
+
f_15 += (deg[a]-1)+(deg[b]-1);
|
| 1224 |
+
}
|
| 1225 |
+
}
|
| 1226 |
+
|
| 1227 |
+
// edge-orbit 3 = (5,5)
|
| 1228 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1229 |
+
int a=adj[x][nx];
|
| 1230 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1231 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1232 |
+
int b=adj[y][ny];
|
| 1233 |
+
if (b==x || adjacent(x,b) || adjacent(a,b)) continue;
|
| 1234 |
+
eorbit[e][3]++;
|
| 1235 |
+
f_20 += tri[xy];
|
| 1236 |
+
f_16 += (deg[x]-2)+(deg[y]-2);
|
| 1237 |
+
f_13 += (deg[a]-1)+(deg[b]-1);
|
| 1238 |
+
}
|
| 1239 |
+
}
|
| 1240 |
+
|
| 1241 |
+
// edge-orbit 2 = (4,5)
|
| 1242 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1243 |
+
int a=adj[y][ny];
|
| 1244 |
+
if (a==x || adjacent(x,a)) continue;
|
| 1245 |
+
for (int na=0;na<deg[a];na++) {
|
| 1246 |
+
int b=adj[a][na], ab=inc[a][na].second;
|
| 1247 |
+
if (b==y || adjacent(y,b) || adjacent(x,b)) continue;
|
| 1248 |
+
eorbit[e][2]++;
|
| 1249 |
+
f_29 += common_y[b]-1;
|
| 1250 |
+
f_28 += common_x[b];
|
| 1251 |
+
f_24 += tri[xy];
|
| 1252 |
+
f_21 += tri[ab];
|
| 1253 |
+
f_14 += deg[a]-2;
|
| 1254 |
+
f_12 += deg[b]-1;
|
| 1255 |
+
}
|
| 1256 |
+
}
|
| 1257 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1258 |
+
int a=adj[x][nx];
|
| 1259 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1260 |
+
for (int na=0;na<deg[a];na++) {
|
| 1261 |
+
int b=adj[a][na], ab=inc[a][na].second;
|
| 1262 |
+
if (b==x || adjacent(x,b) || adjacent(y,b)) continue;
|
| 1263 |
+
eorbit[e][2]++;
|
| 1264 |
+
f_29 += common_x[b]-1;
|
| 1265 |
+
f_28 += common_y[b];
|
| 1266 |
+
f_24 += tri[xy];
|
| 1267 |
+
f_21 += tri[ab];
|
| 1268 |
+
f_14 += deg[a]-2;
|
| 1269 |
+
f_12 += deg[b]-1;
|
| 1270 |
+
}
|
| 1271 |
+
}
|
| 1272 |
+
|
| 1273 |
+
// solve system of equations
|
| 1274 |
+
eorbit[e][67]=C5[e];
|
| 1275 |
+
eorbit[e][66]=(f_66-6*eorbit[e][67])/2;
|
| 1276 |
+
eorbit[e][65]=(f_65-6*eorbit[e][67]);
|
| 1277 |
+
eorbit[e][64]=(f_64-2*eorbit[e][66]);
|
| 1278 |
+
eorbit[e][63]=(f_63-2*eorbit[e][65])/2;
|
| 1279 |
+
eorbit[e][62]=(f_62-2*eorbit[e][66]-3*eorbit[e][67]);
|
| 1280 |
+
eorbit[e][61]=(f_61-2*eorbit[e][65]-4*eorbit[e][66]-12*eorbit[e][67]);
|
| 1281 |
+
eorbit[e][60]=(f_60-1*eorbit[e][65]-3*eorbit[e][67]);
|
| 1282 |
+
eorbit[e][59]=(f_59-2*eorbit[e][65])/2;
|
| 1283 |
+
eorbit[e][58]=(f_58-1*eorbit[e][64]-1*eorbit[e][66]);
|
| 1284 |
+
eorbit[e][57]=(f_57-2*eorbit[e][63]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1285 |
+
eorbit[e][56]=(f_56-2*eorbit[e][63])/2;
|
| 1286 |
+
eorbit[e][55]=(f_55-4*eorbit[e][62]-2*eorbit[e][64]-4*eorbit[e][66]);
|
| 1287 |
+
eorbit[e][54]=(f_54-1*eorbit[e][61]-2*eorbit[e][63]-2*eorbit[e][65])/2;
|
| 1288 |
+
eorbit[e][53]=(f_53-2*eorbit[e][59]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1289 |
+
eorbit[e][52]=(f_52-2*eorbit[e][59]-2*eorbit[e][63]-2*eorbit[e][65]);
|
| 1290 |
+
eorbit[e][51]=(f_51-1*eorbit[e][61]-2*eorbit[e][62]-1*eorbit[e][65]-4*eorbit[e][66]-6*eorbit[e][67]);
|
| 1291 |
+
eorbit[e][50]=(f_50-2*eorbit[e][60]-1*eorbit[e][61]-2*eorbit[e][65]-2*eorbit[e][66]-6*eorbit[e][67]);
|
| 1292 |
+
eorbit[e][49]=(f_49-1*eorbit[e][59])/3;
|
| 1293 |
+
eorbit[e][48]=(f_48-2*eorbit[e][62]-1*eorbit[e][66])/3;
|
| 1294 |
+
eorbit[e][47]=(f_47-2*eorbit[e][59]-1*eorbit[e][61]-2*eorbit[e][65])/2;
|
| 1295 |
+
eorbit[e][46]=(f_46-1*eorbit[e][57]-1*eorbit[e][63]);
|
| 1296 |
+
eorbit[e][45]=(f_45-1*eorbit[e][52]-4*eorbit[e][58]-4*eorbit[e][60]);
|
| 1297 |
+
eorbit[e][44]=(f_44-2*eorbit[e][56]-1*eorbit[e][57]-2*eorbit[e][63]);
|
| 1298 |
+
eorbit[e][43]=(f_43-2*eorbit[e][56]-1*eorbit[e][63]);
|
| 1299 |
+
eorbit[e][42]=(f_42-2*eorbit[e][56]-1*eorbit[e][57]-2*eorbit[e][63])/2;
|
| 1300 |
+
eorbit[e][41]=(f_41-1*eorbit[e][55]-2*eorbit[e][58]-2*eorbit[e][62]-2*eorbit[e][64]-2*eorbit[e][66]);
|
| 1301 |
+
eorbit[e][40]=(f_40-2*eorbit[e][54]-1*eorbit[e][55]-1*eorbit[e][57]-1*eorbit[e][61]-2*eorbit[e][63]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1302 |
+
eorbit[e][39]=(f_39-1*eorbit[e][52]-1*eorbit[e][53]-1*eorbit[e][57]-2*eorbit[e][59]-2*eorbit[e][63]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1303 |
+
eorbit[e][38]=(f_38-3*eorbit[e][49]-1*eorbit[e][56]-1*eorbit[e][59]);
|
| 1304 |
+
eorbit[e][37]=(f_37-1*eorbit[e][53]-1*eorbit[e][59]);
|
| 1305 |
+
eorbit[e][36]=(f_36-1*eorbit[e][52]-2*eorbit[e][60])/2;
|
| 1306 |
+
eorbit[e][35]=(f_35-6*eorbit[e][48]-1*eorbit[e][55]-4*eorbit[e][62]-1*eorbit[e][64]-2*eorbit[e][66]);
|
| 1307 |
+
eorbit[e][34]=(f_34-2*eorbit[e][47]-1*eorbit[e][53]-1*eorbit[e][55]-2*eorbit[e][59]-1*eorbit[e][61]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1308 |
+
eorbit[e][33]=(f_33-2*eorbit[e][47]-1*eorbit[e][52]-2*eorbit[e][54]-2*eorbit[e][59]-1*eorbit[e][61]-2*eorbit[e][63]-2*eorbit[e][65]);
|
| 1309 |
+
eorbit[e][32]=(f_32-6*eorbit[e][49]-1*eorbit[e][53]-2*eorbit[e][59])/2;
|
| 1310 |
+
eorbit[e][31]=(f_31-2*eorbit[e][42]-1*eorbit[e][44]-2*eorbit[e][46]-2*eorbit[e][56]-2*eorbit[e][57]-2*eorbit[e][63]);
|
| 1311 |
+
eorbit[e][30]=(f_30-2*eorbit[e][42]-2*eorbit[e][43]-1*eorbit[e][44]-4*eorbit[e][56]-1*eorbit[e][57]-2*eorbit[e][63]);
|
| 1312 |
+
eorbit[e][29]=(f_29-2*eorbit[e][38]-1*eorbit[e][45]-1*eorbit[e][52])/2;
|
| 1313 |
+
eorbit[e][28]=(f_28-2*eorbit[e][43]-1*eorbit[e][45]-1*eorbit[e][52])/2;
|
| 1314 |
+
eorbit[e][27]=(f_27-1*eorbit[e][34]-1*eorbit[e][47]);
|
| 1315 |
+
eorbit[e][26]=(f_26-1*eorbit[e][33]-2*eorbit[e][36]-1*eorbit[e][50]-1*eorbit[e][52]-2*eorbit[e][60])/2;
|
| 1316 |
+
eorbit[e][25]=(f_25-2*eorbit[e][32]-1*eorbit[e][37]-3*eorbit[e][49]-1*eorbit[e][53]-1*eorbit[e][59]);
|
| 1317 |
+
eorbit[e][24]=(f_24-1*eorbit[e][39]-1*eorbit[e][45]-1*eorbit[e][52]);
|
| 1318 |
+
eorbit[e][23]=(f_23-2*eorbit[e][36]-1*eorbit[e][45]-1*eorbit[e][52]-2*eorbit[e][58]-2*eorbit[e][60]);
|
| 1319 |
+
eorbit[e][22]=(f_22-1*eorbit[e][37]-1*eorbit[e][44]-1*eorbit[e][53]-1*eorbit[e][56]-1*eorbit[e][59]);
|
| 1320 |
+
eorbit[e][21]=(f_21-2*eorbit[e][38]-2*eorbit[e][43]-1*eorbit[e][52])/2;
|
| 1321 |
+
eorbit[e][20]=(f_20-1*eorbit[e][40]-1*eorbit[e][54]);
|
| 1322 |
+
eorbit[e][19]=(f_19-1*eorbit[e][33]-2*eorbit[e][41]-1*eorbit[e][45]-2*eorbit[e][50]-1*eorbit[e][52]-4*eorbit[e][58]-4*eorbit[e][60]);
|
| 1323 |
+
eorbit[e][18]=(f_18-2*eorbit[e][32]-2*eorbit[e][38]-1*eorbit[e][44]-6*eorbit[e][49]-1*eorbit[e][53]-2*eorbit[e][56]-2*eorbit[e][59]);
|
| 1324 |
+
eorbit[e][17]=(f_17-2*eorbit[e][25]-1*eorbit[e][27]-1*eorbit[e][32]-1*eorbit[e][34]-1*eorbit[e][47])/3;
|
| 1325 |
+
eorbit[e][16]=(f_16-2*eorbit[e][20]-2*eorbit[e][22]-1*eorbit[e][31]-2*eorbit[e][40]-1*eorbit[e][44]-2*eorbit[e][54])/2;
|
| 1326 |
+
eorbit[e][15]=(f_15-2*eorbit[e][25]-2*eorbit[e][29]-1*eorbit[e][31]-2*eorbit[e][32]-1*eorbit[e][34]-2*eorbit[e][42]-2*eorbit[e][47]);
|
| 1327 |
+
eorbit[e][14]=(f_14-1*eorbit[e][18]-2*eorbit[e][21]-1*eorbit[e][30]-2*eorbit[e][38]-1*eorbit[e][39]-2*eorbit[e][43]-1*eorbit[e][52])/2;
|
| 1328 |
+
eorbit[e][13]=(f_13-2*eorbit[e][22]-2*eorbit[e][28]-1*eorbit[e][31]-1*eorbit[e][40]-2*eorbit[e][44]-2*eorbit[e][54]);
|
| 1329 |
+
eorbit[e][12]=(f_12-2*eorbit[e][21]-2*eorbit[e][28]-2*eorbit[e][29]-2*eorbit[e][38]-2*eorbit[e][43]-1*eorbit[e][45]-1*eorbit[e][52]);
|
| 1330 |
+
}
|
| 1331 |
+
}
|
| 1332 |
+
|
| 1333 |
+
endTime = clock();
|
| 1334 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 1335 |
+
|
| 1336 |
+
endTime_all = endTime;
|
| 1337 |
+
printf("total: %.2f\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 1338 |
+
}
|
| 1339 |
+
|
| 1340 |
+
int writeResults(int g, const char* output_filename) {
|
| 1341 |
+
fstream fout;
|
| 1342 |
+
if (fout.fail()) {
|
| 1343 |
+
cerr << "Failed to open file " << output_filename << endl;
|
| 1344 |
+
return 1;
|
| 1345 |
+
}
|
| 1346 |
+
fout.open(output_filename, fstream::out | fstream::binary);
|
| 1347 |
+
int no[] = {0,0,1,4,15,73};
|
| 1348 |
+
for (int i=0;i<n;i++) {
|
| 1349 |
+
for (int j=0;j<no[g];j++) {
|
| 1350 |
+
if (j!=0)
|
| 1351 |
+
fout << " ";
|
| 1352 |
+
fout << orbit[i][j];
|
| 1353 |
+
}
|
| 1354 |
+
fout << endl;
|
| 1355 |
+
}
|
| 1356 |
+
fout.close();
|
| 1357 |
+
}
|
| 1358 |
+
|
| 1359 |
+
string writeResultsString(int g) {
|
| 1360 |
+
std::stringstream ss("", ios_base::app | ios_base::out);
|
| 1361 |
+
int no[] = {0,0,1,4,15,73};
|
| 1362 |
+
for (int i=0;i<n;i++) {
|
| 1363 |
+
for (int j=0;j<no[g];j++) {
|
| 1364 |
+
if (j!=0)
|
| 1365 |
+
ss << " ";
|
| 1366 |
+
ss << orbit[i][j];
|
| 1367 |
+
}
|
| 1368 |
+
ss << endl;
|
| 1369 |
+
}
|
| 1370 |
+
return ss.str();
|
| 1371 |
+
}
|
| 1372 |
+
|
| 1373 |
+
int writeEdgeResults(int g, const char* output_filename) {
|
| 1374 |
+
fstream fout;
|
| 1375 |
+
if (fout.fail()) {
|
| 1376 |
+
cerr << "Failed to open file " << output_filename << endl;
|
| 1377 |
+
return 1;
|
| 1378 |
+
}
|
| 1379 |
+
int no[] = {0,0,0,2,12,68};
|
| 1380 |
+
for (int i=0;i<m;i++) {
|
| 1381 |
+
for (int j=0;j<no[g];j++) {
|
| 1382 |
+
if (j!=0) fout << " ";
|
| 1383 |
+
fout << eorbit[i][j];
|
| 1384 |
+
}
|
| 1385 |
+
fout << endl;
|
| 1386 |
+
}
|
| 1387 |
+
fout.close();
|
| 1388 |
+
}
|
| 1389 |
+
|
| 1390 |
+
string writeEdgeResultsString(int g) {
|
| 1391 |
+
std::stringstream ss("", ios_base::app | ios_base::out);
|
| 1392 |
+
int no[] = {0,0,0,2,12,68};
|
| 1393 |
+
for (int i=0;i<m;i++) {
|
| 1394 |
+
for (int j=0;j<no[g];j++) {
|
| 1395 |
+
if (j!=0) ss << " ";
|
| 1396 |
+
ss << eorbit[i][j];
|
| 1397 |
+
}
|
| 1398 |
+
ss << endl;
|
| 1399 |
+
}
|
| 1400 |
+
return ss.str();
|
| 1401 |
+
}
|
| 1402 |
+
|
| 1403 |
+
int motif_counts(const char* orbit_type, int graphlet_size,
|
| 1404 |
+
const char* input_filename, const char* output_filename, string &out_str) {
|
| 1405 |
+
fstream fin; // input and output files
|
| 1406 |
+
// open input, output files
|
| 1407 |
+
if (strcmp(orbit_type, "node")!=0 && strcmp(orbit_type, "edge")!=0) {
|
| 1408 |
+
cerr << "Incorrect orbit type '" << orbit_type << "'. Should be 'node' or 'edge'." << endl;
|
| 1409 |
+
return 0;
|
| 1410 |
+
}
|
| 1411 |
+
if (graphlet_size!=4 && graphlet_size!=5) {
|
| 1412 |
+
cerr << "Incorrect graphlet size " << graphlet_size << ". Should be 4 or 5." << endl;
|
| 1413 |
+
return 0;
|
| 1414 |
+
}
|
| 1415 |
+
fin.open(input_filename, fstream::in);
|
| 1416 |
+
if (fin.fail()) {
|
| 1417 |
+
cerr << "Failed to open file " << input_filename << endl;
|
| 1418 |
+
return 0;
|
| 1419 |
+
}
|
| 1420 |
+
// read input graph
|
| 1421 |
+
fin >> n >> m;
|
| 1422 |
+
int d_max=0;
|
| 1423 |
+
edges = (PAIR*)malloc(m*sizeof(PAIR));
|
| 1424 |
+
deg = (int*)calloc(n,sizeof(int));
|
| 1425 |
+
for (int i=0;i<m;i++) {
|
| 1426 |
+
int a,b;
|
| 1427 |
+
fin >> a >> b;
|
| 1428 |
+
if (!(0<=a && a<n) || !(0<=b && b<n)) {
|
| 1429 |
+
cerr << "Node ids should be between 0 and n-1." << endl;
|
| 1430 |
+
return 0;
|
| 1431 |
+
}
|
| 1432 |
+
if (a==b) {
|
| 1433 |
+
cerr << "Self loops (edge from x to x) are not allowed." << endl;
|
| 1434 |
+
return 0;
|
| 1435 |
+
}
|
| 1436 |
+
deg[a]++; deg[b]++;
|
| 1437 |
+
edges[i]=PAIR(a,b);
|
| 1438 |
+
}
|
| 1439 |
+
for (int i=0;i<n;i++) d_max=max(d_max,deg[i]);
|
| 1440 |
+
printf("nodes: %d\n",n);
|
| 1441 |
+
printf("edges: %d\n",m);
|
| 1442 |
+
printf("max degree: %d\n",d_max);
|
| 1443 |
+
fin.close();
|
| 1444 |
+
if ((int)(set<PAIR>(edges,edges+m).size())!=m) {
|
| 1445 |
+
cerr << "Input file contains duplicate undirected edges." << endl;
|
| 1446 |
+
return 0;
|
| 1447 |
+
}
|
| 1448 |
+
// set up adjacency matrix if it's smaller than 100MB
|
| 1449 |
+
if ((int64)n*n < 100LL*1024*1024*8) {
|
| 1450 |
+
adjacent = adjacent_matrix;
|
| 1451 |
+
adj_matrix = (int*)calloc((n*n)/adj_chunk+1,sizeof(int));
|
| 1452 |
+
for (int i=0;i<m;i++) {
|
| 1453 |
+
int a=edges[i].a, b=edges[i].b;
|
| 1454 |
+
adj_matrix[(a*n+b)/adj_chunk]|=(1<<((a*n+b)%adj_chunk));
|
| 1455 |
+
adj_matrix[(b*n+a)/adj_chunk]|=(1<<((b*n+a)%adj_chunk));
|
| 1456 |
+
}
|
| 1457 |
+
} else {
|
| 1458 |
+
adjacent = adjacent_list;
|
| 1459 |
+
}
|
| 1460 |
+
// set up adjacency, incidence lists
|
| 1461 |
+
adj = (int**)malloc(n*sizeof(int*));
|
| 1462 |
+
for (int i=0;i<n;i++) adj[i] = (int*)malloc(deg[i]*sizeof(int));
|
| 1463 |
+
inc = (PII**)malloc(n*sizeof(PII*));
|
| 1464 |
+
for (int i=0;i<n;i++) inc[i] = (PII*)malloc(deg[i]*sizeof(PII));
|
| 1465 |
+
int *d = (int*)calloc(n,sizeof(int));
|
| 1466 |
+
for (int i=0;i<m;i++) {
|
| 1467 |
+
int a=edges[i].a, b=edges[i].b;
|
| 1468 |
+
adj[a][d[a]]=b; adj[b][d[b]]=a;
|
| 1469 |
+
inc[a][d[a]]=PII(b,i); inc[b][d[b]]=PII(a,i);
|
| 1470 |
+
d[a]++; d[b]++;
|
| 1471 |
+
}
|
| 1472 |
+
for (int i=0;i<n;i++) {
|
| 1473 |
+
sort(adj[i],adj[i]+deg[i]);
|
| 1474 |
+
sort(inc[i],inc[i]+deg[i]);
|
| 1475 |
+
}
|
| 1476 |
+
// initialize orbit counts
|
| 1477 |
+
orbit = (int64**)malloc(n*sizeof(int64*));
|
| 1478 |
+
for (int i=0;i<n;i++) orbit[i] = (int64*)calloc(73,sizeof(int64));
|
| 1479 |
+
// initialize edge orbit counts
|
| 1480 |
+
eorbit = (int64**)malloc(m*sizeof(int64*));
|
| 1481 |
+
for (int i=0;i<m;i++) eorbit[i] = (int64*)calloc(68,sizeof(int64));
|
| 1482 |
+
|
| 1483 |
+
if (strcmp(orbit_type,"node") == 0) {
|
| 1484 |
+
printf("Counting NODE orbits of graphlets on %d nodes.\n\n",graphlet_size);
|
| 1485 |
+
if (graphlet_size==4) count4();
|
| 1486 |
+
if (graphlet_size==5) count5();
|
| 1487 |
+
if (strcmp(output_filename, "std") == 0) {
|
| 1488 |
+
cout << "orbit counts: \n" << writeResultsString(graphlet_size) << endl;
|
| 1489 |
+
} else {
|
| 1490 |
+
out_str = writeResults(graphlet_size, output_filename);
|
| 1491 |
+
}
|
| 1492 |
+
} else {
|
| 1493 |
+
printf("Counting EDGE orbits of graphlets on %d nodes.\n\n",graphlet_size);
|
| 1494 |
+
if (graphlet_size==4) ecount4();
|
| 1495 |
+
if (graphlet_size==5) ecount5();
|
| 1496 |
+
if (strcmp(output_filename, "std") == 0) {
|
| 1497 |
+
cout << "orbit counts: \n" << writeEdgeResultsString(graphlet_size) << endl;
|
| 1498 |
+
} else {
|
| 1499 |
+
out_str = writeEdgeResults(graphlet_size, output_filename);
|
| 1500 |
+
}
|
| 1501 |
+
}
|
| 1502 |
+
|
| 1503 |
+
return 1;
|
| 1504 |
+
}
|
| 1505 |
+
|
| 1506 |
+
int init(int argc, char *argv[]) {
|
| 1507 |
+
if (argc!=5) {
|
| 1508 |
+
cerr << "Incorrect number of arguments." << endl;
|
| 1509 |
+
cerr << "Usage: orca.exe [orbit type: node|edge] [graphlet size: 4/5] [graph - input file] [graphlets - output file]" << endl;
|
| 1510 |
+
return 0;
|
| 1511 |
+
}
|
| 1512 |
+
int graphlet_size;
|
| 1513 |
+
sscanf(argv[2],"%d", &graphlet_size);
|
| 1514 |
+
string out;
|
| 1515 |
+
motif_counts(argv[1], graphlet_size, argv[3], argv[4], out);
|
| 1516 |
+
|
| 1517 |
+
return 1;
|
| 1518 |
+
}
|
| 1519 |
+
|
| 1520 |
+
|
| 1521 |
+
int main(int argc, char *argv[]) {
|
| 1522 |
+
|
| 1523 |
+
|
| 1524 |
+
if (!init(argc, argv)) {
|
| 1525 |
+
// cerr << "Stopping!" << endl;
|
| 1526 |
+
return 1;
|
| 1527 |
+
}
|
| 1528 |
+
|
| 1529 |
+
|
| 1530 |
+
return 0;
|
| 1531 |
+
}
|
| 1532 |
+
|
analysis/orca/orca.h
ADDED
|
@@ -0,0 +1,1488 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <cstdio>
|
| 2 |
+
#include <cstdlib>
|
| 3 |
+
#include <cstring>
|
| 4 |
+
#include <cassert>
|
| 5 |
+
#include <ctime>
|
| 6 |
+
#include <iostream>
|
| 7 |
+
#include <fstream>
|
| 8 |
+
#include <set>
|
| 9 |
+
#include <unordered_map>
|
| 10 |
+
#include <algorithm>
|
| 11 |
+
|
| 12 |
+
#include <Python.h>
|
| 13 |
+
using namespace std;
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
typedef long long int64;
|
| 17 |
+
typedef pair<int,int> PII;
|
| 18 |
+
typedef struct { int first, second, third; } TIII;
|
| 19 |
+
|
| 20 |
+
struct PAIR {
|
| 21 |
+
int a, b;
|
| 22 |
+
PAIR(int a0, int b0) { a=min(a0,b0); b=max(a0,b0); }
|
| 23 |
+
};
|
| 24 |
+
bool operator<(const PAIR &x, const PAIR &y) {
|
| 25 |
+
if (x.a==y.a) return x.b<y.b;
|
| 26 |
+
else return x.a<y.a;
|
| 27 |
+
}
|
| 28 |
+
bool operator==(const PAIR &x, const PAIR &y) {
|
| 29 |
+
return x.a==y.a && x.b==y.b;
|
| 30 |
+
}
|
| 31 |
+
struct hash_PAIR {
|
| 32 |
+
size_t operator()(const PAIR &x) const {
|
| 33 |
+
return (x.a<<8) ^ (x.b<<0);
|
| 34 |
+
}
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
struct TRIPLE {
|
| 38 |
+
int a, b, c;
|
| 39 |
+
TRIPLE(int a0, int b0, int c0) {
|
| 40 |
+
a=a0; b=b0; c=c0;
|
| 41 |
+
if (a>b) swap(a,b);
|
| 42 |
+
if (b>c) swap(b,c);
|
| 43 |
+
if (a>b) swap(a,b);
|
| 44 |
+
}
|
| 45 |
+
};
|
| 46 |
+
bool operator<(const TRIPLE &x, const TRIPLE &y) {
|
| 47 |
+
if (x.a==y.a) {
|
| 48 |
+
if (x.b==y.b) return x.c<y.c;
|
| 49 |
+
else return x.b<y.b;
|
| 50 |
+
} else return x.a<y.a;
|
| 51 |
+
}
|
| 52 |
+
bool operator==(const TRIPLE &x, const TRIPLE &y) {
|
| 53 |
+
return x.a==y.a && x.b==y.b && x.c==y.c;
|
| 54 |
+
}
|
| 55 |
+
struct hash_TRIPLE {
|
| 56 |
+
size_t operator()(const TRIPLE &x) const {
|
| 57 |
+
return (x.a<<16) ^ (x.b<<8) ^ (x.c<<0);
|
| 58 |
+
}
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
unordered_map<PAIR, int, hash_PAIR> common2;
|
| 62 |
+
unordered_map<TRIPLE, int, hash_TRIPLE> common3;
|
| 63 |
+
unordered_map<PAIR, int, hash_PAIR>::iterator common2_it;
|
| 64 |
+
unordered_map<TRIPLE, int, hash_TRIPLE>::iterator common3_it;
|
| 65 |
+
|
| 66 |
+
#define common3_get(x) (((common3_it=common3.find(x))!=common3.end())?(common3_it->second):0)
|
| 67 |
+
#define common2_get(x) (((common2_it=common2.find(x))!=common2.end())?(common2_it->second):0)
|
| 68 |
+
|
| 69 |
+
int n,m; // n = number of nodes, m = number of edges
|
| 70 |
+
int *deg; // degrees of individual nodes
|
| 71 |
+
PAIR *edges; // list of edges
|
| 72 |
+
|
| 73 |
+
int **adj; // adj[x] - adjacency list of node x
|
| 74 |
+
PII **inc; // inc[x] - incidence list of node x: (y, edge id)
|
| 75 |
+
bool adjacent_list(int x, int y) { return binary_search(adj[x],adj[x]+deg[x],y); }
|
| 76 |
+
int *adj_matrix; // compressed adjacency matrix
|
| 77 |
+
const int adj_chunk = 8*sizeof(int);
|
| 78 |
+
bool adjacent_matrix(int x, int y) { return adj_matrix[(x*n+y)/adj_chunk]&(1<<((x*n+y)%adj_chunk)); }
|
| 79 |
+
bool (*adjacent)(int,int);
|
| 80 |
+
int getEdgeId(int x, int y) { return inc[x][lower_bound(adj[x],adj[x]+deg[x],y)-adj[x]].second; }
|
| 81 |
+
|
| 82 |
+
int64 **orbit; // orbit[x][o] - how many times does node x participate in orbit o
|
| 83 |
+
int64 **eorbit; // eorbit[x][o] - how many times does node x participate in edge orbit o
|
| 84 |
+
|
| 85 |
+
/** count graphlets on max 4 nodes */
|
| 86 |
+
void count4() {
|
| 87 |
+
clock_t startTime, endTime;
|
| 88 |
+
startTime = clock();
|
| 89 |
+
clock_t startTime_all, endTime_all;
|
| 90 |
+
startTime_all = startTime;
|
| 91 |
+
int frac,frac_prev;
|
| 92 |
+
|
| 93 |
+
// precompute triangles that span over edges
|
| 94 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 95 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 96 |
+
frac_prev=-1;
|
| 97 |
+
for (int i=0;i<m;i++) {
|
| 98 |
+
frac = 100LL*i/m;
|
| 99 |
+
if (frac!=frac_prev) {
|
| 100 |
+
printf("%d%%\r",frac);
|
| 101 |
+
frac_prev=frac;
|
| 102 |
+
}
|
| 103 |
+
int x=edges[i].a, y=edges[i].b;
|
| 104 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 105 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 106 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 107 |
+
else { yi++; }
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
endTime = clock();
|
| 111 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 112 |
+
startTime = endTime;
|
| 113 |
+
|
| 114 |
+
// count full graphlets
|
| 115 |
+
printf("stage 2 - counting full graphlets\n");
|
| 116 |
+
int64 *C4 = (int64*)calloc(n,sizeof(int64));
|
| 117 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn;
|
| 118 |
+
frac_prev=-1;
|
| 119 |
+
for (int x=0;x<n;x++) {
|
| 120 |
+
frac = 100LL*x/n;
|
| 121 |
+
if (frac!=frac_prev) {
|
| 122 |
+
printf("%d%%\r",frac);
|
| 123 |
+
frac_prev=frac;
|
| 124 |
+
}
|
| 125 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 126 |
+
int y=adj[x][nx];
|
| 127 |
+
if (y >= x) break;
|
| 128 |
+
nn=0;
|
| 129 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 130 |
+
int z=adj[y][ny];
|
| 131 |
+
if (z >= y) break;
|
| 132 |
+
if (adjacent(x,z)==0) continue;
|
| 133 |
+
neigh[nn++]=z;
|
| 134 |
+
}
|
| 135 |
+
for (int i=0;i<nn;i++) {
|
| 136 |
+
int z = neigh[i];
|
| 137 |
+
for (int j=i+1;j<nn;j++) {
|
| 138 |
+
int zz = neigh[j];
|
| 139 |
+
if (adjacent(z,zz)) {
|
| 140 |
+
C4[x]++; C4[y]++; C4[z]++; C4[zz]++;
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
endTime = clock();
|
| 147 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 148 |
+
startTime = endTime;
|
| 149 |
+
|
| 150 |
+
// set up a system of equations relating orbits for every node
|
| 151 |
+
printf("stage 3 - building systems of equations\n");
|
| 152 |
+
int *common = (int*)calloc(n,sizeof(int));
|
| 153 |
+
int *common_list = (int*)malloc(n*sizeof(int)), nc=0;
|
| 154 |
+
frac_prev=-1;
|
| 155 |
+
for (int x=0;x<n;x++) {
|
| 156 |
+
frac = 100LL*x/n;
|
| 157 |
+
if (frac!=frac_prev) {
|
| 158 |
+
printf("%d%%\r",frac);
|
| 159 |
+
frac_prev=frac;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
int64 f_12_14=0, f_10_13=0;
|
| 163 |
+
int64 f_13_14=0, f_11_13=0;
|
| 164 |
+
int64 f_7_11=0, f_5_8=0;
|
| 165 |
+
int64 f_6_9=0, f_9_12=0, f_4_8=0, f_8_12=0;
|
| 166 |
+
int64 f_14=C4[x];
|
| 167 |
+
|
| 168 |
+
for (int i=0;i<nc;i++) common[common_list[i]]=0;
|
| 169 |
+
nc=0;
|
| 170 |
+
|
| 171 |
+
orbit[x][0]=deg[x];
|
| 172 |
+
// x - middle node
|
| 173 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 174 |
+
int y=inc[x][nx1].first, ey=inc[x][nx1].second;
|
| 175 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 176 |
+
int z=inc[y][ny].first, ez=inc[y][ny].second;
|
| 177 |
+
if (adjacent(x,z)) { // triangle
|
| 178 |
+
if (z<y) {
|
| 179 |
+
f_12_14 += tri[ez]-1;
|
| 180 |
+
f_10_13 += (deg[y]-1-tri[ez])+(deg[z]-1-tri[ez]);
|
| 181 |
+
}
|
| 182 |
+
} else {
|
| 183 |
+
if (common[z]==0) common_list[nc++]=z;
|
| 184 |
+
common[z]++;
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 188 |
+
int z=inc[x][nx2].first, ez=inc[x][nx2].second;
|
| 189 |
+
if (adjacent(y,z)) { // triangle
|
| 190 |
+
orbit[x][3]++;
|
| 191 |
+
f_13_14 += (tri[ey]-1)+(tri[ez]-1);
|
| 192 |
+
f_11_13 += (deg[x]-1-tri[ey])+(deg[x]-1-tri[ez]);
|
| 193 |
+
} else { // path
|
| 194 |
+
orbit[x][2]++;
|
| 195 |
+
f_7_11 += (deg[x]-1-tri[ey]-1)+(deg[x]-1-tri[ez]-1);
|
| 196 |
+
f_5_8 += (deg[y]-1-tri[ey])+(deg[z]-1-tri[ez]);
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
}
|
| 200 |
+
// x - side node
|
| 201 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 202 |
+
int y=inc[x][nx1].first, ey=inc[x][nx1].second;
|
| 203 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 204 |
+
int z=inc[y][ny].first, ez=inc[y][ny].second;
|
| 205 |
+
if (x==z) continue;
|
| 206 |
+
if (!adjacent(x,z)) { // path
|
| 207 |
+
orbit[x][1]++;
|
| 208 |
+
f_6_9 += (deg[y]-1-tri[ey]-1);
|
| 209 |
+
f_9_12 += tri[ez];
|
| 210 |
+
f_4_8 += (deg[z]-1-tri[ez]);
|
| 211 |
+
f_8_12 += (common[z]-1);
|
| 212 |
+
}
|
| 213 |
+
}
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
// solve system of equations
|
| 217 |
+
orbit[x][14]=(f_14);
|
| 218 |
+
orbit[x][13]=(f_13_14-6*f_14)/2;
|
| 219 |
+
orbit[x][12]=(f_12_14-3*f_14);
|
| 220 |
+
orbit[x][11]=(f_11_13-f_13_14+6*f_14)/2;
|
| 221 |
+
orbit[x][10]=(f_10_13-f_13_14+6*f_14);
|
| 222 |
+
orbit[x][9]=(f_9_12-2*f_12_14+6*f_14)/2;
|
| 223 |
+
orbit[x][8]=(f_8_12-2*f_12_14+6*f_14)/2;
|
| 224 |
+
orbit[x][7]=(f_13_14+f_7_11-f_11_13-6*f_14)/6;
|
| 225 |
+
orbit[x][6]=(2*f_12_14+f_6_9-f_9_12-6*f_14)/2;
|
| 226 |
+
orbit[x][5]=(2*f_12_14+f_5_8-f_8_12-6*f_14);
|
| 227 |
+
orbit[x][4]=(2*f_12_14+f_4_8-f_8_12-6*f_14);
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
endTime = clock();
|
| 231 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 232 |
+
|
| 233 |
+
endTime_all = endTime;
|
| 234 |
+
printf("total: %.2f\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
/** count edge orbits of graphlets on max 4 nodes */
|
| 239 |
+
void ecount4() {
|
| 240 |
+
clock_t startTime, endTime;
|
| 241 |
+
startTime = clock();
|
| 242 |
+
clock_t startTime_all, endTime_all;
|
| 243 |
+
startTime_all = startTime;
|
| 244 |
+
int frac,frac_prev;
|
| 245 |
+
|
| 246 |
+
// precompute triangles that span over edges
|
| 247 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 248 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 249 |
+
frac_prev=-1;
|
| 250 |
+
for (int i=0;i<m;i++) {
|
| 251 |
+
frac = 100LL*i/m;
|
| 252 |
+
if (frac!=frac_prev) {
|
| 253 |
+
printf("%d%%\r",frac);
|
| 254 |
+
frac_prev=frac;
|
| 255 |
+
}
|
| 256 |
+
int x=edges[i].a, y=edges[i].b;
|
| 257 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 258 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 259 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 260 |
+
else { yi++; }
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
endTime = clock();
|
| 264 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 265 |
+
startTime = endTime;
|
| 266 |
+
|
| 267 |
+
// count full graphlets
|
| 268 |
+
printf("stage 2 - counting full graphlets\n");
|
| 269 |
+
int64 *C4 = (int64*)calloc(m,sizeof(int64));
|
| 270 |
+
int *neighx = (int*)malloc(n*sizeof(int)); // lookup table - edges to neighbors of x
|
| 271 |
+
memset(neighx,-1,n*sizeof(int));
|
| 272 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn; // lookup table - common neighbors of x and y
|
| 273 |
+
PII *neigh_edges = (PII*)malloc(n*sizeof(PII)); // list of common neighbors of x and y
|
| 274 |
+
frac_prev=-1;
|
| 275 |
+
for (int x=0;x<n;x++) {
|
| 276 |
+
frac = 100LL*x/n;
|
| 277 |
+
if (frac!=frac_prev) {
|
| 278 |
+
printf("%d%%\r",frac);
|
| 279 |
+
frac_prev=frac;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 283 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 284 |
+
neighx[y]=xy;
|
| 285 |
+
}
|
| 286 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 287 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 288 |
+
if (y >= x) break;
|
| 289 |
+
nn=0;
|
| 290 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 291 |
+
int z=inc[y][ny].first, yz=inc[y][ny].second;
|
| 292 |
+
if (z >= y) break;
|
| 293 |
+
if (neighx[z]==-1) continue;
|
| 294 |
+
int xz=neighx[z];
|
| 295 |
+
neigh[nn]=z;
|
| 296 |
+
neigh_edges[nn]={xz, yz};
|
| 297 |
+
nn++;
|
| 298 |
+
}
|
| 299 |
+
for (int i=0;i<nn;i++) {
|
| 300 |
+
int z = neigh[i], xz = neigh_edges[i].first, yz = neigh_edges[i].second;
|
| 301 |
+
for (int j=i+1;j<nn;j++) {
|
| 302 |
+
int w = neigh[j], xw = neigh_edges[j].first, yw = neigh_edges[j].second;
|
| 303 |
+
if (adjacent(z,w)) {
|
| 304 |
+
C4[xy]++;
|
| 305 |
+
C4[xz]++; C4[yz]++;
|
| 306 |
+
C4[xw]++; C4[yw]++;
|
| 307 |
+
// another iteration to count this last(smallest) edge instead of calling getEdgeId
|
| 308 |
+
//int zw=getEdgeId(z,w); C4[zw]++;
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
}
|
| 312 |
+
}
|
| 313 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 314 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 315 |
+
neighx[y]=-1;
|
| 316 |
+
}
|
| 317 |
+
}
|
| 318 |
+
endTime = clock();
|
| 319 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 320 |
+
startTime = endTime;
|
| 321 |
+
|
| 322 |
+
// count full graphlets for the smallest edge
|
| 323 |
+
for (int x=0;x<n;x++) {
|
| 324 |
+
frac = 100LL*x/n;
|
| 325 |
+
if (frac!=frac_prev) {
|
| 326 |
+
printf("%d%%\r",frac);
|
| 327 |
+
frac_prev=frac;
|
| 328 |
+
}
|
| 329 |
+
for (int nx=deg[x]-1;nx>=0;nx--) {
|
| 330 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 331 |
+
if (y <= x) break;
|
| 332 |
+
nn=0;
|
| 333 |
+
for (int ny=deg[y]-1;ny>=0;ny--) {
|
| 334 |
+
int z=adj[y][ny];
|
| 335 |
+
if (z <= y) break;
|
| 336 |
+
if (adjacent(x,z)==0) continue;
|
| 337 |
+
neigh[nn++]=z;
|
| 338 |
+
}
|
| 339 |
+
for (int i=0;i<nn;i++) {
|
| 340 |
+
int z = neigh[i];
|
| 341 |
+
for (int j=i+1;j<nn;j++) {
|
| 342 |
+
int zz = neigh[j];
|
| 343 |
+
if (adjacent(z,zz)) {
|
| 344 |
+
C4[xy]++;
|
| 345 |
+
}
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
}
|
| 350 |
+
endTime = clock();
|
| 351 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 352 |
+
startTime = endTime;
|
| 353 |
+
|
| 354 |
+
// set up a system of equations relating orbits for every node
|
| 355 |
+
printf("stage 3 - building systems of equations\n");
|
| 356 |
+
int *common = (int*)calloc(n,sizeof(int));
|
| 357 |
+
int *common_list = (int*)malloc(n*sizeof(int)), nc=0;
|
| 358 |
+
frac_prev=-1;
|
| 359 |
+
|
| 360 |
+
for (int x=0;x<n;x++) {
|
| 361 |
+
frac = 100LL*x/n;
|
| 362 |
+
if (frac!=frac_prev) {
|
| 363 |
+
printf("%d%%\r",frac);
|
| 364 |
+
frac_prev=frac;
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
// common nodes of x and some other node
|
| 368 |
+
for (int i=0;i<nc;i++) common[common_list[i]]=0;
|
| 369 |
+
nc=0;
|
| 370 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 371 |
+
int y=adj[x][nx];
|
| 372 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 373 |
+
int z=adj[y][ny];
|
| 374 |
+
if (z==x) continue;
|
| 375 |
+
if (common[z]==0) common_list[nc++]=z;
|
| 376 |
+
common[z]++;
|
| 377 |
+
}
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 381 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 382 |
+
int e=xy;
|
| 383 |
+
for (int n1=0;n1<deg[x];n1++) {
|
| 384 |
+
int z=inc[x][n1].first, xz=inc[x][n1].second;
|
| 385 |
+
if (z==y) continue;
|
| 386 |
+
if (adjacent(y,z)) { // triangle
|
| 387 |
+
if (x<y) {
|
| 388 |
+
eorbit[e][1]++;
|
| 389 |
+
eorbit[e][10] += tri[xy]-1;
|
| 390 |
+
eorbit[e][7] += deg[z]-2;
|
| 391 |
+
}
|
| 392 |
+
eorbit[e][9] += tri[xz]-1;
|
| 393 |
+
eorbit[e][8] += deg[x]-2;
|
| 394 |
+
}
|
| 395 |
+
}
|
| 396 |
+
for (int n1=0;n1<deg[y];n1++) {
|
| 397 |
+
int z=inc[y][n1].first, yz=inc[y][n1].second;
|
| 398 |
+
if (z==x) continue;
|
| 399 |
+
if (!adjacent(x,z)) { // path x-y-z
|
| 400 |
+
eorbit[e][0]++;
|
| 401 |
+
eorbit[e][6] += tri[yz];
|
| 402 |
+
eorbit[e][5] += common[z]-1;
|
| 403 |
+
eorbit[e][4] += deg[y]-2;
|
| 404 |
+
eorbit[e][3] += deg[x]-1;
|
| 405 |
+
eorbit[e][2] += deg[z]-1;
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
}
|
| 410 |
+
// solve system of equations
|
| 411 |
+
for (int e=0;e<m;e++) {
|
| 412 |
+
eorbit[e][11]=C4[e];
|
| 413 |
+
eorbit[e][10]=(eorbit[e][10]-2*eorbit[e][11])/2;
|
| 414 |
+
eorbit[e][9]=(eorbit[e][9]-4*eorbit[e][11]);
|
| 415 |
+
eorbit[e][8]=(eorbit[e][8]-eorbit[e][9]-4*eorbit[e][10]-4*eorbit[e][11]);
|
| 416 |
+
eorbit[e][7]=(eorbit[e][7]-eorbit[e][9]-2*eorbit[e][11]);
|
| 417 |
+
eorbit[e][6]=(eorbit[e][6]-eorbit[e][9])/2;
|
| 418 |
+
eorbit[e][5]=(eorbit[e][5]-eorbit[e][9])/2;
|
| 419 |
+
eorbit[e][4]=(eorbit[e][4]-2*eorbit[e][6]-eorbit[e][8]-eorbit[e][9])/2;
|
| 420 |
+
eorbit[e][3]=(eorbit[e][3]-2*eorbit[e][5]-eorbit[e][8]-eorbit[e][9])/2;
|
| 421 |
+
eorbit[e][2]=(eorbit[e][2]-2*eorbit[e][5]-2*eorbit[e][6]-eorbit[e][9]);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
endTime = clock();
|
| 425 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 426 |
+
|
| 427 |
+
endTime_all = endTime;
|
| 428 |
+
printf("total: %.2f\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
|
| 432 |
+
/** count graphlets on max 5 nodes */
|
| 433 |
+
void count5() {
|
| 434 |
+
clock_t startTime, endTime;
|
| 435 |
+
startTime = clock();
|
| 436 |
+
clock_t startTime_all, endTime_all;
|
| 437 |
+
startTime_all = startTime;
|
| 438 |
+
int frac,frac_prev;
|
| 439 |
+
|
| 440 |
+
// precompute common nodes
|
| 441 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 442 |
+
frac_prev=-1;
|
| 443 |
+
for (int x=0;x<n;x++) {
|
| 444 |
+
frac = 100LL*x/n;
|
| 445 |
+
if (frac!=frac_prev) {
|
| 446 |
+
printf("%d%%\r",frac);
|
| 447 |
+
frac_prev=frac;
|
| 448 |
+
}
|
| 449 |
+
for (int n1=0;n1<deg[x];n1++) {
|
| 450 |
+
int a=adj[x][n1];
|
| 451 |
+
for (int n2=n1+1;n2<deg[x];n2++) {
|
| 452 |
+
int b=adj[x][n2];
|
| 453 |
+
PAIR ab=PAIR(a,b);
|
| 454 |
+
common2[ab]++;
|
| 455 |
+
for (int n3=n2+1;n3<deg[x];n3++) {
|
| 456 |
+
int c=adj[x][n3];
|
| 457 |
+
int st = adjacent(a,b)+adjacent(a,c)+adjacent(b,c);
|
| 458 |
+
if (st<2) continue;
|
| 459 |
+
TRIPLE abc=TRIPLE(a,b,c);
|
| 460 |
+
common3[abc]++;
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
}
|
| 464 |
+
}
|
| 465 |
+
// precompute triangles that span over edges
|
| 466 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 467 |
+
for (int i=0;i<m;i++) {
|
| 468 |
+
int x=edges[i].a, y=edges[i].b;
|
| 469 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 470 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 471 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 472 |
+
else { yi++; }
|
| 473 |
+
}
|
| 474 |
+
}
|
| 475 |
+
endTime = clock();
|
| 476 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 477 |
+
startTime = endTime;
|
| 478 |
+
|
| 479 |
+
// count full graphlets
|
| 480 |
+
printf("stage 2 - counting full graphlets\n");
|
| 481 |
+
int64 *C5 = (int64*)calloc(n,sizeof(int64));
|
| 482 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn;
|
| 483 |
+
int *neigh2 = (int*)malloc(n*sizeof(int)), nn2;
|
| 484 |
+
frac_prev=-1;
|
| 485 |
+
for (int x=0;x<n;x++) {
|
| 486 |
+
frac = 100LL*x/n;
|
| 487 |
+
if (frac!=frac_prev) {
|
| 488 |
+
printf("%d%%\r",frac);
|
| 489 |
+
frac_prev=frac;
|
| 490 |
+
}
|
| 491 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 492 |
+
int y=adj[x][nx];
|
| 493 |
+
if (y >= x) break;
|
| 494 |
+
nn=0;
|
| 495 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 496 |
+
int z=adj[y][ny];
|
| 497 |
+
if (z >= y) break;
|
| 498 |
+
if (adjacent(x,z)) {
|
| 499 |
+
neigh[nn++]=z;
|
| 500 |
+
}
|
| 501 |
+
}
|
| 502 |
+
for (int i=0;i<nn;i++) {
|
| 503 |
+
int z = neigh[i];
|
| 504 |
+
nn2=0;
|
| 505 |
+
for (int j=i+1;j<nn;j++) {
|
| 506 |
+
int zz = neigh[j];
|
| 507 |
+
if (adjacent(z,zz)) {
|
| 508 |
+
neigh2[nn2++]=zz;
|
| 509 |
+
}
|
| 510 |
+
}
|
| 511 |
+
for (int i2=0;i2<nn2;i2++) {
|
| 512 |
+
int zz = neigh2[i2];
|
| 513 |
+
for (int j2=i2+1;j2<nn2;j2++) {
|
| 514 |
+
int zzz = neigh2[j2];
|
| 515 |
+
if (adjacent(zz,zzz)) {
|
| 516 |
+
C5[x]++; C5[y]++; C5[z]++; C5[zz]++; C5[zzz]++;
|
| 517 |
+
}
|
| 518 |
+
}
|
| 519 |
+
}
|
| 520 |
+
}
|
| 521 |
+
}
|
| 522 |
+
}
|
| 523 |
+
endTime = clock();
|
| 524 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 525 |
+
startTime = endTime;
|
| 526 |
+
|
| 527 |
+
int *common_x = (int*)calloc(n,sizeof(int));
|
| 528 |
+
int *common_x_list = (int*)malloc(n*sizeof(int)), ncx=0;
|
| 529 |
+
int *common_a = (int*)calloc(n,sizeof(int));
|
| 530 |
+
int *common_a_list = (int*)malloc(n*sizeof(int)), nca=0;
|
| 531 |
+
|
| 532 |
+
// set up a system of equations relating orbit counts
|
| 533 |
+
printf("stage 3 - building systems of equations\n");
|
| 534 |
+
frac_prev=-1;
|
| 535 |
+
for (int x=0;x<n;x++) {
|
| 536 |
+
frac = 100LL*x/n;
|
| 537 |
+
if (frac!=frac_prev) {
|
| 538 |
+
printf("%d%%\r",frac);
|
| 539 |
+
frac_prev=frac;
|
| 540 |
+
}
|
| 541 |
+
|
| 542 |
+
for (int i=0;i<ncx;i++) common_x[common_x_list[i]]=0;
|
| 543 |
+
ncx=0;
|
| 544 |
+
|
| 545 |
+
// smaller graphlets
|
| 546 |
+
orbit[x][0] = deg[x];
|
| 547 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 548 |
+
int a=adj[x][nx1];
|
| 549 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 550 |
+
int b=adj[x][nx2];
|
| 551 |
+
if (adjacent(a,b)) orbit[x][3]++;
|
| 552 |
+
else orbit[x][2]++;
|
| 553 |
+
}
|
| 554 |
+
for (int na=0;na<deg[a];na++) {
|
| 555 |
+
int b=adj[a][na];
|
| 556 |
+
if (b!=x && !adjacent(x,b)) {
|
| 557 |
+
orbit[x][1]++;
|
| 558 |
+
if (common_x[b]==0) common_x_list[ncx++]=b;
|
| 559 |
+
common_x[b]++;
|
| 560 |
+
}
|
| 561 |
+
}
|
| 562 |
+
}
|
| 563 |
+
|
| 564 |
+
int64 f_71=0, f_70=0, f_67=0, f_66=0, f_58=0, f_57=0; // 14
|
| 565 |
+
int64 f_69=0, f_68=0, f_64=0, f_61=0, f_60=0, f_55=0, f_48=0, f_42=0, f_41=0; // 13
|
| 566 |
+
int64 f_65=0, f_63=0, f_59=0, f_54=0, f_47=0, f_46=0, f_40=0; // 12
|
| 567 |
+
int64 f_62=0, f_53=0, f_51=0, f_50=0, f_49=0, f_38=0, f_37=0, f_36=0; // 8
|
| 568 |
+
int64 f_44=0, f_33=0, f_30=0, f_26=0; // 11
|
| 569 |
+
int64 f_52=0, f_43=0, f_32=0, f_29=0, f_25=0; // 10
|
| 570 |
+
int64 f_56=0, f_45=0, f_39=0, f_31=0, f_28=0, f_24=0; // 9
|
| 571 |
+
int64 f_35=0, f_34=0, f_27=0, f_18=0, f_16=0, f_15=0; // 4
|
| 572 |
+
int64 f_17=0; // 5
|
| 573 |
+
int64 f_22=0, f_20=0, f_19=0; // 6
|
| 574 |
+
int64 f_23=0, f_21=0; // 7
|
| 575 |
+
|
| 576 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 577 |
+
int a=inc[x][nx1].first, xa=inc[x][nx1].second;
|
| 578 |
+
|
| 579 |
+
for (int i=0;i<nca;i++) common_a[common_a_list[i]]=0;
|
| 580 |
+
nca=0;
|
| 581 |
+
for (int na=0;na<deg[a];na++) {
|
| 582 |
+
int b=adj[a][na];
|
| 583 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 584 |
+
int c=adj[b][nb];
|
| 585 |
+
if (c==a || adjacent(a,c)) continue;
|
| 586 |
+
if (common_a[c]==0) common_a_list[nca++]=c;
|
| 587 |
+
common_a[c]++;
|
| 588 |
+
}
|
| 589 |
+
}
|
| 590 |
+
|
| 591 |
+
// x = orbit-14 (tetrahedron)
|
| 592 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 593 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 594 |
+
if (!adjacent(a,b)) continue;
|
| 595 |
+
for (int nx3=nx2+1;nx3<deg[x];nx3++) {
|
| 596 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 597 |
+
if (!adjacent(a,c) || !adjacent(b,c)) continue;
|
| 598 |
+
orbit[x][14]++;
|
| 599 |
+
f_70 += common3_get(TRIPLE(a,b,c))-1;
|
| 600 |
+
f_71 += (tri[xa]>2 && tri[xb]>2)?(common3_get(TRIPLE(x,a,b))-1):0;
|
| 601 |
+
f_71 += (tri[xa]>2 && tri[xc]>2)?(common3_get(TRIPLE(x,a,c))-1):0;
|
| 602 |
+
f_71 += (tri[xb]>2 && tri[xc]>2)?(common3_get(TRIPLE(x,b,c))-1):0;
|
| 603 |
+
f_67 += tri[xa]-2+tri[xb]-2+tri[xc]-2;
|
| 604 |
+
f_66 += common2_get(PAIR(a,b))-2;
|
| 605 |
+
f_66 += common2_get(PAIR(a,c))-2;
|
| 606 |
+
f_66 += common2_get(PAIR(b,c))-2;
|
| 607 |
+
f_58 += deg[x]-3;
|
| 608 |
+
f_57 += deg[a]-3+deg[b]-3+deg[c]-3;
|
| 609 |
+
}
|
| 610 |
+
}
|
| 611 |
+
|
| 612 |
+
// x = orbit-13 (diamond)
|
| 613 |
+
for (int nx2=0;nx2<deg[x];nx2++) {
|
| 614 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 615 |
+
if (!adjacent(a,b)) continue;
|
| 616 |
+
for (int nx3=nx2+1;nx3<deg[x];nx3++) {
|
| 617 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 618 |
+
if (!adjacent(a,c) || adjacent(b,c)) continue;
|
| 619 |
+
orbit[x][13]++;
|
| 620 |
+
f_69 += (tri[xb]>1 && tri[xc]>1)?(common3_get(TRIPLE(x,b,c))-1):0;
|
| 621 |
+
f_68 += common3_get(TRIPLE(a,b,c))-1;
|
| 622 |
+
f_64 += common2_get(PAIR(b,c))-2;
|
| 623 |
+
f_61 += tri[xb]-1+tri[xc]-1;
|
| 624 |
+
f_60 += common2_get(PAIR(a,b))-1;
|
| 625 |
+
f_60 += common2_get(PAIR(a,c))-1;
|
| 626 |
+
f_55 += tri[xa]-2;
|
| 627 |
+
f_48 += deg[b]-2+deg[c]-2;
|
| 628 |
+
f_42 += deg[x]-3;
|
| 629 |
+
f_41 += deg[a]-3;
|
| 630 |
+
}
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
// x = orbit-12 (diamond)
|
| 634 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 635 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 636 |
+
if (!adjacent(a,b)) continue;
|
| 637 |
+
for (int na=0;na<deg[a];na++) {
|
| 638 |
+
int c=inc[a][na].first, ac=inc[a][na].second;
|
| 639 |
+
if (c==x || adjacent(x,c) || !adjacent(b,c)) continue;
|
| 640 |
+
orbit[x][12]++;
|
| 641 |
+
f_65 += (tri[ac]>1)?common3_get(TRIPLE(a,b,c)):0;
|
| 642 |
+
f_63 += common_x[c]-2;
|
| 643 |
+
f_59 += tri[ac]-1+common2_get(PAIR(b,c))-1;
|
| 644 |
+
f_54 += common2_get(PAIR(a,b))-2;
|
| 645 |
+
f_47 += deg[x]-2;
|
| 646 |
+
f_46 += deg[c]-2;
|
| 647 |
+
f_40 += deg[a]-3+deg[b]-3;
|
| 648 |
+
}
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
+
// x = orbit-8 (cycle)
|
| 652 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 653 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 654 |
+
if (adjacent(a,b)) continue;
|
| 655 |
+
for (int na=0;na<deg[a];na++) {
|
| 656 |
+
int c=inc[a][na].first, ac=inc[a][na].second;
|
| 657 |
+
if (c==x || adjacent(x,c) || !adjacent(b,c)) continue;
|
| 658 |
+
orbit[x][8]++;
|
| 659 |
+
f_62 += (tri[ac]>0)?common3_get(TRIPLE(a,b,c)):0;
|
| 660 |
+
f_53 += tri[xa]+tri[xb];
|
| 661 |
+
f_51 += tri[ac]+common2_get(PAIR(c,b));
|
| 662 |
+
f_50 += common_x[c]-2;
|
| 663 |
+
f_49 += common_a[b]-2;
|
| 664 |
+
f_38 += deg[x]-2;
|
| 665 |
+
f_37 += deg[a]-2+deg[b]-2;
|
| 666 |
+
f_36 += deg[c]-2;
|
| 667 |
+
}
|
| 668 |
+
}
|
| 669 |
+
|
| 670 |
+
// x = orbit-11 (paw)
|
| 671 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 672 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 673 |
+
if (!adjacent(a,b)) continue;
|
| 674 |
+
for (int nx3=0;nx3<deg[x];nx3++) {
|
| 675 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 676 |
+
if (c==a || c==b || adjacent(a,c) || adjacent(b,c)) continue;
|
| 677 |
+
orbit[x][11]++;
|
| 678 |
+
f_44 += tri[xc];
|
| 679 |
+
f_33 += deg[x]-3;
|
| 680 |
+
f_30 += deg[c]-1;
|
| 681 |
+
f_26 += deg[a]-2+deg[b]-2;
|
| 682 |
+
}
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
// x = orbit-10 (paw)
|
| 686 |
+
for (int nx2=0;nx2<deg[x];nx2++) {
|
| 687 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 688 |
+
if (!adjacent(a,b)) continue;
|
| 689 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 690 |
+
int c=inc[b][nb].first, bc=inc[b][nb].second;
|
| 691 |
+
if (c==x || c==a || adjacent(a,c) || adjacent(x,c)) continue;
|
| 692 |
+
orbit[x][10]++;
|
| 693 |
+
f_52 += common_a[c]-1;
|
| 694 |
+
f_43 += tri[bc];
|
| 695 |
+
f_32 += deg[b]-3;
|
| 696 |
+
f_29 += deg[c]-1;
|
| 697 |
+
f_25 += deg[a]-2;
|
| 698 |
+
}
|
| 699 |
+
}
|
| 700 |
+
|
| 701 |
+
// x = orbit-9 (paw)
|
| 702 |
+
for (int na1=0;na1<deg[a];na1++) {
|
| 703 |
+
int b=inc[a][na1].first, ab=inc[a][na1].second;
|
| 704 |
+
if (b==x || adjacent(x,b)) continue;
|
| 705 |
+
for (int na2=na1+1;na2<deg[a];na2++) {
|
| 706 |
+
int c=inc[a][na2].first, ac=inc[a][na2].second;
|
| 707 |
+
if (c==x || !adjacent(b,c) || adjacent(x,c)) continue;
|
| 708 |
+
orbit[x][9]++;
|
| 709 |
+
f_56 += (tri[ab]>1 && tri[ac]>1)?common3_get(TRIPLE(a,b,c)):0;
|
| 710 |
+
f_45 += common2_get(PAIR(b,c))-1;
|
| 711 |
+
f_39 += tri[ab]-1+tri[ac]-1;
|
| 712 |
+
f_31 += deg[a]-3;
|
| 713 |
+
f_28 += deg[x]-1;
|
| 714 |
+
f_24 += deg[b]-2+deg[c]-2;
|
| 715 |
+
}
|
| 716 |
+
}
|
| 717 |
+
|
| 718 |
+
// x = orbit-4 (path)
|
| 719 |
+
for (int na=0;na<deg[a];na++) {
|
| 720 |
+
int b=inc[a][na].first, ab=inc[a][na].second;
|
| 721 |
+
if (b==x || adjacent(x,b)) continue;
|
| 722 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 723 |
+
int c=inc[b][nb].first, bc=inc[b][nb].second;
|
| 724 |
+
if (c==a || adjacent(a,c) || adjacent(x,c)) continue;
|
| 725 |
+
orbit[x][4]++;
|
| 726 |
+
f_35 += common_a[c]-1;
|
| 727 |
+
f_34 += common_x[c];
|
| 728 |
+
f_27 += tri[bc];
|
| 729 |
+
f_18 += deg[b]-2;
|
| 730 |
+
f_16 += deg[x]-1;
|
| 731 |
+
f_15 += deg[c]-1;
|
| 732 |
+
}
|
| 733 |
+
}
|
| 734 |
+
|
| 735 |
+
// x = orbit-5 (path)
|
| 736 |
+
for (int nx2=0;nx2<deg[x];nx2++) {
|
| 737 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 738 |
+
if (b==a || adjacent(a,b)) continue;
|
| 739 |
+
for (int nb=0;nb<deg[b];nb++) {
|
| 740 |
+
int c=inc[b][nb].first, bc=inc[b][nb].second;
|
| 741 |
+
if (c==x || adjacent(a,c) || adjacent(x,c)) continue;
|
| 742 |
+
orbit[x][5]++;
|
| 743 |
+
f_17 += deg[a]-1;
|
| 744 |
+
}
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
// x = orbit-6 (claw)
|
| 748 |
+
for (int na1=0;na1<deg[a];na1++) {
|
| 749 |
+
int b=inc[a][na1].first, ab=inc[a][na1].second;
|
| 750 |
+
if (b==x || adjacent(x,b)) continue;
|
| 751 |
+
for (int na2=na1+1;na2<deg[a];na2++) {
|
| 752 |
+
int c=inc[a][na2].first, ac=inc[a][na2].second;
|
| 753 |
+
if (c==x || adjacent(x,c) || adjacent(b,c)) continue;
|
| 754 |
+
orbit[x][6]++;
|
| 755 |
+
f_22 += deg[a]-3;
|
| 756 |
+
f_20 += deg[x]-1;
|
| 757 |
+
f_19 += deg[b]-1+deg[c]-1;
|
| 758 |
+
}
|
| 759 |
+
}
|
| 760 |
+
|
| 761 |
+
// x = orbit-7 (claw)
|
| 762 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 763 |
+
int b=inc[x][nx2].first, xb=inc[x][nx2].second;
|
| 764 |
+
if (adjacent(a,b)) continue;
|
| 765 |
+
for (int nx3=nx2+1;nx3<deg[x];nx3++) {
|
| 766 |
+
int c=inc[x][nx3].first, xc=inc[x][nx3].second;
|
| 767 |
+
if (adjacent(a,c) || adjacent(b,c)) continue;
|
| 768 |
+
orbit[x][7]++;
|
| 769 |
+
f_23 += deg[x]-3;
|
| 770 |
+
f_21 += deg[a]-1+deg[b]-1+deg[c]-1;
|
| 771 |
+
}
|
| 772 |
+
}
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
// solve equations
|
| 776 |
+
orbit[x][72] = C5[x];
|
| 777 |
+
orbit[x][71] = (f_71-12*orbit[x][72])/2;
|
| 778 |
+
orbit[x][70] = (f_70-4*orbit[x][72]);
|
| 779 |
+
orbit[x][69] = (f_69-2*orbit[x][71])/4;
|
| 780 |
+
orbit[x][68] = (f_68-2*orbit[x][71]);
|
| 781 |
+
orbit[x][67] = (f_67-12*orbit[x][72]-4*orbit[x][71]);
|
| 782 |
+
orbit[x][66] = (f_66-12*orbit[x][72]-2*orbit[x][71]-3*orbit[x][70]);
|
| 783 |
+
orbit[x][65] = (f_65-3*orbit[x][70])/2;
|
| 784 |
+
orbit[x][64] = (f_64-2*orbit[x][71]-4*orbit[x][69]-1*orbit[x][68]);
|
| 785 |
+
orbit[x][63] = (f_63-3*orbit[x][70]-2*orbit[x][68]);
|
| 786 |
+
orbit[x][62] = (f_62-1*orbit[x][68])/2;
|
| 787 |
+
orbit[x][61] = (f_61-4*orbit[x][71]-8*orbit[x][69]-2*orbit[x][67])/2;
|
| 788 |
+
orbit[x][60] = (f_60-4*orbit[x][71]-2*orbit[x][68]-2*orbit[x][67]);
|
| 789 |
+
orbit[x][59] = (f_59-6*orbit[x][70]-2*orbit[x][68]-4*orbit[x][65]);
|
| 790 |
+
orbit[x][58] = (f_58-4*orbit[x][72]-2*orbit[x][71]-1*orbit[x][67]);
|
| 791 |
+
orbit[x][57] = (f_57-12*orbit[x][72]-4*orbit[x][71]-3*orbit[x][70]-1*orbit[x][67]-2*orbit[x][66]);
|
| 792 |
+
orbit[x][56] = (f_56-2*orbit[x][65])/3;
|
| 793 |
+
orbit[x][55] = (f_55-2*orbit[x][71]-2*orbit[x][67])/3;
|
| 794 |
+
orbit[x][54] = (f_54-3*orbit[x][70]-1*orbit[x][66]-2*orbit[x][65])/2;
|
| 795 |
+
orbit[x][53] = (f_53-2*orbit[x][68]-2*orbit[x][64]-2*orbit[x][63]);
|
| 796 |
+
orbit[x][52] = (f_52-2*orbit[x][66]-2*orbit[x][64]-1*orbit[x][59])/2;
|
| 797 |
+
orbit[x][51] = (f_51-2*orbit[x][68]-2*orbit[x][63]-4*orbit[x][62]);
|
| 798 |
+
orbit[x][50] = (f_50-1*orbit[x][68]-2*orbit[x][63])/3;
|
| 799 |
+
orbit[x][49] = (f_49-1*orbit[x][68]-1*orbit[x][64]-2*orbit[x][62])/2;
|
| 800 |
+
orbit[x][48] = (f_48-4*orbit[x][71]-8*orbit[x][69]-2*orbit[x][68]-2*orbit[x][67]-2*orbit[x][64]-2*orbit[x][61]-1*orbit[x][60]);
|
| 801 |
+
orbit[x][47] = (f_47-3*orbit[x][70]-2*orbit[x][68]-1*orbit[x][66]-1*orbit[x][63]-1*orbit[x][60]);
|
| 802 |
+
orbit[x][46] = (f_46-3*orbit[x][70]-2*orbit[x][68]-2*orbit[x][65]-1*orbit[x][63]-1*orbit[x][59]);
|
| 803 |
+
orbit[x][45] = (f_45-2*orbit[x][65]-2*orbit[x][62]-3*orbit[x][56]);
|
| 804 |
+
orbit[x][44] = (f_44-1*orbit[x][67]-2*orbit[x][61])/4;
|
| 805 |
+
orbit[x][43] = (f_43-2*orbit[x][66]-1*orbit[x][60]-1*orbit[x][59])/2;
|
| 806 |
+
orbit[x][42] = (f_42-2*orbit[x][71]-4*orbit[x][69]-2*orbit[x][67]-2*orbit[x][61]-3*orbit[x][55]);
|
| 807 |
+
orbit[x][41] = (f_41-2*orbit[x][71]-1*orbit[x][68]-2*orbit[x][67]-1*orbit[x][60]-3*orbit[x][55]);
|
| 808 |
+
orbit[x][40] = (f_40-6*orbit[x][70]-2*orbit[x][68]-2*orbit[x][66]-4*orbit[x][65]-1*orbit[x][60]-1*orbit[x][59]-4*orbit[x][54]);
|
| 809 |
+
orbit[x][39] = (f_39-4*orbit[x][65]-1*orbit[x][59]-6*orbit[x][56])/2;
|
| 810 |
+
orbit[x][38] = (f_38-1*orbit[x][68]-1*orbit[x][64]-2*orbit[x][63]-1*orbit[x][53]-3*orbit[x][50]);
|
| 811 |
+
orbit[x][37] = (f_37-2*orbit[x][68]-2*orbit[x][64]-2*orbit[x][63]-4*orbit[x][62]-1*orbit[x][53]-1*orbit[x][51]-4*orbit[x][49]);
|
| 812 |
+
orbit[x][36] = (f_36-1*orbit[x][68]-2*orbit[x][63]-2*orbit[x][62]-1*orbit[x][51]-3*orbit[x][50]);
|
| 813 |
+
orbit[x][35] = (f_35-1*orbit[x][59]-2*orbit[x][52]-2*orbit[x][45])/2;
|
| 814 |
+
orbit[x][34] = (f_34-1*orbit[x][59]-2*orbit[x][52]-1*orbit[x][51])/2;
|
| 815 |
+
orbit[x][33] = (f_33-1*orbit[x][67]-2*orbit[x][61]-3*orbit[x][58]-4*orbit[x][44]-2*orbit[x][42])/2;
|
| 816 |
+
orbit[x][32] = (f_32-2*orbit[x][66]-1*orbit[x][60]-1*orbit[x][59]-2*orbit[x][57]-2*orbit[x][43]-2*orbit[x][41]-1*orbit[x][40])/2;
|
| 817 |
+
orbit[x][31] = (f_31-2*orbit[x][65]-1*orbit[x][59]-3*orbit[x][56]-1*orbit[x][43]-2*orbit[x][39]);
|
| 818 |
+
orbit[x][30] = (f_30-1*orbit[x][67]-1*orbit[x][63]-2*orbit[x][61]-1*orbit[x][53]-4*orbit[x][44]);
|
| 819 |
+
orbit[x][29] = (f_29-2*orbit[x][66]-2*orbit[x][64]-1*orbit[x][60]-1*orbit[x][59]-1*orbit[x][53]-2*orbit[x][52]-2*orbit[x][43]);
|
| 820 |
+
orbit[x][28] = (f_28-2*orbit[x][65]-2*orbit[x][62]-1*orbit[x][59]-1*orbit[x][51]-1*orbit[x][43]);
|
| 821 |
+
orbit[x][27] = (f_27-1*orbit[x][59]-1*orbit[x][51]-2*orbit[x][45])/2;
|
| 822 |
+
orbit[x][26] = (f_26-2*orbit[x][67]-2*orbit[x][63]-2*orbit[x][61]-6*orbit[x][58]-1*orbit[x][53]-2*orbit[x][47]-2*orbit[x][42]);
|
| 823 |
+
orbit[x][25] = (f_25-2*orbit[x][66]-2*orbit[x][64]-1*orbit[x][59]-2*orbit[x][57]-2*orbit[x][52]-1*orbit[x][48]-1*orbit[x][40])/2;
|
| 824 |
+
orbit[x][24] = (f_24-4*orbit[x][65]-4*orbit[x][62]-1*orbit[x][59]-6*orbit[x][56]-1*orbit[x][51]-2*orbit[x][45]-2*orbit[x][39]);
|
| 825 |
+
orbit[x][23] = (f_23-1*orbit[x][55]-1*orbit[x][42]-2*orbit[x][33])/4;
|
| 826 |
+
orbit[x][22] = (f_22-2*orbit[x][54]-1*orbit[x][40]-1*orbit[x][39]-1*orbit[x][32]-2*orbit[x][31])/3;
|
| 827 |
+
orbit[x][21] = (f_21-3*orbit[x][55]-3*orbit[x][50]-2*orbit[x][42]-2*orbit[x][38]-2*orbit[x][33]);
|
| 828 |
+
orbit[x][20] = (f_20-2*orbit[x][54]-2*orbit[x][49]-1*orbit[x][40]-1*orbit[x][37]-1*orbit[x][32]);
|
| 829 |
+
orbit[x][19] = (f_19-4*orbit[x][54]-4*orbit[x][49]-1*orbit[x][40]-2*orbit[x][39]-1*orbit[x][37]-2*orbit[x][35]-2*orbit[x][31]);
|
| 830 |
+
orbit[x][18] = (f_18-1*orbit[x][59]-1*orbit[x][51]-2*orbit[x][46]-2*orbit[x][45]-2*orbit[x][36]-2*orbit[x][27]-1*orbit[x][24])/2;
|
| 831 |
+
orbit[x][17] = (f_17-1*orbit[x][60]-1*orbit[x][53]-1*orbit[x][51]-1*orbit[x][48]-1*orbit[x][37]-2*orbit[x][34]-2*orbit[x][30])/2;
|
| 832 |
+
orbit[x][16] = (f_16-1*orbit[x][59]-2*orbit[x][52]-1*orbit[x][51]-2*orbit[x][46]-2*orbit[x][36]-2*orbit[x][34]-1*orbit[x][29]);
|
| 833 |
+
orbit[x][15] = (f_15-1*orbit[x][59]-2*orbit[x][52]-1*orbit[x][51]-2*orbit[x][45]-2*orbit[x][35]-2*orbit[x][34]-2*orbit[x][27]);
|
| 834 |
+
}
|
| 835 |
+
endTime = clock();
|
| 836 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 837 |
+
|
| 838 |
+
endTime_all = endTime;
|
| 839 |
+
printf("total: %.2f sec\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 840 |
+
}
|
| 841 |
+
|
| 842 |
+
|
| 843 |
+
/** count edge orbits of graphlets on max 5 nodes */
|
| 844 |
+
void ecount5() {
|
| 845 |
+
clock_t startTime, endTime;
|
| 846 |
+
startTime = clock();
|
| 847 |
+
clock_t startTime_all, endTime_all;
|
| 848 |
+
startTime_all = startTime;
|
| 849 |
+
int frac,frac_prev;
|
| 850 |
+
|
| 851 |
+
// precompute common nodes
|
| 852 |
+
printf("stage 1 - precomputing common nodes\n");
|
| 853 |
+
frac_prev=-1;
|
| 854 |
+
for (int x=0;x<n;x++) {
|
| 855 |
+
frac = 100LL*x/n;
|
| 856 |
+
if (frac!=frac_prev) {
|
| 857 |
+
printf("%d%%\r",frac);
|
| 858 |
+
frac_prev=frac;
|
| 859 |
+
}
|
| 860 |
+
for (int n1=0;n1<deg[x];n1++) {
|
| 861 |
+
int a=adj[x][n1];
|
| 862 |
+
for (int n2=n1+1;n2<deg[x];n2++) {
|
| 863 |
+
int b=adj[x][n2];
|
| 864 |
+
PAIR ab=PAIR(a,b);
|
| 865 |
+
common2[ab]++;
|
| 866 |
+
for (int n3=n2+1;n3<deg[x];n3++) {
|
| 867 |
+
int c=adj[x][n3];
|
| 868 |
+
int st = adjacent(a,b)+adjacent(a,c)+adjacent(b,c);
|
| 869 |
+
if (st<2) continue;
|
| 870 |
+
TRIPLE abc=TRIPLE(a,b,c);
|
| 871 |
+
common3[abc]++;
|
| 872 |
+
}
|
| 873 |
+
}
|
| 874 |
+
}
|
| 875 |
+
}
|
| 876 |
+
// precompute triangles that span over edges
|
| 877 |
+
int *tri = (int*)calloc(m,sizeof(int));
|
| 878 |
+
for (int i=0;i<m;i++) {
|
| 879 |
+
int x=edges[i].a, y=edges[i].b;
|
| 880 |
+
for (int xi=0,yi=0; xi<deg[x] && yi<deg[y]; ) {
|
| 881 |
+
if (adj[x][xi]==adj[y][yi]) { tri[i]++; xi++; yi++; }
|
| 882 |
+
else if (adj[x][xi]<adj[y][yi]) { xi++; }
|
| 883 |
+
else { yi++; }
|
| 884 |
+
}
|
| 885 |
+
}
|
| 886 |
+
endTime = clock();
|
| 887 |
+
printf("%.2f sec\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 888 |
+
startTime = endTime;
|
| 889 |
+
|
| 890 |
+
// count full graphlets
|
| 891 |
+
printf("stage 2 - counting full graphlets\n");
|
| 892 |
+
int64 *C5 = (int64*)calloc(m,sizeof(int64));
|
| 893 |
+
int *neighx = (int*)malloc(n*sizeof(int)); // lookup table - edges to neighbors of x
|
| 894 |
+
memset(neighx,-1,n*sizeof(int));
|
| 895 |
+
int *neigh = (int*)malloc(n*sizeof(int)), nn; // lookup table - common neighbors of x and y
|
| 896 |
+
PII *neigh_edges = (PII*)malloc(n*sizeof(PII)); // list of common neighbors of x and y
|
| 897 |
+
int *neigh2 = (int*)malloc(n*sizeof(int)), nn2;
|
| 898 |
+
TIII *neigh2_edges = (TIII*)malloc(n*sizeof(TIII));
|
| 899 |
+
frac_prev=-1;
|
| 900 |
+
for (int x=0;x<n;x++) {
|
| 901 |
+
frac = 100LL*x/n;
|
| 902 |
+
if (frac!=frac_prev) {
|
| 903 |
+
printf("%d%%\r",frac);
|
| 904 |
+
frac_prev=frac;
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 908 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 909 |
+
neighx[y]=xy;
|
| 910 |
+
}
|
| 911 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 912 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 913 |
+
if (y >= x) break;
|
| 914 |
+
nn=0;
|
| 915 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 916 |
+
int z=inc[y][ny].first, yz=inc[y][ny].second;
|
| 917 |
+
if (z >= y) break;
|
| 918 |
+
if (neighx[z]==-1) continue;
|
| 919 |
+
int xz=neighx[z];
|
| 920 |
+
neigh[nn]=z;
|
| 921 |
+
neigh_edges[nn]={xz, yz};
|
| 922 |
+
nn++;
|
| 923 |
+
}
|
| 924 |
+
for (int i=0;i<nn;i++) {
|
| 925 |
+
int z = neigh[i], xz = neigh_edges[i].first, yz = neigh_edges[i].second;
|
| 926 |
+
nn2 = 0;
|
| 927 |
+
for (int j=i+1;j<nn;j++) {
|
| 928 |
+
int w = neigh[j], xw = neigh_edges[j].first, yw = neigh_edges[j].second;
|
| 929 |
+
if (adjacent(z,w)) {
|
| 930 |
+
neigh2[nn2]=w;
|
| 931 |
+
int zw=getEdgeId(z,w);
|
| 932 |
+
neigh2_edges[nn2]={xw,yw,zw};
|
| 933 |
+
nn2++;
|
| 934 |
+
}
|
| 935 |
+
}
|
| 936 |
+
for (int i2=0;i2<nn2;i2++) {
|
| 937 |
+
int z2 = neigh2[i2];
|
| 938 |
+
int z2x=neigh2_edges[i2].first, z2y=neigh2_edges[i2].second, z2z=neigh2_edges[i2].third;
|
| 939 |
+
for (int j2=i2+1;j2<nn2;j2++) {
|
| 940 |
+
int z3 = neigh2[j2];
|
| 941 |
+
int z3x=neigh2_edges[j2].first, z3y=neigh2_edges[j2].second, z3z=neigh2_edges[j2].third;
|
| 942 |
+
if (adjacent(z2,z3)) {
|
| 943 |
+
int zid=getEdgeId(z2,z3);
|
| 944 |
+
C5[xy]++; C5[xz]++; C5[yz]++;
|
| 945 |
+
C5[z2x]++; C5[z2y]++; C5[z2z]++;
|
| 946 |
+
C5[z3x]++; C5[z3y]++; C5[z3z]++;
|
| 947 |
+
C5[zid]++;
|
| 948 |
+
}
|
| 949 |
+
}
|
| 950 |
+
}
|
| 951 |
+
}
|
| 952 |
+
}
|
| 953 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 954 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 955 |
+
neighx[y]=-1;
|
| 956 |
+
}
|
| 957 |
+
}
|
| 958 |
+
endTime = clock();
|
| 959 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 960 |
+
startTime = endTime;
|
| 961 |
+
|
| 962 |
+
// set up a system of equations relating orbits for every node
|
| 963 |
+
printf("stage 3 - building systems of equations\n");
|
| 964 |
+
int *common_x = (int*)calloc(n,sizeof(int));
|
| 965 |
+
int *common_x_list = (int*)malloc(n*sizeof(int)), nc_x=0;
|
| 966 |
+
int *common_y = (int*)calloc(n,sizeof(int));
|
| 967 |
+
int *common_y_list = (int*)malloc(n*sizeof(int)), nc_y=0;
|
| 968 |
+
frac_prev=-1;
|
| 969 |
+
|
| 970 |
+
for (int x=0;x<n;x++) {
|
| 971 |
+
frac = 100LL*x/n;
|
| 972 |
+
if (frac!=frac_prev) {
|
| 973 |
+
printf("%d%%\r",frac);
|
| 974 |
+
frac_prev=frac;
|
| 975 |
+
}
|
| 976 |
+
|
| 977 |
+
// common nodes of x and some other node
|
| 978 |
+
for (int i=0;i<nc_x;i++) common_x[common_x_list[i]]=0;
|
| 979 |
+
nc_x=0;
|
| 980 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 981 |
+
int a=adj[x][nx];
|
| 982 |
+
for (int na=0;na<deg[a];na++) {
|
| 983 |
+
int z=adj[a][na];
|
| 984 |
+
if (z==x) continue;
|
| 985 |
+
if (common_x[z]==0) common_x_list[nc_x++]=z;
|
| 986 |
+
common_x[z]++;
|
| 987 |
+
}
|
| 988 |
+
}
|
| 989 |
+
|
| 990 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 991 |
+
int y=inc[x][nx].first, xy=inc[x][nx].second;
|
| 992 |
+
int e=xy;
|
| 993 |
+
if (y>=x) break;
|
| 994 |
+
|
| 995 |
+
// common nodes of y and some other node
|
| 996 |
+
for (int i=0;i<nc_y;i++) common_y[common_y_list[i]]=0;
|
| 997 |
+
nc_y=0;
|
| 998 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 999 |
+
int a=adj[y][ny];
|
| 1000 |
+
for (int na=0;na<deg[a];na++) {
|
| 1001 |
+
int z=adj[a][na];
|
| 1002 |
+
if (z==y) continue;
|
| 1003 |
+
if (common_y[z]==0) common_y_list[nc_y++]=z;
|
| 1004 |
+
common_y[z]++;
|
| 1005 |
+
}
|
| 1006 |
+
}
|
| 1007 |
+
|
| 1008 |
+
int64 f_66=0, f_65=0, f_62=0, f_61=0, f_60=0, f_51=0, f_50=0; // 11
|
| 1009 |
+
int64 f_64=0, f_58=0, f_55=0, f_48=0, f_41=0, f_35=0; // 10
|
| 1010 |
+
int64 f_63=0, f_59=0, f_57=0, f_54=0, f_53=0, f_52=0, f_47=0, f_40=0, f_39=0, f_34=0, f_33=0; // 9
|
| 1011 |
+
int64 f_45=0, f_36=0, f_26=0, f_23=0, f_19=0; // 7
|
| 1012 |
+
int64 f_49=0, f_38=0, f_37=0, f_32=0, f_25=0, f_22=0, f_18=0; // 6
|
| 1013 |
+
int64 f_56=0, f_46=0, f_44=0, f_43=0, f_42=0, f_31=0, f_30=0; // 5
|
| 1014 |
+
int64 f_27=0, f_17=0, f_15=0; // 4
|
| 1015 |
+
int64 f_20=0, f_16=0, f_13=0; // 3
|
| 1016 |
+
int64 f_29=0, f_28=0, f_24=0, f_21=0, f_14=0, f_12=0; // 2
|
| 1017 |
+
|
| 1018 |
+
// smaller (3-node) graphlets
|
| 1019 |
+
orbit[x][0] = deg[x];
|
| 1020 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1021 |
+
int z=adj[x][nx1];
|
| 1022 |
+
if (z==y) continue;
|
| 1023 |
+
if (adjacent(y,z)) eorbit[e][1]++;
|
| 1024 |
+
else eorbit[e][0]++;
|
| 1025 |
+
}
|
| 1026 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1027 |
+
int z=adj[y][ny];
|
| 1028 |
+
if (z==x) continue;
|
| 1029 |
+
if (!adjacent(x,z)) eorbit[e][0]++;
|
| 1030 |
+
}
|
| 1031 |
+
|
| 1032 |
+
// edge-orbit 11 = (14,14)
|
| 1033 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1034 |
+
int a=adj[x][nx1], xa=inc[x][nx1].second;
|
| 1035 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1036 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1037 |
+
int b=adj[x][nx2], xb=inc[x][nx2].second;
|
| 1038 |
+
if (b==y || !adjacent(y,b) || !adjacent(a,b)) continue;
|
| 1039 |
+
int ya=getEdgeId(y,a), yb=getEdgeId(y,b), ab=getEdgeId(a,b);
|
| 1040 |
+
eorbit[e][11]++;
|
| 1041 |
+
f_66 += common3_get(TRIPLE(x,y,a))-1;
|
| 1042 |
+
f_66 += common3_get(TRIPLE(x,y,b))-1;
|
| 1043 |
+
f_65 += common3_get(TRIPLE(a,b,x))-1;
|
| 1044 |
+
f_65 += common3_get(TRIPLE(a,b,y))-1;
|
| 1045 |
+
f_62 += tri[xy]-2;
|
| 1046 |
+
f_61 += (tri[xa]-2)+(tri[xb]-2)+(tri[ya]-2)+(tri[yb]-2);
|
| 1047 |
+
f_60 += tri[ab]-2;
|
| 1048 |
+
f_51 += (deg[x]-3)+(deg[y]-3);
|
| 1049 |
+
f_50 += (deg[a]-3)+(deg[b]-3);
|
| 1050 |
+
}
|
| 1051 |
+
}
|
| 1052 |
+
|
| 1053 |
+
// edge-orbit 10 = (13,13)
|
| 1054 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1055 |
+
int a=adj[x][nx1], xa=inc[x][nx1].second;
|
| 1056 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1057 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1058 |
+
int b=adj[x][nx2], xb=inc[x][nx2].second;
|
| 1059 |
+
if (b==y || !adjacent(y,b) || adjacent(a,b)) continue;
|
| 1060 |
+
int ya=getEdgeId(y,a), yb=getEdgeId(y,b);
|
| 1061 |
+
eorbit[e][10]++;
|
| 1062 |
+
f_64 += common3_get(TRIPLE(a,b,x))-1;
|
| 1063 |
+
f_64 += common3_get(TRIPLE(a,b,y))-1;
|
| 1064 |
+
f_58 += common2_get(PAIR(a,b))-2;
|
| 1065 |
+
f_55 += (tri[xa]-1)+(tri[xb]-1)+(tri[ya]-1)+(tri[yb]-1);
|
| 1066 |
+
f_48 += tri[xy]-2;
|
| 1067 |
+
f_41 += (deg[a]-2)+(deg[b]-2);
|
| 1068 |
+
f_35 += (deg[x]-3)+(deg[y]-3);
|
| 1069 |
+
}
|
| 1070 |
+
}
|
| 1071 |
+
|
| 1072 |
+
// edge-orbit 9 = (12,13)
|
| 1073 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1074 |
+
int a=adj[x][nx], xa=inc[x][nx].second;
|
| 1075 |
+
if (a==y) continue;
|
| 1076 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1077 |
+
int b=adj[y][ny], yb=inc[y][ny].second;
|
| 1078 |
+
if (b==x || !adjacent(a,b)) continue;
|
| 1079 |
+
int adj_ya=adjacent(y,a), adj_xb=adjacent(x,b);
|
| 1080 |
+
if (adj_ya+adj_xb!=1) continue;
|
| 1081 |
+
int ab=getEdgeId(a,b);
|
| 1082 |
+
eorbit[e][9]++;
|
| 1083 |
+
if (adj_xb) {
|
| 1084 |
+
int xb=getEdgeId(x,b);
|
| 1085 |
+
f_63 += common3_get(TRIPLE(a,b,y))-1;
|
| 1086 |
+
f_59 += common3_get(TRIPLE(a,b,x));
|
| 1087 |
+
f_57 += common_y[a]-2;
|
| 1088 |
+
f_54 += tri[yb]-1;
|
| 1089 |
+
f_53 += tri[xa]-1;
|
| 1090 |
+
f_47 += tri[xb]-2;
|
| 1091 |
+
f_40 += deg[y]-2;
|
| 1092 |
+
f_39 += deg[a]-2;
|
| 1093 |
+
f_34 += deg[x]-3;
|
| 1094 |
+
f_33 += deg[b]-3;
|
| 1095 |
+
} else if (adj_ya) {
|
| 1096 |
+
int ya=getEdgeId(y,a);
|
| 1097 |
+
f_63 += common3_get(TRIPLE(a,b,x))-1;
|
| 1098 |
+
f_59 += common3_get(TRIPLE(a,b,y));
|
| 1099 |
+
f_57 += common_x[b]-2;
|
| 1100 |
+
f_54 += tri[xa]-1;
|
| 1101 |
+
f_53 += tri[yb]-1;
|
| 1102 |
+
f_47 += tri[ya]-2;
|
| 1103 |
+
f_40 += deg[x]-2;
|
| 1104 |
+
f_39 += deg[b]-2;
|
| 1105 |
+
f_34 += deg[y]-3;
|
| 1106 |
+
f_33 += deg[a]-3;
|
| 1107 |
+
}
|
| 1108 |
+
f_52 += tri[ab]-1;
|
| 1109 |
+
}
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
+
// edge-orbit 8 = (10,11)
|
| 1113 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1114 |
+
int a=adj[x][nx];
|
| 1115 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1116 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1117 |
+
int b=adj[x][nx1];
|
| 1118 |
+
if (b==y || b==a || adjacent(y,b) || adjacent(a,b)) continue;
|
| 1119 |
+
eorbit[e][8]++;
|
| 1120 |
+
}
|
| 1121 |
+
for (int ny1=0;ny1<deg[y];ny1++) {
|
| 1122 |
+
int b=adj[y][ny1];
|
| 1123 |
+
if (b==x || b==a || adjacent(x,b) || adjacent(a,b)) continue;
|
| 1124 |
+
eorbit[e][8]++;
|
| 1125 |
+
}
|
| 1126 |
+
}
|
| 1127 |
+
|
| 1128 |
+
// edge-orbit 7 = (10,10)
|
| 1129 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1130 |
+
int a=adj[x][nx];
|
| 1131 |
+
if (a==y || !adjacent(y,a)) continue;
|
| 1132 |
+
for (int na=0;na<deg[a];na++) {
|
| 1133 |
+
int b=adj[a][na], ab=inc[a][na].second;
|
| 1134 |
+
if (b==x || b==y || adjacent(x,b) || adjacent(y,b)) continue;
|
| 1135 |
+
eorbit[e][7]++;
|
| 1136 |
+
f_45 += common_x[b]-1;
|
| 1137 |
+
f_45 += common_y[b]-1;
|
| 1138 |
+
f_36 += tri[ab];
|
| 1139 |
+
f_26 += deg[a]-3;
|
| 1140 |
+
f_23 += deg[b]-1;
|
| 1141 |
+
f_19 += (deg[x]-2)+(deg[y]-2);
|
| 1142 |
+
}
|
| 1143 |
+
}
|
| 1144 |
+
|
| 1145 |
+
// edge-orbit 6 = (9,11)
|
| 1146 |
+
for (int ny1=0;ny1<deg[y];ny1++) {
|
| 1147 |
+
int a=adj[y][ny1], ya=inc[y][ny1].second;
|
| 1148 |
+
if (a==x || adjacent(x,a)) continue;
|
| 1149 |
+
for (int ny2=ny1+1;ny2<deg[y];ny2++) {
|
| 1150 |
+
int b=adj[y][ny2], yb=inc[y][ny2].second;
|
| 1151 |
+
if (b==x || adjacent(x,b) || !adjacent(a,b)) continue;
|
| 1152 |
+
int ab=getEdgeId(a,b);
|
| 1153 |
+
eorbit[e][6]++;
|
| 1154 |
+
f_49 += common3_get(TRIPLE(y,a,b));
|
| 1155 |
+
f_38 += tri[ab]-1;
|
| 1156 |
+
f_37 += tri[xy];
|
| 1157 |
+
f_32 += (tri[ya]-1)+(tri[yb]-1);
|
| 1158 |
+
f_25 += deg[y]-3;
|
| 1159 |
+
f_22 += deg[x]-1;
|
| 1160 |
+
f_18 += (deg[a]-2)+(deg[b]-2);
|
| 1161 |
+
}
|
| 1162 |
+
}
|
| 1163 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1164 |
+
int a=adj[x][nx1], xa=inc[x][nx1].second;
|
| 1165 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1166 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1167 |
+
int b=adj[x][nx2], xb=inc[x][nx2].second;
|
| 1168 |
+
if (b==y || adjacent(y,b) || !adjacent(a,b)) continue;
|
| 1169 |
+
int ab=getEdgeId(a,b);
|
| 1170 |
+
eorbit[e][6]++;
|
| 1171 |
+
f_49 += common3_get(TRIPLE(x,a,b));
|
| 1172 |
+
f_38 += tri[ab]-1;
|
| 1173 |
+
f_37 += tri[xy];
|
| 1174 |
+
f_32 += (tri[xa]-1)+(tri[xb]-1);
|
| 1175 |
+
f_25 += deg[x]-3;
|
| 1176 |
+
f_22 += deg[y]-1;
|
| 1177 |
+
f_18 += (deg[a]-2)+(deg[b]-2);
|
| 1178 |
+
}
|
| 1179 |
+
}
|
| 1180 |
+
|
| 1181 |
+
// edge-orbit 5 = (8,8)
|
| 1182 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1183 |
+
int a=adj[x][nx], xa=inc[x][nx].second;
|
| 1184 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1185 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1186 |
+
int b=adj[y][ny], yb=inc[y][ny].second;
|
| 1187 |
+
if (b==x || adjacent(x,b) || !adjacent(a,b)) continue;
|
| 1188 |
+
int ab=getEdgeId(a,b);
|
| 1189 |
+
eorbit[e][5]++;
|
| 1190 |
+
f_56 += common3_get(TRIPLE(x,a,b));
|
| 1191 |
+
f_56 += common3_get(TRIPLE(y,a,b));
|
| 1192 |
+
f_46 += tri[xy];
|
| 1193 |
+
f_44 += tri[xa]+tri[yb];
|
| 1194 |
+
f_43 += tri[ab];
|
| 1195 |
+
f_42 += common_x[b]-2;
|
| 1196 |
+
f_42 += common_y[a]-2;
|
| 1197 |
+
f_31 += (deg[x]-2)+(deg[y]-2);
|
| 1198 |
+
f_30 += (deg[a]-2)+(deg[b]-2);
|
| 1199 |
+
}
|
| 1200 |
+
}
|
| 1201 |
+
|
| 1202 |
+
// edge-orbit 4 = (6,7)
|
| 1203 |
+
for (int ny1=0;ny1<deg[y];ny1++) {
|
| 1204 |
+
int a=adj[y][ny1];
|
| 1205 |
+
if (a==x || adjacent(x,a)) continue;
|
| 1206 |
+
for (int ny2=ny1+1;ny2<deg[y];ny2++) {
|
| 1207 |
+
int b=adj[y][ny2];
|
| 1208 |
+
if (b==x || adjacent(x,b) || adjacent(a,b)) continue;
|
| 1209 |
+
eorbit[e][4]++;
|
| 1210 |
+
f_27 += tri[xy];
|
| 1211 |
+
f_17 += deg[y]-3;
|
| 1212 |
+
f_15 += (deg[a]-1)+(deg[b]-1);
|
| 1213 |
+
}
|
| 1214 |
+
}
|
| 1215 |
+
for (int nx1=0;nx1<deg[x];nx1++) {
|
| 1216 |
+
int a=adj[x][nx1];
|
| 1217 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1218 |
+
for (int nx2=nx1+1;nx2<deg[x];nx2++) {
|
| 1219 |
+
int b=adj[x][nx2];
|
| 1220 |
+
if (b==y || adjacent(y,b) || adjacent(a,b)) continue;
|
| 1221 |
+
eorbit[e][4]++;
|
| 1222 |
+
f_27 += tri[xy];
|
| 1223 |
+
f_17 += deg[x]-3;
|
| 1224 |
+
f_15 += (deg[a]-1)+(deg[b]-1);
|
| 1225 |
+
}
|
| 1226 |
+
}
|
| 1227 |
+
|
| 1228 |
+
// edge-orbit 3 = (5,5)
|
| 1229 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1230 |
+
int a=adj[x][nx];
|
| 1231 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1232 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1233 |
+
int b=adj[y][ny];
|
| 1234 |
+
if (b==x || adjacent(x,b) || adjacent(a,b)) continue;
|
| 1235 |
+
eorbit[e][3]++;
|
| 1236 |
+
f_20 += tri[xy];
|
| 1237 |
+
f_16 += (deg[x]-2)+(deg[y]-2);
|
| 1238 |
+
f_13 += (deg[a]-1)+(deg[b]-1);
|
| 1239 |
+
}
|
| 1240 |
+
}
|
| 1241 |
+
|
| 1242 |
+
// edge-orbit 2 = (4,5)
|
| 1243 |
+
for (int ny=0;ny<deg[y];ny++) {
|
| 1244 |
+
int a=adj[y][ny];
|
| 1245 |
+
if (a==x || adjacent(x,a)) continue;
|
| 1246 |
+
for (int na=0;na<deg[a];na++) {
|
| 1247 |
+
int b=adj[a][na], ab=inc[a][na].second;
|
| 1248 |
+
if (b==y || adjacent(y,b) || adjacent(x,b)) continue;
|
| 1249 |
+
eorbit[e][2]++;
|
| 1250 |
+
f_29 += common_y[b]-1;
|
| 1251 |
+
f_28 += common_x[b];
|
| 1252 |
+
f_24 += tri[xy];
|
| 1253 |
+
f_21 += tri[ab];
|
| 1254 |
+
f_14 += deg[a]-2;
|
| 1255 |
+
f_12 += deg[b]-1;
|
| 1256 |
+
}
|
| 1257 |
+
}
|
| 1258 |
+
for (int nx=0;nx<deg[x];nx++) {
|
| 1259 |
+
int a=adj[x][nx];
|
| 1260 |
+
if (a==y || adjacent(y,a)) continue;
|
| 1261 |
+
for (int na=0;na<deg[a];na++) {
|
| 1262 |
+
int b=adj[a][na], ab=inc[a][na].second;
|
| 1263 |
+
if (b==x || adjacent(x,b) || adjacent(y,b)) continue;
|
| 1264 |
+
eorbit[e][2]++;
|
| 1265 |
+
f_29 += common_x[b]-1;
|
| 1266 |
+
f_28 += common_y[b];
|
| 1267 |
+
f_24 += tri[xy];
|
| 1268 |
+
f_21 += tri[ab];
|
| 1269 |
+
f_14 += deg[a]-2;
|
| 1270 |
+
f_12 += deg[b]-1;
|
| 1271 |
+
}
|
| 1272 |
+
}
|
| 1273 |
+
|
| 1274 |
+
// solve system of equations
|
| 1275 |
+
eorbit[e][67]=C5[e];
|
| 1276 |
+
eorbit[e][66]=(f_66-6*eorbit[e][67])/2;
|
| 1277 |
+
eorbit[e][65]=(f_65-6*eorbit[e][67]);
|
| 1278 |
+
eorbit[e][64]=(f_64-2*eorbit[e][66]);
|
| 1279 |
+
eorbit[e][63]=(f_63-2*eorbit[e][65])/2;
|
| 1280 |
+
eorbit[e][62]=(f_62-2*eorbit[e][66]-3*eorbit[e][67]);
|
| 1281 |
+
eorbit[e][61]=(f_61-2*eorbit[e][65]-4*eorbit[e][66]-12*eorbit[e][67]);
|
| 1282 |
+
eorbit[e][60]=(f_60-1*eorbit[e][65]-3*eorbit[e][67]);
|
| 1283 |
+
eorbit[e][59]=(f_59-2*eorbit[e][65])/2;
|
| 1284 |
+
eorbit[e][58]=(f_58-1*eorbit[e][64]-1*eorbit[e][66]);
|
| 1285 |
+
eorbit[e][57]=(f_57-2*eorbit[e][63]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1286 |
+
eorbit[e][56]=(f_56-2*eorbit[e][63])/2;
|
| 1287 |
+
eorbit[e][55]=(f_55-4*eorbit[e][62]-2*eorbit[e][64]-4*eorbit[e][66]);
|
| 1288 |
+
eorbit[e][54]=(f_54-1*eorbit[e][61]-2*eorbit[e][63]-2*eorbit[e][65])/2;
|
| 1289 |
+
eorbit[e][53]=(f_53-2*eorbit[e][59]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1290 |
+
eorbit[e][52]=(f_52-2*eorbit[e][59]-2*eorbit[e][63]-2*eorbit[e][65]);
|
| 1291 |
+
eorbit[e][51]=(f_51-1*eorbit[e][61]-2*eorbit[e][62]-1*eorbit[e][65]-4*eorbit[e][66]-6*eorbit[e][67]);
|
| 1292 |
+
eorbit[e][50]=(f_50-2*eorbit[e][60]-1*eorbit[e][61]-2*eorbit[e][65]-2*eorbit[e][66]-6*eorbit[e][67]);
|
| 1293 |
+
eorbit[e][49]=(f_49-1*eorbit[e][59])/3;
|
| 1294 |
+
eorbit[e][48]=(f_48-2*eorbit[e][62]-1*eorbit[e][66])/3;
|
| 1295 |
+
eorbit[e][47]=(f_47-2*eorbit[e][59]-1*eorbit[e][61]-2*eorbit[e][65])/2;
|
| 1296 |
+
eorbit[e][46]=(f_46-1*eorbit[e][57]-1*eorbit[e][63]);
|
| 1297 |
+
eorbit[e][45]=(f_45-1*eorbit[e][52]-4*eorbit[e][58]-4*eorbit[e][60]);
|
| 1298 |
+
eorbit[e][44]=(f_44-2*eorbit[e][56]-1*eorbit[e][57]-2*eorbit[e][63]);
|
| 1299 |
+
eorbit[e][43]=(f_43-2*eorbit[e][56]-1*eorbit[e][63]);
|
| 1300 |
+
eorbit[e][42]=(f_42-2*eorbit[e][56]-1*eorbit[e][57]-2*eorbit[e][63])/2;
|
| 1301 |
+
eorbit[e][41]=(f_41-1*eorbit[e][55]-2*eorbit[e][58]-2*eorbit[e][62]-2*eorbit[e][64]-2*eorbit[e][66]);
|
| 1302 |
+
eorbit[e][40]=(f_40-2*eorbit[e][54]-1*eorbit[e][55]-1*eorbit[e][57]-1*eorbit[e][61]-2*eorbit[e][63]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1303 |
+
eorbit[e][39]=(f_39-1*eorbit[e][52]-1*eorbit[e][53]-1*eorbit[e][57]-2*eorbit[e][59]-2*eorbit[e][63]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1304 |
+
eorbit[e][38]=(f_38-3*eorbit[e][49]-1*eorbit[e][56]-1*eorbit[e][59]);
|
| 1305 |
+
eorbit[e][37]=(f_37-1*eorbit[e][53]-1*eorbit[e][59]);
|
| 1306 |
+
eorbit[e][36]=(f_36-1*eorbit[e][52]-2*eorbit[e][60])/2;
|
| 1307 |
+
eorbit[e][35]=(f_35-6*eorbit[e][48]-1*eorbit[e][55]-4*eorbit[e][62]-1*eorbit[e][64]-2*eorbit[e][66]);
|
| 1308 |
+
eorbit[e][34]=(f_34-2*eorbit[e][47]-1*eorbit[e][53]-1*eorbit[e][55]-2*eorbit[e][59]-1*eorbit[e][61]-2*eorbit[e][64]-2*eorbit[e][65]);
|
| 1309 |
+
eorbit[e][33]=(f_33-2*eorbit[e][47]-1*eorbit[e][52]-2*eorbit[e][54]-2*eorbit[e][59]-1*eorbit[e][61]-2*eorbit[e][63]-2*eorbit[e][65]);
|
| 1310 |
+
eorbit[e][32]=(f_32-6*eorbit[e][49]-1*eorbit[e][53]-2*eorbit[e][59])/2;
|
| 1311 |
+
eorbit[e][31]=(f_31-2*eorbit[e][42]-1*eorbit[e][44]-2*eorbit[e][46]-2*eorbit[e][56]-2*eorbit[e][57]-2*eorbit[e][63]);
|
| 1312 |
+
eorbit[e][30]=(f_30-2*eorbit[e][42]-2*eorbit[e][43]-1*eorbit[e][44]-4*eorbit[e][56]-1*eorbit[e][57]-2*eorbit[e][63]);
|
| 1313 |
+
eorbit[e][29]=(f_29-2*eorbit[e][38]-1*eorbit[e][45]-1*eorbit[e][52])/2;
|
| 1314 |
+
eorbit[e][28]=(f_28-2*eorbit[e][43]-1*eorbit[e][45]-1*eorbit[e][52])/2;
|
| 1315 |
+
eorbit[e][27]=(f_27-1*eorbit[e][34]-1*eorbit[e][47]);
|
| 1316 |
+
eorbit[e][26]=(f_26-1*eorbit[e][33]-2*eorbit[e][36]-1*eorbit[e][50]-1*eorbit[e][52]-2*eorbit[e][60])/2;
|
| 1317 |
+
eorbit[e][25]=(f_25-2*eorbit[e][32]-1*eorbit[e][37]-3*eorbit[e][49]-1*eorbit[e][53]-1*eorbit[e][59]);
|
| 1318 |
+
eorbit[e][24]=(f_24-1*eorbit[e][39]-1*eorbit[e][45]-1*eorbit[e][52]);
|
| 1319 |
+
eorbit[e][23]=(f_23-2*eorbit[e][36]-1*eorbit[e][45]-1*eorbit[e][52]-2*eorbit[e][58]-2*eorbit[e][60]);
|
| 1320 |
+
eorbit[e][22]=(f_22-1*eorbit[e][37]-1*eorbit[e][44]-1*eorbit[e][53]-1*eorbit[e][56]-1*eorbit[e][59]);
|
| 1321 |
+
eorbit[e][21]=(f_21-2*eorbit[e][38]-2*eorbit[e][43]-1*eorbit[e][52])/2;
|
| 1322 |
+
eorbit[e][20]=(f_20-1*eorbit[e][40]-1*eorbit[e][54]);
|
| 1323 |
+
eorbit[e][19]=(f_19-1*eorbit[e][33]-2*eorbit[e][41]-1*eorbit[e][45]-2*eorbit[e][50]-1*eorbit[e][52]-4*eorbit[e][58]-4*eorbit[e][60]);
|
| 1324 |
+
eorbit[e][18]=(f_18-2*eorbit[e][32]-2*eorbit[e][38]-1*eorbit[e][44]-6*eorbit[e][49]-1*eorbit[e][53]-2*eorbit[e][56]-2*eorbit[e][59]);
|
| 1325 |
+
eorbit[e][17]=(f_17-2*eorbit[e][25]-1*eorbit[e][27]-1*eorbit[e][32]-1*eorbit[e][34]-1*eorbit[e][47])/3;
|
| 1326 |
+
eorbit[e][16]=(f_16-2*eorbit[e][20]-2*eorbit[e][22]-1*eorbit[e][31]-2*eorbit[e][40]-1*eorbit[e][44]-2*eorbit[e][54])/2;
|
| 1327 |
+
eorbit[e][15]=(f_15-2*eorbit[e][25]-2*eorbit[e][29]-1*eorbit[e][31]-2*eorbit[e][32]-1*eorbit[e][34]-2*eorbit[e][42]-2*eorbit[e][47]);
|
| 1328 |
+
eorbit[e][14]=(f_14-1*eorbit[e][18]-2*eorbit[e][21]-1*eorbit[e][30]-2*eorbit[e][38]-1*eorbit[e][39]-2*eorbit[e][43]-1*eorbit[e][52])/2;
|
| 1329 |
+
eorbit[e][13]=(f_13-2*eorbit[e][22]-2*eorbit[e][28]-1*eorbit[e][31]-1*eorbit[e][40]-2*eorbit[e][44]-2*eorbit[e][54]);
|
| 1330 |
+
eorbit[e][12]=(f_12-2*eorbit[e][21]-2*eorbit[e][28]-2*eorbit[e][29]-2*eorbit[e][38]-2*eorbit[e][43]-1*eorbit[e][45]-1*eorbit[e][52]);
|
| 1331 |
+
}
|
| 1332 |
+
}
|
| 1333 |
+
|
| 1334 |
+
endTime = clock();
|
| 1335 |
+
printf("%.2f\n", (double)(endTime-startTime)/CLOCKS_PER_SEC);
|
| 1336 |
+
|
| 1337 |
+
endTime_all = endTime;
|
| 1338 |
+
printf("total: %.2f\n", (double)(endTime_all-startTime_all)/CLOCKS_PER_SEC);
|
| 1339 |
+
}
|
| 1340 |
+
|
| 1341 |
+
fstream fin, fout; // input and output files
|
| 1342 |
+
int GS=5;
|
| 1343 |
+
string orbit_type;
|
| 1344 |
+
|
| 1345 |
+
int motif_counts(char* orbit_type, int graphlet_size, const char* input_filename, const char* output_filename) {
|
| 1346 |
+
// open input, output files
|
| 1347 |
+
if (strcmp(orbit_type, "node")!=0 && strcmp(orbit_type, "edge")!=0) {
|
| 1348 |
+
cerr << "Incorrect orbit type '" << orbit_type << "'. Should be 'node' or 'edge'." << endl;
|
| 1349 |
+
return 0;
|
| 1350 |
+
}
|
| 1351 |
+
if (GS!=4 && GS!=5) {
|
| 1352 |
+
cerr << "Incorrect graphlet size " << graphlet_size << ". Should be 4 or 5." << endl;
|
| 1353 |
+
return 0;
|
| 1354 |
+
}
|
| 1355 |
+
fin.open(input_filename, fstream::in);
|
| 1356 |
+
fout.open(output_filename, fstream::out | fstream::binary);
|
| 1357 |
+
if (fin.fail()) {
|
| 1358 |
+
cerr << "Failed to open file " << input_filename << endl;
|
| 1359 |
+
return 0;
|
| 1360 |
+
}
|
| 1361 |
+
if (fout.fail()) {
|
| 1362 |
+
cerr << "Failed to open file " << output_filename << endl;
|
| 1363 |
+
return 0;
|
| 1364 |
+
}
|
| 1365 |
+
// read input graph
|
| 1366 |
+
fin >> n >> m;
|
| 1367 |
+
int d_max=0;
|
| 1368 |
+
edges = (PAIR*)malloc(m*sizeof(PAIR));
|
| 1369 |
+
deg = (int*)calloc(n,sizeof(int));
|
| 1370 |
+
for (int i=0;i<m;i++) {
|
| 1371 |
+
int a,b;
|
| 1372 |
+
fin >> a >> b;
|
| 1373 |
+
if (!(0<=a && a<n) || !(0<=b && b<n)) {
|
| 1374 |
+
cerr << "Node ids should be between 0 and n-1." << endl;
|
| 1375 |
+
return 0;
|
| 1376 |
+
}
|
| 1377 |
+
if (a==b) {
|
| 1378 |
+
cerr << "Self loops (edge from x to x) are not allowed." << endl;
|
| 1379 |
+
return 0;
|
| 1380 |
+
}
|
| 1381 |
+
deg[a]++; deg[b]++;
|
| 1382 |
+
edges[i]=PAIR(a,b);
|
| 1383 |
+
}
|
| 1384 |
+
for (int i=0;i<n;i++) d_max=max(d_max,deg[i]);
|
| 1385 |
+
printf("nodes: %d\n",n);
|
| 1386 |
+
printf("edges: %d\n",m);
|
| 1387 |
+
printf("max degree: %d\n",d_max);
|
| 1388 |
+
fin.close();
|
| 1389 |
+
if ((int)(set<PAIR>(edges,edges+m).size())!=m) {
|
| 1390 |
+
cerr << "Input file contains duplicate undirected edges." << endl;
|
| 1391 |
+
return 0;
|
| 1392 |
+
}
|
| 1393 |
+
// set up adjacency matrix if it's smaller than 100MB
|
| 1394 |
+
if ((int64)n*n < 100LL*1024*1024*8) {
|
| 1395 |
+
adjacent = adjacent_matrix;
|
| 1396 |
+
adj_matrix = (int*)calloc((n*n)/adj_chunk+1,sizeof(int));
|
| 1397 |
+
for (int i=0;i<m;i++) {
|
| 1398 |
+
int a=edges[i].a, b=edges[i].b;
|
| 1399 |
+
adj_matrix[(a*n+b)/adj_chunk]|=(1<<((a*n+b)%adj_chunk));
|
| 1400 |
+
adj_matrix[(b*n+a)/adj_chunk]|=(1<<((b*n+a)%adj_chunk));
|
| 1401 |
+
}
|
| 1402 |
+
} else {
|
| 1403 |
+
adjacent = adjacent_list;
|
| 1404 |
+
}
|
| 1405 |
+
// set up adjacency, incidence lists
|
| 1406 |
+
adj = (int**)malloc(n*sizeof(int*));
|
| 1407 |
+
for (int i=0;i<n;i++) adj[i] = (int*)malloc(deg[i]*sizeof(int));
|
| 1408 |
+
inc = (PII**)malloc(n*sizeof(PII*));
|
| 1409 |
+
for (int i=0;i<n;i++) inc[i] = (PII*)malloc(deg[i]*sizeof(PII));
|
| 1410 |
+
int *d = (int*)calloc(n,sizeof(int));
|
| 1411 |
+
for (int i=0;i<m;i++) {
|
| 1412 |
+
int a=edges[i].a, b=edges[i].b;
|
| 1413 |
+
adj[a][d[a]]=b; adj[b][d[b]]=a;
|
| 1414 |
+
inc[a][d[a]]=PII(b,i); inc[b][d[b]]=PII(a,i);
|
| 1415 |
+
d[a]++; d[b]++;
|
| 1416 |
+
}
|
| 1417 |
+
for (int i=0;i<n;i++) {
|
| 1418 |
+
sort(adj[i],adj[i]+deg[i]);
|
| 1419 |
+
sort(inc[i],inc[i]+deg[i]);
|
| 1420 |
+
}
|
| 1421 |
+
// initialize orbit counts
|
| 1422 |
+
orbit = (int64**)malloc(n*sizeof(int64*));
|
| 1423 |
+
for (int i=0;i<n;i++) orbit[i] = (int64*)calloc(73,sizeof(int64));
|
| 1424 |
+
// initialize edge orbit counts
|
| 1425 |
+
eorbit = (int64**)malloc(m*sizeof(int64*));
|
| 1426 |
+
for (int i=0;i<m;i++) eorbit[i] = (int64*)calloc(68,sizeof(int64));
|
| 1427 |
+
return 1;
|
| 1428 |
+
}
|
| 1429 |
+
|
| 1430 |
+
int init(int argc, char *argv[]) {
|
| 1431 |
+
if (argc!=5) {
|
| 1432 |
+
cerr << "Incorrect number of arguments." << endl;
|
| 1433 |
+
cerr << "Usage: orca.exe [orbit type: node|edge] [graphlet size: 4/5] [graph - input file] [graphlets - output file]" << endl;
|
| 1434 |
+
return 0;
|
| 1435 |
+
}
|
| 1436 |
+
int graphlet_size;
|
| 1437 |
+
sscanf(argv[2],"%d", &graphlet_size);
|
| 1438 |
+
motif_counts(argv[1], graphlet_size, argv[3], argv[4]);
|
| 1439 |
+
}
|
| 1440 |
+
|
| 1441 |
+
void writeResults(int g=5) {
|
| 1442 |
+
int no[] = {0,0,1,4,15,73};
|
| 1443 |
+
for (int i=0;i<n;i++) {
|
| 1444 |
+
for (int j=0;j<no[g];j++) {
|
| 1445 |
+
if (j!=0) fout << " ";
|
| 1446 |
+
fout << orbit[i][j];
|
| 1447 |
+
}
|
| 1448 |
+
fout << endl;
|
| 1449 |
+
}
|
| 1450 |
+
fout.close();
|
| 1451 |
+
}
|
| 1452 |
+
|
| 1453 |
+
void writeEdgeResults(int g=5) {
|
| 1454 |
+
int no[] = {0,0,0,2,12,68};
|
| 1455 |
+
for (int i=0;i<m;i++) {
|
| 1456 |
+
for (int j=0;j<no[g];j++) {
|
| 1457 |
+
if (j!=0) fout << " ";
|
| 1458 |
+
fout << eorbit[i][j];
|
| 1459 |
+
}
|
| 1460 |
+
fout << endl;
|
| 1461 |
+
}
|
| 1462 |
+
fout.close();
|
| 1463 |
+
}
|
| 1464 |
+
|
| 1465 |
+
|
| 1466 |
+
//int main(int argc, char *argv[]) {
|
| 1467 |
+
//
|
| 1468 |
+
//
|
| 1469 |
+
// if (!init(argc, argv)) {
|
| 1470 |
+
// cerr << "Stopping!" << endl;
|
| 1471 |
+
// return 0;
|
| 1472 |
+
// }
|
| 1473 |
+
// if (orbit_type=="node") {
|
| 1474 |
+
// printf("Counting NODE orbits of graphlets on %d nodes.\n\n",GS);
|
| 1475 |
+
// if (GS==4) count4();
|
| 1476 |
+
// if (GS==5) count5();
|
| 1477 |
+
// writeResults(GS);
|
| 1478 |
+
// } else {
|
| 1479 |
+
// printf("Counting EDGE orbits of graphlets on %d nodes.\n\n",GS);
|
| 1480 |
+
// if (GS==4) ecount4();
|
| 1481 |
+
// if (GS==5) ecount5();
|
| 1482 |
+
// writeEdgeResults(GS);
|
| 1483 |
+
// }
|
| 1484 |
+
//
|
| 1485 |
+
//
|
| 1486 |
+
// return 0;
|
| 1487 |
+
//}
|
| 1488 |
+
|
analysis/orca/tmp_JJOX0U87.txt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
9 24
|
| 2 |
+
0 1
|
| 3 |
+
0 2
|
| 4 |
+
0 5
|
| 5 |
+
0 6
|
| 6 |
+
0 7
|
| 7 |
+
1 4
|
| 8 |
+
1 6
|
| 9 |
+
1 8
|
| 10 |
+
2 3
|
| 11 |
+
2 4
|
| 12 |
+
2 6
|
| 13 |
+
2 8
|
| 14 |
+
3 4
|
| 15 |
+
3 5
|
| 16 |
+
3 7
|
| 17 |
+
4 5
|
| 18 |
+
4 7
|
| 19 |
+
4 8
|
| 20 |
+
5 6
|
| 21 |
+
5 7
|
| 22 |
+
5 8
|
| 23 |
+
6 7
|
| 24 |
+
6 8
|
| 25 |
+
7 8
|
analysis/orca/tmp_YX4O2JRL.txt
ADDED
|
@@ -0,0 +1,3269 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
217 3268
|
| 2 |
+
0 1
|
| 3 |
+
0 2
|
| 4 |
+
0 4
|
| 5 |
+
0 8
|
| 6 |
+
0 9
|
| 7 |
+
0 11
|
| 8 |
+
0 13
|
| 9 |
+
0 16
|
| 10 |
+
0 17
|
| 11 |
+
0 30
|
| 12 |
+
0 33
|
| 13 |
+
0 35
|
| 14 |
+
0 36
|
| 15 |
+
0 42
|
| 16 |
+
0 47
|
| 17 |
+
0 50
|
| 18 |
+
0 51
|
| 19 |
+
0 52
|
| 20 |
+
0 53
|
| 21 |
+
0 54
|
| 22 |
+
0 55
|
| 23 |
+
0 56
|
| 24 |
+
0 57
|
| 25 |
+
0 58
|
| 26 |
+
1 2
|
| 27 |
+
1 3
|
| 28 |
+
1 4
|
| 29 |
+
1 7
|
| 30 |
+
1 8
|
| 31 |
+
1 9
|
| 32 |
+
1 10
|
| 33 |
+
1 11
|
| 34 |
+
1 12
|
| 35 |
+
1 13
|
| 36 |
+
1 14
|
| 37 |
+
1 15
|
| 38 |
+
1 16
|
| 39 |
+
1 17
|
| 40 |
+
1 18
|
| 41 |
+
1 19
|
| 42 |
+
1 20
|
| 43 |
+
1 21
|
| 44 |
+
1 22
|
| 45 |
+
1 23
|
| 46 |
+
1 24
|
| 47 |
+
1 25
|
| 48 |
+
1 27
|
| 49 |
+
1 28
|
| 50 |
+
1 29
|
| 51 |
+
1 30
|
| 52 |
+
1 32
|
| 53 |
+
1 33
|
| 54 |
+
1 34
|
| 55 |
+
1 35
|
| 56 |
+
1 36
|
| 57 |
+
1 37
|
| 58 |
+
1 38
|
| 59 |
+
1 39
|
| 60 |
+
1 40
|
| 61 |
+
1 41
|
| 62 |
+
1 42
|
| 63 |
+
1 43
|
| 64 |
+
1 46
|
| 65 |
+
1 47
|
| 66 |
+
1 48
|
| 67 |
+
1 49
|
| 68 |
+
1 50
|
| 69 |
+
1 51
|
| 70 |
+
1 52
|
| 71 |
+
1 53
|
| 72 |
+
1 54
|
| 73 |
+
1 55
|
| 74 |
+
1 57
|
| 75 |
+
1 62
|
| 76 |
+
1 64
|
| 77 |
+
1 69
|
| 78 |
+
1 80
|
| 79 |
+
1 95
|
| 80 |
+
1 97
|
| 81 |
+
1 98
|
| 82 |
+
1 99
|
| 83 |
+
1 100
|
| 84 |
+
1 101
|
| 85 |
+
1 103
|
| 86 |
+
1 104
|
| 87 |
+
1 105
|
| 88 |
+
1 106
|
| 89 |
+
1 107
|
| 90 |
+
1 108
|
| 91 |
+
1 111
|
| 92 |
+
1 112
|
| 93 |
+
1 115
|
| 94 |
+
1 116
|
| 95 |
+
1 117
|
| 96 |
+
1 118
|
| 97 |
+
1 120
|
| 98 |
+
1 122
|
| 99 |
+
1 124
|
| 100 |
+
1 127
|
| 101 |
+
1 128
|
| 102 |
+
1 137
|
| 103 |
+
1 162
|
| 104 |
+
1 164
|
| 105 |
+
1 165
|
| 106 |
+
1 197
|
| 107 |
+
2 3
|
| 108 |
+
2 4
|
| 109 |
+
2 5
|
| 110 |
+
2 8
|
| 111 |
+
2 9
|
| 112 |
+
2 10
|
| 113 |
+
2 11
|
| 114 |
+
2 12
|
| 115 |
+
2 13
|
| 116 |
+
2 14
|
| 117 |
+
2 16
|
| 118 |
+
2 17
|
| 119 |
+
2 18
|
| 120 |
+
2 19
|
| 121 |
+
2 20
|
| 122 |
+
2 21
|
| 123 |
+
2 22
|
| 124 |
+
2 23
|
| 125 |
+
2 24
|
| 126 |
+
2 25
|
| 127 |
+
2 27
|
| 128 |
+
2 28
|
| 129 |
+
2 29
|
| 130 |
+
2 30
|
| 131 |
+
2 31
|
| 132 |
+
2 33
|
| 133 |
+
2 35
|
| 134 |
+
2 36
|
| 135 |
+
2 37
|
| 136 |
+
2 38
|
| 137 |
+
2 39
|
| 138 |
+
2 41
|
| 139 |
+
2 42
|
| 140 |
+
2 43
|
| 141 |
+
2 44
|
| 142 |
+
2 45
|
| 143 |
+
2 46
|
| 144 |
+
2 47
|
| 145 |
+
2 48
|
| 146 |
+
2 49
|
| 147 |
+
2 50
|
| 148 |
+
2 51
|
| 149 |
+
2 52
|
| 150 |
+
2 53
|
| 151 |
+
2 54
|
| 152 |
+
2 55
|
| 153 |
+
2 56
|
| 154 |
+
2 57
|
| 155 |
+
2 59
|
| 156 |
+
2 60
|
| 157 |
+
2 62
|
| 158 |
+
2 63
|
| 159 |
+
2 64
|
| 160 |
+
2 65
|
| 161 |
+
2 66
|
| 162 |
+
2 69
|
| 163 |
+
2 80
|
| 164 |
+
2 95
|
| 165 |
+
2 96
|
| 166 |
+
2 97
|
| 167 |
+
2 98
|
| 168 |
+
2 99
|
| 169 |
+
2 100
|
| 170 |
+
2 101
|
| 171 |
+
2 103
|
| 172 |
+
2 104
|
| 173 |
+
2 105
|
| 174 |
+
2 106
|
| 175 |
+
2 107
|
| 176 |
+
2 108
|
| 177 |
+
2 110
|
| 178 |
+
2 111
|
| 179 |
+
2 112
|
| 180 |
+
2 113
|
| 181 |
+
2 114
|
| 182 |
+
2 115
|
| 183 |
+
2 116
|
| 184 |
+
2 117
|
| 185 |
+
2 118
|
| 186 |
+
2 119
|
| 187 |
+
2 120
|
| 188 |
+
2 121
|
| 189 |
+
2 122
|
| 190 |
+
2 123
|
| 191 |
+
2 126
|
| 192 |
+
2 127
|
| 193 |
+
2 128
|
| 194 |
+
2 129
|
| 195 |
+
2 131
|
| 196 |
+
2 135
|
| 197 |
+
2 136
|
| 198 |
+
2 137
|
| 199 |
+
2 154
|
| 200 |
+
2 158
|
| 201 |
+
2 162
|
| 202 |
+
2 164
|
| 203 |
+
2 175
|
| 204 |
+
2 202
|
| 205 |
+
3 6
|
| 206 |
+
3 7
|
| 207 |
+
3 8
|
| 208 |
+
3 11
|
| 209 |
+
3 13
|
| 210 |
+
3 14
|
| 211 |
+
3 15
|
| 212 |
+
3 16
|
| 213 |
+
3 17
|
| 214 |
+
3 18
|
| 215 |
+
3 19
|
| 216 |
+
3 20
|
| 217 |
+
3 25
|
| 218 |
+
3 26
|
| 219 |
+
3 27
|
| 220 |
+
3 29
|
| 221 |
+
3 31
|
| 222 |
+
3 32
|
| 223 |
+
3 33
|
| 224 |
+
3 34
|
| 225 |
+
3 35
|
| 226 |
+
3 37
|
| 227 |
+
3 38
|
| 228 |
+
3 39
|
| 229 |
+
3 40
|
| 230 |
+
3 41
|
| 231 |
+
3 43
|
| 232 |
+
3 44
|
| 233 |
+
3 46
|
| 234 |
+
3 47
|
| 235 |
+
3 48
|
| 236 |
+
3 49
|
| 237 |
+
3 50
|
| 238 |
+
3 51
|
| 239 |
+
3 52
|
| 240 |
+
3 54
|
| 241 |
+
3 55
|
| 242 |
+
3 56
|
| 243 |
+
3 57
|
| 244 |
+
3 69
|
| 245 |
+
3 80
|
| 246 |
+
3 95
|
| 247 |
+
3 99
|
| 248 |
+
3 100
|
| 249 |
+
3 101
|
| 250 |
+
3 102
|
| 251 |
+
3 103
|
| 252 |
+
3 104
|
| 253 |
+
3 105
|
| 254 |
+
3 107
|
| 255 |
+
3 108
|
| 256 |
+
3 111
|
| 257 |
+
3 112
|
| 258 |
+
3 114
|
| 259 |
+
3 115
|
| 260 |
+
3 116
|
| 261 |
+
3 118
|
| 262 |
+
3 121
|
| 263 |
+
3 122
|
| 264 |
+
3 124
|
| 265 |
+
3 126
|
| 266 |
+
3 128
|
| 267 |
+
3 129
|
| 268 |
+
3 130
|
| 269 |
+
3 131
|
| 270 |
+
3 136
|
| 271 |
+
4 5
|
| 272 |
+
4 7
|
| 273 |
+
4 8
|
| 274 |
+
4 9
|
| 275 |
+
4 10
|
| 276 |
+
4 11
|
| 277 |
+
4 15
|
| 278 |
+
4 16
|
| 279 |
+
4 17
|
| 280 |
+
4 20
|
| 281 |
+
4 21
|
| 282 |
+
4 25
|
| 283 |
+
4 27
|
| 284 |
+
4 28
|
| 285 |
+
4 30
|
| 286 |
+
4 32
|
| 287 |
+
4 33
|
| 288 |
+
4 34
|
| 289 |
+
4 35
|
| 290 |
+
4 36
|
| 291 |
+
4 37
|
| 292 |
+
4 38
|
| 293 |
+
4 39
|
| 294 |
+
4 41
|
| 295 |
+
4 43
|
| 296 |
+
4 44
|
| 297 |
+
4 45
|
| 298 |
+
4 46
|
| 299 |
+
4 47
|
| 300 |
+
4 49
|
| 301 |
+
4 50
|
| 302 |
+
4 51
|
| 303 |
+
4 53
|
| 304 |
+
4 54
|
| 305 |
+
4 55
|
| 306 |
+
4 56
|
| 307 |
+
4 57
|
| 308 |
+
4 59
|
| 309 |
+
4 60
|
| 310 |
+
4 61
|
| 311 |
+
4 63
|
| 312 |
+
4 65
|
| 313 |
+
4 67
|
| 314 |
+
4 69
|
| 315 |
+
4 70
|
| 316 |
+
4 80
|
| 317 |
+
4 85
|
| 318 |
+
4 87
|
| 319 |
+
4 91
|
| 320 |
+
4 92
|
| 321 |
+
4 93
|
| 322 |
+
4 94
|
| 323 |
+
4 97
|
| 324 |
+
4 98
|
| 325 |
+
4 101
|
| 326 |
+
4 103
|
| 327 |
+
4 104
|
| 328 |
+
4 105
|
| 329 |
+
4 106
|
| 330 |
+
4 107
|
| 331 |
+
4 108
|
| 332 |
+
4 110
|
| 333 |
+
4 111
|
| 334 |
+
4 112
|
| 335 |
+
4 115
|
| 336 |
+
4 116
|
| 337 |
+
4 117
|
| 338 |
+
4 118
|
| 339 |
+
4 119
|
| 340 |
+
4 120
|
| 341 |
+
4 122
|
| 342 |
+
4 123
|
| 343 |
+
4 127
|
| 344 |
+
4 128
|
| 345 |
+
4 129
|
| 346 |
+
4 130
|
| 347 |
+
4 137
|
| 348 |
+
4 138
|
| 349 |
+
4 139
|
| 350 |
+
4 140
|
| 351 |
+
4 142
|
| 352 |
+
4 146
|
| 353 |
+
4 147
|
| 354 |
+
4 148
|
| 355 |
+
4 150
|
| 356 |
+
4 151
|
| 357 |
+
4 152
|
| 358 |
+
4 154
|
| 359 |
+
4 155
|
| 360 |
+
4 156
|
| 361 |
+
4 157
|
| 362 |
+
4 164
|
| 363 |
+
4 175
|
| 364 |
+
4 176
|
| 365 |
+
4 196
|
| 366 |
+
4 197
|
| 367 |
+
4 202
|
| 368 |
+
5 8
|
| 369 |
+
5 11
|
| 370 |
+
5 13
|
| 371 |
+
5 16
|
| 372 |
+
5 17
|
| 373 |
+
5 20
|
| 374 |
+
5 25
|
| 375 |
+
5 27
|
| 376 |
+
5 30
|
| 377 |
+
5 32
|
| 378 |
+
5 33
|
| 379 |
+
5 35
|
| 380 |
+
5 36
|
| 381 |
+
5 37
|
| 382 |
+
5 38
|
| 383 |
+
5 42
|
| 384 |
+
5 43
|
| 385 |
+
5 45
|
| 386 |
+
5 46
|
| 387 |
+
5 47
|
| 388 |
+
5 50
|
| 389 |
+
5 51
|
| 390 |
+
5 53
|
| 391 |
+
5 54
|
| 392 |
+
5 55
|
| 393 |
+
5 56
|
| 394 |
+
5 57
|
| 395 |
+
5 60
|
| 396 |
+
5 64
|
| 397 |
+
5 88
|
| 398 |
+
5 98
|
| 399 |
+
5 99
|
| 400 |
+
5 101
|
| 401 |
+
5 104
|
| 402 |
+
5 105
|
| 403 |
+
5 106
|
| 404 |
+
5 107
|
| 405 |
+
5 110
|
| 406 |
+
5 116
|
| 407 |
+
5 117
|
| 408 |
+
5 119
|
| 409 |
+
5 120
|
| 410 |
+
5 122
|
| 411 |
+
5 123
|
| 412 |
+
5 137
|
| 413 |
+
5 164
|
| 414 |
+
5 202
|
| 415 |
+
5 204
|
| 416 |
+
6 7
|
| 417 |
+
6 15
|
| 418 |
+
6 16
|
| 419 |
+
6 20
|
| 420 |
+
6 21
|
| 421 |
+
6 22
|
| 422 |
+
6 23
|
| 423 |
+
6 28
|
| 424 |
+
6 29
|
| 425 |
+
6 31
|
| 426 |
+
6 32
|
| 427 |
+
6 33
|
| 428 |
+
6 34
|
| 429 |
+
6 37
|
| 430 |
+
6 39
|
| 431 |
+
6 41
|
| 432 |
+
6 51
|
| 433 |
+
6 101
|
| 434 |
+
6 103
|
| 435 |
+
6 116
|
| 436 |
+
6 131
|
| 437 |
+
6 135
|
| 438 |
+
6 136
|
| 439 |
+
7 8
|
| 440 |
+
7 10
|
| 441 |
+
7 11
|
| 442 |
+
7 12
|
| 443 |
+
7 13
|
| 444 |
+
7 14
|
| 445 |
+
7 16
|
| 446 |
+
7 17
|
| 447 |
+
7 18
|
| 448 |
+
7 19
|
| 449 |
+
7 20
|
| 450 |
+
7 21
|
| 451 |
+
7 22
|
| 452 |
+
7 23
|
| 453 |
+
7 24
|
| 454 |
+
7 25
|
| 455 |
+
7 26
|
| 456 |
+
7 27
|
| 457 |
+
7 28
|
| 458 |
+
7 29
|
| 459 |
+
7 30
|
| 460 |
+
7 31
|
| 461 |
+
7 33
|
| 462 |
+
7 35
|
| 463 |
+
7 36
|
| 464 |
+
7 37
|
| 465 |
+
7 38
|
| 466 |
+
7 39
|
| 467 |
+
7 40
|
| 468 |
+
7 41
|
| 469 |
+
7 42
|
| 470 |
+
7 43
|
| 471 |
+
7 46
|
| 472 |
+
7 47
|
| 473 |
+
7 48
|
| 474 |
+
7 49
|
| 475 |
+
7 50
|
| 476 |
+
7 51
|
| 477 |
+
7 52
|
| 478 |
+
7 55
|
| 479 |
+
7 56
|
| 480 |
+
7 57
|
| 481 |
+
7 60
|
| 482 |
+
7 63
|
| 483 |
+
7 64
|
| 484 |
+
7 65
|
| 485 |
+
7 69
|
| 486 |
+
7 97
|
| 487 |
+
7 101
|
| 488 |
+
7 103
|
| 489 |
+
7 104
|
| 490 |
+
7 105
|
| 491 |
+
7 108
|
| 492 |
+
7 112
|
| 493 |
+
7 115
|
| 494 |
+
7 116
|
| 495 |
+
7 118
|
| 496 |
+
7 122
|
| 497 |
+
7 124
|
| 498 |
+
7 126
|
| 499 |
+
7 127
|
| 500 |
+
7 129
|
| 501 |
+
7 130
|
| 502 |
+
7 131
|
| 503 |
+
7 135
|
| 504 |
+
7 136
|
| 505 |
+
7 137
|
| 506 |
+
8 9
|
| 507 |
+
8 10
|
| 508 |
+
8 11
|
| 509 |
+
8 12
|
| 510 |
+
8 13
|
| 511 |
+
8 16
|
| 512 |
+
8 17
|
| 513 |
+
8 20
|
| 514 |
+
8 21
|
| 515 |
+
8 22
|
| 516 |
+
8 25
|
| 517 |
+
8 27
|
| 518 |
+
8 28
|
| 519 |
+
8 30
|
| 520 |
+
8 32
|
| 521 |
+
8 33
|
| 522 |
+
8 35
|
| 523 |
+
8 36
|
| 524 |
+
8 37
|
| 525 |
+
8 38
|
| 526 |
+
8 39
|
| 527 |
+
8 41
|
| 528 |
+
8 42
|
| 529 |
+
8 43
|
| 530 |
+
8 44
|
| 531 |
+
8 45
|
| 532 |
+
8 46
|
| 533 |
+
8 47
|
| 534 |
+
8 48
|
| 535 |
+
8 49
|
| 536 |
+
8 50
|
| 537 |
+
8 51
|
| 538 |
+
8 53
|
| 539 |
+
8 54
|
| 540 |
+
8 55
|
| 541 |
+
8 56
|
| 542 |
+
8 57
|
| 543 |
+
8 60
|
| 544 |
+
8 62
|
| 545 |
+
8 64
|
| 546 |
+
8 66
|
| 547 |
+
8 68
|
| 548 |
+
8 95
|
| 549 |
+
8 97
|
| 550 |
+
8 98
|
| 551 |
+
8 99
|
| 552 |
+
8 101
|
| 553 |
+
8 102
|
| 554 |
+
8 104
|
| 555 |
+
8 105
|
| 556 |
+
8 106
|
| 557 |
+
8 107
|
| 558 |
+
8 108
|
| 559 |
+
8 110
|
| 560 |
+
8 115
|
| 561 |
+
8 116
|
| 562 |
+
8 117
|
| 563 |
+
8 119
|
| 564 |
+
8 120
|
| 565 |
+
8 123
|
| 566 |
+
8 126
|
| 567 |
+
8 137
|
| 568 |
+
8 164
|
| 569 |
+
8 165
|
| 570 |
+
8 175
|
| 571 |
+
8 177
|
| 572 |
+
9 10
|
| 573 |
+
9 13
|
| 574 |
+
9 16
|
| 575 |
+
9 17
|
| 576 |
+
9 20
|
| 577 |
+
9 25
|
| 578 |
+
9 28
|
| 579 |
+
9 30
|
| 580 |
+
9 33
|
| 581 |
+
9 35
|
| 582 |
+
9 36
|
| 583 |
+
9 37
|
| 584 |
+
9 38
|
| 585 |
+
9 39
|
| 586 |
+
9 42
|
| 587 |
+
9 47
|
| 588 |
+
9 49
|
| 589 |
+
9 53
|
| 590 |
+
9 55
|
| 591 |
+
9 56
|
| 592 |
+
9 57
|
| 593 |
+
9 58
|
| 594 |
+
9 62
|
| 595 |
+
9 64
|
| 596 |
+
9 101
|
| 597 |
+
9 108
|
| 598 |
+
9 110
|
| 599 |
+
9 116
|
| 600 |
+
9 117
|
| 601 |
+
9 118
|
| 602 |
+
9 120
|
| 603 |
+
9 127
|
| 604 |
+
9 137
|
| 605 |
+
10 12
|
| 606 |
+
10 13
|
| 607 |
+
10 14
|
| 608 |
+
10 16
|
| 609 |
+
10 17
|
| 610 |
+
10 18
|
| 611 |
+
10 19
|
| 612 |
+
10 20
|
| 613 |
+
10 25
|
| 614 |
+
10 30
|
| 615 |
+
10 32
|
| 616 |
+
10 33
|
| 617 |
+
10 36
|
| 618 |
+
10 37
|
| 619 |
+
10 38
|
| 620 |
+
10 39
|
| 621 |
+
10 41
|
| 622 |
+
10 42
|
| 623 |
+
10 46
|
| 624 |
+
10 47
|
| 625 |
+
10 48
|
| 626 |
+
10 51
|
| 627 |
+
10 53
|
| 628 |
+
10 55
|
| 629 |
+
10 56
|
| 630 |
+
10 57
|
| 631 |
+
10 62
|
| 632 |
+
10 64
|
| 633 |
+
10 95
|
| 634 |
+
10 97
|
| 635 |
+
10 101
|
| 636 |
+
10 103
|
| 637 |
+
10 116
|
| 638 |
+
10 126
|
| 639 |
+
10 127
|
| 640 |
+
10 165
|
| 641 |
+
10 208
|
| 642 |
+
11 13
|
| 643 |
+
11 15
|
| 644 |
+
11 16
|
| 645 |
+
11 17
|
| 646 |
+
11 18
|
| 647 |
+
11 20
|
| 648 |
+
11 21
|
| 649 |
+
11 22
|
| 650 |
+
11 23
|
| 651 |
+
11 25
|
| 652 |
+
11 28
|
| 653 |
+
11 30
|
| 654 |
+
11 33
|
| 655 |
+
11 35
|
| 656 |
+
11 36
|
| 657 |
+
11 37
|
| 658 |
+
11 38
|
| 659 |
+
11 41
|
| 660 |
+
11 42
|
| 661 |
+
11 43
|
| 662 |
+
11 45
|
| 663 |
+
11 46
|
| 664 |
+
11 47
|
| 665 |
+
11 48
|
| 666 |
+
11 49
|
| 667 |
+
11 50
|
| 668 |
+
11 51
|
| 669 |
+
11 53
|
| 670 |
+
11 54
|
| 671 |
+
11 55
|
| 672 |
+
11 56
|
| 673 |
+
11 57
|
| 674 |
+
11 97
|
| 675 |
+
11 99
|
| 676 |
+
11 103
|
| 677 |
+
11 104
|
| 678 |
+
11 105
|
| 679 |
+
11 106
|
| 680 |
+
11 107
|
| 681 |
+
11 108
|
| 682 |
+
11 110
|
| 683 |
+
11 112
|
| 684 |
+
11 117
|
| 685 |
+
11 119
|
| 686 |
+
11 120
|
| 687 |
+
11 123
|
| 688 |
+
11 131
|
| 689 |
+
11 164
|
| 690 |
+
11 175
|
| 691 |
+
12 15
|
| 692 |
+
12 16
|
| 693 |
+
12 21
|
| 694 |
+
12 23
|
| 695 |
+
12 25
|
| 696 |
+
12 33
|
| 697 |
+
12 35
|
| 698 |
+
12 36
|
| 699 |
+
12 37
|
| 700 |
+
12 38
|
| 701 |
+
12 43
|
| 702 |
+
12 47
|
| 703 |
+
12 49
|
| 704 |
+
12 50
|
| 705 |
+
12 51
|
| 706 |
+
12 53
|
| 707 |
+
12 56
|
| 708 |
+
12 97
|
| 709 |
+
12 101
|
| 710 |
+
12 104
|
| 711 |
+
12 106
|
| 712 |
+
12 110
|
| 713 |
+
12 117
|
| 714 |
+
13 15
|
| 715 |
+
13 16
|
| 716 |
+
13 17
|
| 717 |
+
13 18
|
| 718 |
+
13 20
|
| 719 |
+
13 21
|
| 720 |
+
13 22
|
| 721 |
+
13 23
|
| 722 |
+
13 25
|
| 723 |
+
13 27
|
| 724 |
+
13 28
|
| 725 |
+
13 30
|
| 726 |
+
13 32
|
| 727 |
+
13 33
|
| 728 |
+
13 34
|
| 729 |
+
13 35
|
| 730 |
+
13 36
|
| 731 |
+
13 37
|
| 732 |
+
13 38
|
| 733 |
+
13 39
|
| 734 |
+
13 41
|
| 735 |
+
13 43
|
| 736 |
+
13 44
|
| 737 |
+
13 45
|
| 738 |
+
13 46
|
| 739 |
+
13 47
|
| 740 |
+
13 48
|
| 741 |
+
13 49
|
| 742 |
+
13 50
|
| 743 |
+
13 51
|
| 744 |
+
13 52
|
| 745 |
+
13 53
|
| 746 |
+
13 54
|
| 747 |
+
13 55
|
| 748 |
+
13 56
|
| 749 |
+
13 57
|
| 750 |
+
13 60
|
| 751 |
+
13 61
|
| 752 |
+
13 63
|
| 753 |
+
13 65
|
| 754 |
+
13 69
|
| 755 |
+
13 80
|
| 756 |
+
13 87
|
| 757 |
+
13 95
|
| 758 |
+
13 97
|
| 759 |
+
13 98
|
| 760 |
+
13 99
|
| 761 |
+
13 100
|
| 762 |
+
13 101
|
| 763 |
+
13 103
|
| 764 |
+
13 104
|
| 765 |
+
13 105
|
| 766 |
+
13 106
|
| 767 |
+
13 107
|
| 768 |
+
13 108
|
| 769 |
+
13 110
|
| 770 |
+
13 111
|
| 771 |
+
13 112
|
| 772 |
+
13 115
|
| 773 |
+
13 116
|
| 774 |
+
13 117
|
| 775 |
+
13 118
|
| 776 |
+
13 119
|
| 777 |
+
13 120
|
| 778 |
+
13 121
|
| 779 |
+
13 122
|
| 780 |
+
13 123
|
| 781 |
+
13 126
|
| 782 |
+
13 127
|
| 783 |
+
13 128
|
| 784 |
+
13 137
|
| 785 |
+
13 154
|
| 786 |
+
13 155
|
| 787 |
+
13 156
|
| 788 |
+
13 157
|
| 789 |
+
13 164
|
| 790 |
+
13 175
|
| 791 |
+
13 196
|
| 792 |
+
14 15
|
| 793 |
+
14 16
|
| 794 |
+
14 19
|
| 795 |
+
14 20
|
| 796 |
+
14 21
|
| 797 |
+
14 29
|
| 798 |
+
14 30
|
| 799 |
+
14 31
|
| 800 |
+
14 32
|
| 801 |
+
14 34
|
| 802 |
+
14 37
|
| 803 |
+
14 51
|
| 804 |
+
14 57
|
| 805 |
+
14 101
|
| 806 |
+
14 103
|
| 807 |
+
14 116
|
| 808 |
+
14 118
|
| 809 |
+
14 122
|
| 810 |
+
14 126
|
| 811 |
+
14 127
|
| 812 |
+
14 162
|
| 813 |
+
15 16
|
| 814 |
+
15 17
|
| 815 |
+
15 18
|
| 816 |
+
15 19
|
| 817 |
+
15 20
|
| 818 |
+
15 21
|
| 819 |
+
15 22
|
| 820 |
+
15 23
|
| 821 |
+
15 24
|
| 822 |
+
15 25
|
| 823 |
+
15 26
|
| 824 |
+
15 27
|
| 825 |
+
15 28
|
| 826 |
+
15 29
|
| 827 |
+
15 30
|
| 828 |
+
15 31
|
| 829 |
+
15 33
|
| 830 |
+
15 35
|
| 831 |
+
15 37
|
| 832 |
+
15 38
|
| 833 |
+
15 39
|
| 834 |
+
15 40
|
| 835 |
+
15 41
|
| 836 |
+
15 42
|
| 837 |
+
15 43
|
| 838 |
+
15 46
|
| 839 |
+
15 47
|
| 840 |
+
15 49
|
| 841 |
+
15 50
|
| 842 |
+
15 51
|
| 843 |
+
15 54
|
| 844 |
+
15 56
|
| 845 |
+
15 60
|
| 846 |
+
15 63
|
| 847 |
+
15 64
|
| 848 |
+
15 68
|
| 849 |
+
15 69
|
| 850 |
+
15 97
|
| 851 |
+
15 99
|
| 852 |
+
15 101
|
| 853 |
+
15 102
|
| 854 |
+
15 103
|
| 855 |
+
15 104
|
| 856 |
+
15 105
|
| 857 |
+
15 108
|
| 858 |
+
15 112
|
| 859 |
+
15 114
|
| 860 |
+
15 115
|
| 861 |
+
15 116
|
| 862 |
+
15 118
|
| 863 |
+
15 122
|
| 864 |
+
15 126
|
| 865 |
+
15 127
|
| 866 |
+
15 128
|
| 867 |
+
15 129
|
| 868 |
+
15 130
|
| 869 |
+
15 131
|
| 870 |
+
15 135
|
| 871 |
+
15 136
|
| 872 |
+
15 158
|
| 873 |
+
16 17
|
| 874 |
+
16 18
|
| 875 |
+
16 19
|
| 876 |
+
16 20
|
| 877 |
+
16 21
|
| 878 |
+
16 22
|
| 879 |
+
16 23
|
| 880 |
+
16 24
|
| 881 |
+
16 25
|
| 882 |
+
16 26
|
| 883 |
+
16 27
|
| 884 |
+
16 28
|
| 885 |
+
16 29
|
| 886 |
+
16 30
|
| 887 |
+
16 31
|
| 888 |
+
16 32
|
| 889 |
+
16 33
|
| 890 |
+
16 34
|
| 891 |
+
16 35
|
| 892 |
+
16 36
|
| 893 |
+
16 37
|
| 894 |
+
16 38
|
| 895 |
+
16 39
|
| 896 |
+
16 40
|
| 897 |
+
16 41
|
| 898 |
+
16 42
|
| 899 |
+
16 43
|
| 900 |
+
16 44
|
| 901 |
+
16 45
|
| 902 |
+
16 46
|
| 903 |
+
16 47
|
| 904 |
+
16 48
|
| 905 |
+
16 49
|
| 906 |
+
16 50
|
| 907 |
+
16 51
|
| 908 |
+
16 52
|
| 909 |
+
16 53
|
| 910 |
+
16 54
|
| 911 |
+
16 55
|
| 912 |
+
16 56
|
| 913 |
+
16 57
|
| 914 |
+
16 60
|
| 915 |
+
16 62
|
| 916 |
+
16 64
|
| 917 |
+
16 65
|
| 918 |
+
16 66
|
| 919 |
+
16 68
|
| 920 |
+
16 69
|
| 921 |
+
16 70
|
| 922 |
+
16 71
|
| 923 |
+
16 73
|
| 924 |
+
16 74
|
| 925 |
+
16 80
|
| 926 |
+
16 81
|
| 927 |
+
16 87
|
| 928 |
+
16 91
|
| 929 |
+
16 92
|
| 930 |
+
16 93
|
| 931 |
+
16 94
|
| 932 |
+
16 95
|
| 933 |
+
16 96
|
| 934 |
+
16 97
|
| 935 |
+
16 98
|
| 936 |
+
16 99
|
| 937 |
+
16 100
|
| 938 |
+
16 101
|
| 939 |
+
16 102
|
| 940 |
+
16 103
|
| 941 |
+
16 104
|
| 942 |
+
16 105
|
| 943 |
+
16 106
|
| 944 |
+
16 107
|
| 945 |
+
16 108
|
| 946 |
+
16 109
|
| 947 |
+
16 110
|
| 948 |
+
16 111
|
| 949 |
+
16 112
|
| 950 |
+
16 113
|
| 951 |
+
16 114
|
| 952 |
+
16 115
|
| 953 |
+
16 116
|
| 954 |
+
16 117
|
| 955 |
+
16 118
|
| 956 |
+
16 119
|
| 957 |
+
16 120
|
| 958 |
+
16 121
|
| 959 |
+
16 122
|
| 960 |
+
16 123
|
| 961 |
+
16 124
|
| 962 |
+
16 126
|
| 963 |
+
16 127
|
| 964 |
+
16 128
|
| 965 |
+
16 129
|
| 966 |
+
16 131
|
| 967 |
+
16 133
|
| 968 |
+
16 134
|
| 969 |
+
16 137
|
| 970 |
+
16 138
|
| 971 |
+
16 139
|
| 972 |
+
16 140
|
| 973 |
+
16 142
|
| 974 |
+
16 145
|
| 975 |
+
16 146
|
| 976 |
+
16 147
|
| 977 |
+
16 148
|
| 978 |
+
16 149
|
| 979 |
+
16 150
|
| 980 |
+
16 151
|
| 981 |
+
16 152
|
| 982 |
+
16 154
|
| 983 |
+
16 160
|
| 984 |
+
16 162
|
| 985 |
+
16 164
|
| 986 |
+
16 165
|
| 987 |
+
16 175
|
| 988 |
+
16 176
|
| 989 |
+
16 177
|
| 990 |
+
16 183
|
| 991 |
+
16 197
|
| 992 |
+
16 202
|
| 993 |
+
16 204
|
| 994 |
+
16 214
|
| 995 |
+
17 18
|
| 996 |
+
17 19
|
| 997 |
+
17 20
|
| 998 |
+
17 21
|
| 999 |
+
17 22
|
| 1000 |
+
17 23
|
| 1001 |
+
17 25
|
| 1002 |
+
17 27
|
| 1003 |
+
17 28
|
| 1004 |
+
17 29
|
| 1005 |
+
17 30
|
| 1006 |
+
17 31
|
| 1007 |
+
17 32
|
| 1008 |
+
17 33
|
| 1009 |
+
17 34
|
| 1010 |
+
17 35
|
| 1011 |
+
17 36
|
| 1012 |
+
17 37
|
| 1013 |
+
17 38
|
| 1014 |
+
17 39
|
| 1015 |
+
17 40
|
| 1016 |
+
17 41
|
| 1017 |
+
17 42
|
| 1018 |
+
17 43
|
| 1019 |
+
17 47
|
| 1020 |
+
17 50
|
| 1021 |
+
17 51
|
| 1022 |
+
17 53
|
| 1023 |
+
17 54
|
| 1024 |
+
17 55
|
| 1025 |
+
17 56
|
| 1026 |
+
17 57
|
| 1027 |
+
17 60
|
| 1028 |
+
17 62
|
| 1029 |
+
17 64
|
| 1030 |
+
17 95
|
| 1031 |
+
17 97
|
| 1032 |
+
17 98
|
| 1033 |
+
17 99
|
| 1034 |
+
17 101
|
| 1035 |
+
17 103
|
| 1036 |
+
17 104
|
| 1037 |
+
17 105
|
| 1038 |
+
17 106
|
| 1039 |
+
17 110
|
| 1040 |
+
17 112
|
| 1041 |
+
17 115
|
| 1042 |
+
17 116
|
| 1043 |
+
17 117
|
| 1044 |
+
17 118
|
| 1045 |
+
17 122
|
| 1046 |
+
17 127
|
| 1047 |
+
17 128
|
| 1048 |
+
17 129
|
| 1049 |
+
17 131
|
| 1050 |
+
17 137
|
| 1051 |
+
17 164
|
| 1052 |
+
17 165
|
| 1053 |
+
17 197
|
| 1054 |
+
18 21
|
| 1055 |
+
18 22
|
| 1056 |
+
18 23
|
| 1057 |
+
18 25
|
| 1058 |
+
18 28
|
| 1059 |
+
18 30
|
| 1060 |
+
18 32
|
| 1061 |
+
18 33
|
| 1062 |
+
18 35
|
| 1063 |
+
18 36
|
| 1064 |
+
18 38
|
| 1065 |
+
18 43
|
| 1066 |
+
18 46
|
| 1067 |
+
18 47
|
| 1068 |
+
18 48
|
| 1069 |
+
18 49
|
| 1070 |
+
18 53
|
| 1071 |
+
18 55
|
| 1072 |
+
18 57
|
| 1073 |
+
18 95
|
| 1074 |
+
18 97
|
| 1075 |
+
18 104
|
| 1076 |
+
18 106
|
| 1077 |
+
18 107
|
| 1078 |
+
18 108
|
| 1079 |
+
19 21
|
| 1080 |
+
19 22
|
| 1081 |
+
19 23
|
| 1082 |
+
19 25
|
| 1083 |
+
19 27
|
| 1084 |
+
19 28
|
| 1085 |
+
19 30
|
| 1086 |
+
19 32
|
| 1087 |
+
19 33
|
| 1088 |
+
19 34
|
| 1089 |
+
19 35
|
| 1090 |
+
19 38
|
| 1091 |
+
19 40
|
| 1092 |
+
19 41
|
| 1093 |
+
19 47
|
| 1094 |
+
19 50
|
| 1095 |
+
19 51
|
| 1096 |
+
19 101
|
| 1097 |
+
19 103
|
| 1098 |
+
19 112
|
| 1099 |
+
19 116
|
| 1100 |
+
19 126
|
| 1101 |
+
19 129
|
| 1102 |
+
19 158
|
| 1103 |
+
19 168
|
| 1104 |
+
19 170
|
| 1105 |
+
20 21
|
| 1106 |
+
20 22
|
| 1107 |
+
20 23
|
| 1108 |
+
20 25
|
| 1109 |
+
20 27
|
| 1110 |
+
20 28
|
| 1111 |
+
20 30
|
| 1112 |
+
20 31
|
| 1113 |
+
20 32
|
| 1114 |
+
20 33
|
| 1115 |
+
20 34
|
| 1116 |
+
20 35
|
| 1117 |
+
20 36
|
| 1118 |
+
20 38
|
| 1119 |
+
20 39
|
| 1120 |
+
20 40
|
| 1121 |
+
20 41
|
| 1122 |
+
20 42
|
| 1123 |
+
20 43
|
| 1124 |
+
20 44
|
| 1125 |
+
20 47
|
| 1126 |
+
20 50
|
| 1127 |
+
20 51
|
| 1128 |
+
20 53
|
| 1129 |
+
20 54
|
| 1130 |
+
20 55
|
| 1131 |
+
20 56
|
| 1132 |
+
20 57
|
| 1133 |
+
20 59
|
| 1134 |
+
20 60
|
| 1135 |
+
20 62
|
| 1136 |
+
20 63
|
| 1137 |
+
20 64
|
| 1138 |
+
20 65
|
| 1139 |
+
20 66
|
| 1140 |
+
20 69
|
| 1141 |
+
20 80
|
| 1142 |
+
20 85
|
| 1143 |
+
20 87
|
| 1144 |
+
20 97
|
| 1145 |
+
20 98
|
| 1146 |
+
20 99
|
| 1147 |
+
20 100
|
| 1148 |
+
20 101
|
| 1149 |
+
20 103
|
| 1150 |
+
20 104
|
| 1151 |
+
20 105
|
| 1152 |
+
20 106
|
| 1153 |
+
20 110
|
| 1154 |
+
20 111
|
| 1155 |
+
20 116
|
| 1156 |
+
20 117
|
| 1157 |
+
20 120
|
| 1158 |
+
20 121
|
| 1159 |
+
20 123
|
| 1160 |
+
20 126
|
| 1161 |
+
20 131
|
| 1162 |
+
20 137
|
| 1163 |
+
20 161
|
| 1164 |
+
21 24
|
| 1165 |
+
21 25
|
| 1166 |
+
21 26
|
| 1167 |
+
21 27
|
| 1168 |
+
21 29
|
| 1169 |
+
21 31
|
| 1170 |
+
21 32
|
| 1171 |
+
21 33
|
| 1172 |
+
21 34
|
| 1173 |
+
21 35
|
| 1174 |
+
21 36
|
| 1175 |
+
21 37
|
| 1176 |
+
21 38
|
| 1177 |
+
21 39
|
| 1178 |
+
21 40
|
| 1179 |
+
21 41
|
| 1180 |
+
21 42
|
| 1181 |
+
21 43
|
| 1182 |
+
21 44
|
| 1183 |
+
21 46
|
| 1184 |
+
21 47
|
| 1185 |
+
21 48
|
| 1186 |
+
21 49
|
| 1187 |
+
21 50
|
| 1188 |
+
21 51
|
| 1189 |
+
21 52
|
| 1190 |
+
21 54
|
| 1191 |
+
21 55
|
| 1192 |
+
21 57
|
| 1193 |
+
21 64
|
| 1194 |
+
21 69
|
| 1195 |
+
21 80
|
| 1196 |
+
21 96
|
| 1197 |
+
21 97
|
| 1198 |
+
21 99
|
| 1199 |
+
21 100
|
| 1200 |
+
21 101
|
| 1201 |
+
21 103
|
| 1202 |
+
21 104
|
| 1203 |
+
21 105
|
| 1204 |
+
21 107
|
| 1205 |
+
21 108
|
| 1206 |
+
21 111
|
| 1207 |
+
21 112
|
| 1208 |
+
21 113
|
| 1209 |
+
21 114
|
| 1210 |
+
21 115
|
| 1211 |
+
21 116
|
| 1212 |
+
21 117
|
| 1213 |
+
21 118
|
| 1214 |
+
21 121
|
| 1215 |
+
21 122
|
| 1216 |
+
21 124
|
| 1217 |
+
21 126
|
| 1218 |
+
21 128
|
| 1219 |
+
21 129
|
| 1220 |
+
21 130
|
| 1221 |
+
21 131
|
| 1222 |
+
21 135
|
| 1223 |
+
21 136
|
| 1224 |
+
21 164
|
| 1225 |
+
22 25
|
| 1226 |
+
22 26
|
| 1227 |
+
22 27
|
| 1228 |
+
22 29
|
| 1229 |
+
22 31
|
| 1230 |
+
22 32
|
| 1231 |
+
22 33
|
| 1232 |
+
22 34
|
| 1233 |
+
22 35
|
| 1234 |
+
22 37
|
| 1235 |
+
22 38
|
| 1236 |
+
22 39
|
| 1237 |
+
22 40
|
| 1238 |
+
22 41
|
| 1239 |
+
22 43
|
| 1240 |
+
22 44
|
| 1241 |
+
22 46
|
| 1242 |
+
22 47
|
| 1243 |
+
22 48
|
| 1244 |
+
22 49
|
| 1245 |
+
22 50
|
| 1246 |
+
22 51
|
| 1247 |
+
22 55
|
| 1248 |
+
22 57
|
| 1249 |
+
22 64
|
| 1250 |
+
22 69
|
| 1251 |
+
22 80
|
| 1252 |
+
22 95
|
| 1253 |
+
22 97
|
| 1254 |
+
22 99
|
| 1255 |
+
22 100
|
| 1256 |
+
22 101
|
| 1257 |
+
22 103
|
| 1258 |
+
22 104
|
| 1259 |
+
22 105
|
| 1260 |
+
22 107
|
| 1261 |
+
22 108
|
| 1262 |
+
22 111
|
| 1263 |
+
22 112
|
| 1264 |
+
22 114
|
| 1265 |
+
22 115
|
| 1266 |
+
22 116
|
| 1267 |
+
22 117
|
| 1268 |
+
22 121
|
| 1269 |
+
22 122
|
| 1270 |
+
22 126
|
| 1271 |
+
22 128
|
| 1272 |
+
22 129
|
| 1273 |
+
22 131
|
| 1274 |
+
22 136
|
| 1275 |
+
23 24
|
| 1276 |
+
23 25
|
| 1277 |
+
23 26
|
| 1278 |
+
23 27
|
| 1279 |
+
23 29
|
| 1280 |
+
23 31
|
| 1281 |
+
23 32
|
| 1282 |
+
23 33
|
| 1283 |
+
23 34
|
| 1284 |
+
23 35
|
| 1285 |
+
23 36
|
| 1286 |
+
23 37
|
| 1287 |
+
23 38
|
| 1288 |
+
23 39
|
| 1289 |
+
23 40
|
| 1290 |
+
23 41
|
| 1291 |
+
23 43
|
| 1292 |
+
23 46
|
| 1293 |
+
23 47
|
| 1294 |
+
23 48
|
| 1295 |
+
23 50
|
| 1296 |
+
23 51
|
| 1297 |
+
23 54
|
| 1298 |
+
23 59
|
| 1299 |
+
23 63
|
| 1300 |
+
23 65
|
| 1301 |
+
23 68
|
| 1302 |
+
23 69
|
| 1303 |
+
23 80
|
| 1304 |
+
23 83
|
| 1305 |
+
23 85
|
| 1306 |
+
23 97
|
| 1307 |
+
23 99
|
| 1308 |
+
23 100
|
| 1309 |
+
23 101
|
| 1310 |
+
23 102
|
| 1311 |
+
23 103
|
| 1312 |
+
23 104
|
| 1313 |
+
23 105
|
| 1314 |
+
23 107
|
| 1315 |
+
23 108
|
| 1316 |
+
23 111
|
| 1317 |
+
23 112
|
| 1318 |
+
23 114
|
| 1319 |
+
23 115
|
| 1320 |
+
23 116
|
| 1321 |
+
23 117
|
| 1322 |
+
23 118
|
| 1323 |
+
23 121
|
| 1324 |
+
23 122
|
| 1325 |
+
23 124
|
| 1326 |
+
23 126
|
| 1327 |
+
23 127
|
| 1328 |
+
23 128
|
| 1329 |
+
23 129
|
| 1330 |
+
23 130
|
| 1331 |
+
23 131
|
| 1332 |
+
23 135
|
| 1333 |
+
23 136
|
| 1334 |
+
23 158
|
| 1335 |
+
23 162
|
| 1336 |
+
24 27
|
| 1337 |
+
24 28
|
| 1338 |
+
24 29
|
| 1339 |
+
24 31
|
| 1340 |
+
24 32
|
| 1341 |
+
24 34
|
| 1342 |
+
24 35
|
| 1343 |
+
24 39
|
| 1344 |
+
24 40
|
| 1345 |
+
24 43
|
| 1346 |
+
24 51
|
| 1347 |
+
24 59
|
| 1348 |
+
24 63
|
| 1349 |
+
24 65
|
| 1350 |
+
24 69
|
| 1351 |
+
24 80
|
| 1352 |
+
24 85
|
| 1353 |
+
24 97
|
| 1354 |
+
24 101
|
| 1355 |
+
24 103
|
| 1356 |
+
24 111
|
| 1357 |
+
24 114
|
| 1358 |
+
24 115
|
| 1359 |
+
24 116
|
| 1360 |
+
24 122
|
| 1361 |
+
24 126
|
| 1362 |
+
24 130
|
| 1363 |
+
24 161
|
| 1364 |
+
25 27
|
| 1365 |
+
25 28
|
| 1366 |
+
25 29
|
| 1367 |
+
25 30
|
| 1368 |
+
25 31
|
| 1369 |
+
25 32
|
| 1370 |
+
25 33
|
| 1371 |
+
25 34
|
| 1372 |
+
25 35
|
| 1373 |
+
25 36
|
| 1374 |
+
25 37
|
| 1375 |
+
25 38
|
| 1376 |
+
25 39
|
| 1377 |
+
25 40
|
| 1378 |
+
25 41
|
| 1379 |
+
25 42
|
| 1380 |
+
25 43
|
| 1381 |
+
25 44
|
| 1382 |
+
25 45
|
| 1383 |
+
25 46
|
| 1384 |
+
25 47
|
| 1385 |
+
25 48
|
| 1386 |
+
25 49
|
| 1387 |
+
25 50
|
| 1388 |
+
25 51
|
| 1389 |
+
25 53
|
| 1390 |
+
25 54
|
| 1391 |
+
25 55
|
| 1392 |
+
25 56
|
| 1393 |
+
25 57
|
| 1394 |
+
25 60
|
| 1395 |
+
25 62
|
| 1396 |
+
25 63
|
| 1397 |
+
25 64
|
| 1398 |
+
25 65
|
| 1399 |
+
25 66
|
| 1400 |
+
25 68
|
| 1401 |
+
25 69
|
| 1402 |
+
25 71
|
| 1403 |
+
25 80
|
| 1404 |
+
25 87
|
| 1405 |
+
25 91
|
| 1406 |
+
25 92
|
| 1407 |
+
25 94
|
| 1408 |
+
25 97
|
| 1409 |
+
25 98
|
| 1410 |
+
25 99
|
| 1411 |
+
25 100
|
| 1412 |
+
25 102
|
| 1413 |
+
25 103
|
| 1414 |
+
25 104
|
| 1415 |
+
25 105
|
| 1416 |
+
25 106
|
| 1417 |
+
25 107
|
| 1418 |
+
25 108
|
| 1419 |
+
25 110
|
| 1420 |
+
25 111
|
| 1421 |
+
25 112
|
| 1422 |
+
25 114
|
| 1423 |
+
25 115
|
| 1424 |
+
25 116
|
| 1425 |
+
25 117
|
| 1426 |
+
25 118
|
| 1427 |
+
25 119
|
| 1428 |
+
25 120
|
| 1429 |
+
25 121
|
| 1430 |
+
25 122
|
| 1431 |
+
25 123
|
| 1432 |
+
25 124
|
| 1433 |
+
25 126
|
| 1434 |
+
25 127
|
| 1435 |
+
25 128
|
| 1436 |
+
25 129
|
| 1437 |
+
25 131
|
| 1438 |
+
25 137
|
| 1439 |
+
25 139
|
| 1440 |
+
25 150
|
| 1441 |
+
25 151
|
| 1442 |
+
25 152
|
| 1443 |
+
25 154
|
| 1444 |
+
25 164
|
| 1445 |
+
25 165
|
| 1446 |
+
25 175
|
| 1447 |
+
25 176
|
| 1448 |
+
25 202
|
| 1449 |
+
25 204
|
| 1450 |
+
25 214
|
| 1451 |
+
26 28
|
| 1452 |
+
26 31
|
| 1453 |
+
26 32
|
| 1454 |
+
26 33
|
| 1455 |
+
26 34
|
| 1456 |
+
26 38
|
| 1457 |
+
26 39
|
| 1458 |
+
26 41
|
| 1459 |
+
26 48
|
| 1460 |
+
26 51
|
| 1461 |
+
26 68
|
| 1462 |
+
26 112
|
| 1463 |
+
26 131
|
| 1464 |
+
26 135
|
| 1465 |
+
26 136
|
| 1466 |
+
27 28
|
| 1467 |
+
27 30
|
| 1468 |
+
27 32
|
| 1469 |
+
27 33
|
| 1470 |
+
27 34
|
| 1471 |
+
27 35
|
| 1472 |
+
27 37
|
| 1473 |
+
27 38
|
| 1474 |
+
27 41
|
| 1475 |
+
27 42
|
| 1476 |
+
27 43
|
| 1477 |
+
27 46
|
| 1478 |
+
27 47
|
| 1479 |
+
27 50
|
| 1480 |
+
27 51
|
| 1481 |
+
27 64
|
| 1482 |
+
27 80
|
| 1483 |
+
27 97
|
| 1484 |
+
27 98
|
| 1485 |
+
27 101
|
| 1486 |
+
27 102
|
| 1487 |
+
27 103
|
| 1488 |
+
27 105
|
| 1489 |
+
27 106
|
| 1490 |
+
27 107
|
| 1491 |
+
27 108
|
| 1492 |
+
27 111
|
| 1493 |
+
27 112
|
| 1494 |
+
27 115
|
| 1495 |
+
27 116
|
| 1496 |
+
27 118
|
| 1497 |
+
27 122
|
| 1498 |
+
27 126
|
| 1499 |
+
27 127
|
| 1500 |
+
27 128
|
| 1501 |
+
27 129
|
| 1502 |
+
27 131
|
| 1503 |
+
28 29
|
| 1504 |
+
28 31
|
| 1505 |
+
28 32
|
| 1506 |
+
28 33
|
| 1507 |
+
28 34
|
| 1508 |
+
28 35
|
| 1509 |
+
28 36
|
| 1510 |
+
28 37
|
| 1511 |
+
28 38
|
| 1512 |
+
28 39
|
| 1513 |
+
28 40
|
| 1514 |
+
28 41
|
| 1515 |
+
28 42
|
| 1516 |
+
28 43
|
| 1517 |
+
28 44
|
| 1518 |
+
28 46
|
| 1519 |
+
28 47
|
| 1520 |
+
28 48
|
| 1521 |
+
28 49
|
| 1522 |
+
28 50
|
| 1523 |
+
28 51
|
| 1524 |
+
28 52
|
| 1525 |
+
28 54
|
| 1526 |
+
28 55
|
| 1527 |
+
28 56
|
| 1528 |
+
28 57
|
| 1529 |
+
28 64
|
| 1530 |
+
28 68
|
| 1531 |
+
28 69
|
| 1532 |
+
28 80
|
| 1533 |
+
28 95
|
| 1534 |
+
28 96
|
| 1535 |
+
28 97
|
| 1536 |
+
28 99
|
| 1537 |
+
28 100
|
| 1538 |
+
28 101
|
| 1539 |
+
28 102
|
| 1540 |
+
28 103
|
| 1541 |
+
28 104
|
| 1542 |
+
28 105
|
| 1543 |
+
28 107
|
| 1544 |
+
28 108
|
| 1545 |
+
28 111
|
| 1546 |
+
28 112
|
| 1547 |
+
28 113
|
| 1548 |
+
28 114
|
| 1549 |
+
28 115
|
| 1550 |
+
28 116
|
| 1551 |
+
28 117
|
| 1552 |
+
28 120
|
| 1553 |
+
28 121
|
| 1554 |
+
28 122
|
| 1555 |
+
28 124
|
| 1556 |
+
28 126
|
| 1557 |
+
28 128
|
| 1558 |
+
28 129
|
| 1559 |
+
28 131
|
| 1560 |
+
28 135
|
| 1561 |
+
28 136
|
| 1562 |
+
28 164
|
| 1563 |
+
28 175
|
| 1564 |
+
29 30
|
| 1565 |
+
29 31
|
| 1566 |
+
29 32
|
| 1567 |
+
29 33
|
| 1568 |
+
29 34
|
| 1569 |
+
29 35
|
| 1570 |
+
29 36
|
| 1571 |
+
29 39
|
| 1572 |
+
29 40
|
| 1573 |
+
29 41
|
| 1574 |
+
29 47
|
| 1575 |
+
29 50
|
| 1576 |
+
29 51
|
| 1577 |
+
29 101
|
| 1578 |
+
29 103
|
| 1579 |
+
29 112
|
| 1580 |
+
29 115
|
| 1581 |
+
29 116
|
| 1582 |
+
29 126
|
| 1583 |
+
29 129
|
| 1584 |
+
29 158
|
| 1585 |
+
29 168
|
| 1586 |
+
30 32
|
| 1587 |
+
30 33
|
| 1588 |
+
30 35
|
| 1589 |
+
30 36
|
| 1590 |
+
30 37
|
| 1591 |
+
30 38
|
| 1592 |
+
30 39
|
| 1593 |
+
30 41
|
| 1594 |
+
30 42
|
| 1595 |
+
30 43
|
| 1596 |
+
30 45
|
| 1597 |
+
30 47
|
| 1598 |
+
30 50
|
| 1599 |
+
30 51
|
| 1600 |
+
30 53
|
| 1601 |
+
30 54
|
| 1602 |
+
30 55
|
| 1603 |
+
30 56
|
| 1604 |
+
30 57
|
| 1605 |
+
30 59
|
| 1606 |
+
30 60
|
| 1607 |
+
30 62
|
| 1608 |
+
30 63
|
| 1609 |
+
30 64
|
| 1610 |
+
30 65
|
| 1611 |
+
30 68
|
| 1612 |
+
30 69
|
| 1613 |
+
30 80
|
| 1614 |
+
30 85
|
| 1615 |
+
30 87
|
| 1616 |
+
30 95
|
| 1617 |
+
30 97
|
| 1618 |
+
30 98
|
| 1619 |
+
30 101
|
| 1620 |
+
30 103
|
| 1621 |
+
30 104
|
| 1622 |
+
30 105
|
| 1623 |
+
30 106
|
| 1624 |
+
30 107
|
| 1625 |
+
30 108
|
| 1626 |
+
30 110
|
| 1627 |
+
30 111
|
| 1628 |
+
30 112
|
| 1629 |
+
30 115
|
| 1630 |
+
30 116
|
| 1631 |
+
30 117
|
| 1632 |
+
30 118
|
| 1633 |
+
30 119
|
| 1634 |
+
30 120
|
| 1635 |
+
30 122
|
| 1636 |
+
30 123
|
| 1637 |
+
30 126
|
| 1638 |
+
30 127
|
| 1639 |
+
30 128
|
| 1640 |
+
30 129
|
| 1641 |
+
30 137
|
| 1642 |
+
30 139
|
| 1643 |
+
30 158
|
| 1644 |
+
30 164
|
| 1645 |
+
30 165
|
| 1646 |
+
30 202
|
| 1647 |
+
31 32
|
| 1648 |
+
31 34
|
| 1649 |
+
31 35
|
| 1650 |
+
31 37
|
| 1651 |
+
31 38
|
| 1652 |
+
31 39
|
| 1653 |
+
31 40
|
| 1654 |
+
31 41
|
| 1655 |
+
31 46
|
| 1656 |
+
31 47
|
| 1657 |
+
31 50
|
| 1658 |
+
31 55
|
| 1659 |
+
31 57
|
| 1660 |
+
31 69
|
| 1661 |
+
31 101
|
| 1662 |
+
31 103
|
| 1663 |
+
31 112
|
| 1664 |
+
31 116
|
| 1665 |
+
31 118
|
| 1666 |
+
31 122
|
| 1667 |
+
31 126
|
| 1668 |
+
31 127
|
| 1669 |
+
31 129
|
| 1670 |
+
31 131
|
| 1671 |
+
31 162
|
| 1672 |
+
32 33
|
| 1673 |
+
32 35
|
| 1674 |
+
32 36
|
| 1675 |
+
32 37
|
| 1676 |
+
32 38
|
| 1677 |
+
32 39
|
| 1678 |
+
32 40
|
| 1679 |
+
32 41
|
| 1680 |
+
32 42
|
| 1681 |
+
32 43
|
| 1682 |
+
32 46
|
| 1683 |
+
32 47
|
| 1684 |
+
32 50
|
| 1685 |
+
32 51
|
| 1686 |
+
32 53
|
| 1687 |
+
32 54
|
| 1688 |
+
32 55
|
| 1689 |
+
32 56
|
| 1690 |
+
32 57
|
| 1691 |
+
32 62
|
| 1692 |
+
32 64
|
| 1693 |
+
32 65
|
| 1694 |
+
32 68
|
| 1695 |
+
32 69
|
| 1696 |
+
32 80
|
| 1697 |
+
32 97
|
| 1698 |
+
32 101
|
| 1699 |
+
32 102
|
| 1700 |
+
32 103
|
| 1701 |
+
32 104
|
| 1702 |
+
32 105
|
| 1703 |
+
32 107
|
| 1704 |
+
32 111
|
| 1705 |
+
32 112
|
| 1706 |
+
32 116
|
| 1707 |
+
32 118
|
| 1708 |
+
32 122
|
| 1709 |
+
32 126
|
| 1710 |
+
32 127
|
| 1711 |
+
32 128
|
| 1712 |
+
32 129
|
| 1713 |
+
32 131
|
| 1714 |
+
32 135
|
| 1715 |
+
32 136
|
| 1716 |
+
32 137
|
| 1717 |
+
32 158
|
| 1718 |
+
32 202
|
| 1719 |
+
33 34
|
| 1720 |
+
33 35
|
| 1721 |
+
33 36
|
| 1722 |
+
33 37
|
| 1723 |
+
33 38
|
| 1724 |
+
33 39
|
| 1725 |
+
33 40
|
| 1726 |
+
33 41
|
| 1727 |
+
33 42
|
| 1728 |
+
33 43
|
| 1729 |
+
33 44
|
| 1730 |
+
33 45
|
| 1731 |
+
33 46
|
| 1732 |
+
33 47
|
| 1733 |
+
33 48
|
| 1734 |
+
33 49
|
| 1735 |
+
33 51
|
| 1736 |
+
33 52
|
| 1737 |
+
33 53
|
| 1738 |
+
33 54
|
| 1739 |
+
33 55
|
| 1740 |
+
33 56
|
| 1741 |
+
33 57
|
| 1742 |
+
33 60
|
| 1743 |
+
33 62
|
| 1744 |
+
33 64
|
| 1745 |
+
33 66
|
| 1746 |
+
33 68
|
| 1747 |
+
33 80
|
| 1748 |
+
33 97
|
| 1749 |
+
33 98
|
| 1750 |
+
33 99
|
| 1751 |
+
33 103
|
| 1752 |
+
33 104
|
| 1753 |
+
33 105
|
| 1754 |
+
33 106
|
| 1755 |
+
33 107
|
| 1756 |
+
33 108
|
| 1757 |
+
33 110
|
| 1758 |
+
33 111
|
| 1759 |
+
33 112
|
| 1760 |
+
33 115
|
| 1761 |
+
33 116
|
| 1762 |
+
33 117
|
| 1763 |
+
33 118
|
| 1764 |
+
33 119
|
| 1765 |
+
33 120
|
| 1766 |
+
33 121
|
| 1767 |
+
33 123
|
| 1768 |
+
33 125
|
| 1769 |
+
33 126
|
| 1770 |
+
33 127
|
| 1771 |
+
33 128
|
| 1772 |
+
33 131
|
| 1773 |
+
33 137
|
| 1774 |
+
33 154
|
| 1775 |
+
33 164
|
| 1776 |
+
33 175
|
| 1777 |
+
33 197
|
| 1778 |
+
33 202
|
| 1779 |
+
34 35
|
| 1780 |
+
34 37
|
| 1781 |
+
34 38
|
| 1782 |
+
34 39
|
| 1783 |
+
34 40
|
| 1784 |
+
34 41
|
| 1785 |
+
34 42
|
| 1786 |
+
34 43
|
| 1787 |
+
34 46
|
| 1788 |
+
34 47
|
| 1789 |
+
34 50
|
| 1790 |
+
34 51
|
| 1791 |
+
34 56
|
| 1792 |
+
34 101
|
| 1793 |
+
34 103
|
| 1794 |
+
34 104
|
| 1795 |
+
34 112
|
| 1796 |
+
34 115
|
| 1797 |
+
34 116
|
| 1798 |
+
34 122
|
| 1799 |
+
34 127
|
| 1800 |
+
34 131
|
| 1801 |
+
34 135
|
| 1802 |
+
34 136
|
| 1803 |
+
35 36
|
| 1804 |
+
35 37
|
| 1805 |
+
35 38
|
| 1806 |
+
35 40
|
| 1807 |
+
35 41
|
| 1808 |
+
35 42
|
| 1809 |
+
35 43
|
| 1810 |
+
35 44
|
| 1811 |
+
35 45
|
| 1812 |
+
35 46
|
| 1813 |
+
35 47
|
| 1814 |
+
35 48
|
| 1815 |
+
35 49
|
| 1816 |
+
35 50
|
| 1817 |
+
35 51
|
| 1818 |
+
35 52
|
| 1819 |
+
35 53
|
| 1820 |
+
35 54
|
| 1821 |
+
35 55
|
| 1822 |
+
35 56
|
| 1823 |
+
35 57
|
| 1824 |
+
35 60
|
| 1825 |
+
35 62
|
| 1826 |
+
35 64
|
| 1827 |
+
35 65
|
| 1828 |
+
35 66
|
| 1829 |
+
35 68
|
| 1830 |
+
35 69
|
| 1831 |
+
35 80
|
| 1832 |
+
35 87
|
| 1833 |
+
35 95
|
| 1834 |
+
35 97
|
| 1835 |
+
35 98
|
| 1836 |
+
35 99
|
| 1837 |
+
35 100
|
| 1838 |
+
35 101
|
| 1839 |
+
35 102
|
| 1840 |
+
35 103
|
| 1841 |
+
35 104
|
| 1842 |
+
35 105
|
| 1843 |
+
35 106
|
| 1844 |
+
35 107
|
| 1845 |
+
35 109
|
| 1846 |
+
35 110
|
| 1847 |
+
35 111
|
| 1848 |
+
35 112
|
| 1849 |
+
35 113
|
| 1850 |
+
35 114
|
| 1851 |
+
35 115
|
| 1852 |
+
35 116
|
| 1853 |
+
35 117
|
| 1854 |
+
35 118
|
| 1855 |
+
35 119
|
| 1856 |
+
35 120
|
| 1857 |
+
35 122
|
| 1858 |
+
35 124
|
| 1859 |
+
35 125
|
| 1860 |
+
35 126
|
| 1861 |
+
35 127
|
| 1862 |
+
35 128
|
| 1863 |
+
35 130
|
| 1864 |
+
35 137
|
| 1865 |
+
35 162
|
| 1866 |
+
35 164
|
| 1867 |
+
35 197
|
| 1868 |
+
36 37
|
| 1869 |
+
36 38
|
| 1870 |
+
36 39
|
| 1871 |
+
36 41
|
| 1872 |
+
36 42
|
| 1873 |
+
36 43
|
| 1874 |
+
36 44
|
| 1875 |
+
36 45
|
| 1876 |
+
36 46
|
| 1877 |
+
36 47
|
| 1878 |
+
36 48
|
| 1879 |
+
36 49
|
| 1880 |
+
36 50
|
| 1881 |
+
36 51
|
| 1882 |
+
36 52
|
| 1883 |
+
36 53
|
| 1884 |
+
36 54
|
| 1885 |
+
36 55
|
| 1886 |
+
36 56
|
| 1887 |
+
36 57
|
| 1888 |
+
36 60
|
| 1889 |
+
36 62
|
| 1890 |
+
36 63
|
| 1891 |
+
36 64
|
| 1892 |
+
36 65
|
| 1893 |
+
36 66
|
| 1894 |
+
36 68
|
| 1895 |
+
36 69
|
| 1896 |
+
36 70
|
| 1897 |
+
36 71
|
| 1898 |
+
36 73
|
| 1899 |
+
36 76
|
| 1900 |
+
36 77
|
| 1901 |
+
36 80
|
| 1902 |
+
36 81
|
| 1903 |
+
36 85
|
| 1904 |
+
36 87
|
| 1905 |
+
36 91
|
| 1906 |
+
36 92
|
| 1907 |
+
36 93
|
| 1908 |
+
36 94
|
| 1909 |
+
36 95
|
| 1910 |
+
36 97
|
| 1911 |
+
36 98
|
| 1912 |
+
36 99
|
| 1913 |
+
36 100
|
| 1914 |
+
36 101
|
| 1915 |
+
36 102
|
| 1916 |
+
36 104
|
| 1917 |
+
36 105
|
| 1918 |
+
36 106
|
| 1919 |
+
36 107
|
| 1920 |
+
36 108
|
| 1921 |
+
36 110
|
| 1922 |
+
36 111
|
| 1923 |
+
36 112
|
| 1924 |
+
36 115
|
| 1925 |
+
36 116
|
| 1926 |
+
36 117
|
| 1927 |
+
36 118
|
| 1928 |
+
36 120
|
| 1929 |
+
36 123
|
| 1930 |
+
36 124
|
| 1931 |
+
36 125
|
| 1932 |
+
36 128
|
| 1933 |
+
36 137
|
| 1934 |
+
36 138
|
| 1935 |
+
36 139
|
| 1936 |
+
36 140
|
| 1937 |
+
36 142
|
| 1938 |
+
36 145
|
| 1939 |
+
36 146
|
| 1940 |
+
36 147
|
| 1941 |
+
36 148
|
| 1942 |
+
36 149
|
| 1943 |
+
36 150
|
| 1944 |
+
36 151
|
| 1945 |
+
36 152
|
| 1946 |
+
36 154
|
| 1947 |
+
36 160
|
| 1948 |
+
36 164
|
| 1949 |
+
36 175
|
| 1950 |
+
36 176
|
| 1951 |
+
36 177
|
| 1952 |
+
36 204
|
| 1953 |
+
36 214
|
| 1954 |
+
37 38
|
| 1955 |
+
37 39
|
| 1956 |
+
37 40
|
| 1957 |
+
37 41
|
| 1958 |
+
37 42
|
| 1959 |
+
37 43
|
| 1960 |
+
37 44
|
| 1961 |
+
37 47
|
| 1962 |
+
37 50
|
| 1963 |
+
37 51
|
| 1964 |
+
37 53
|
| 1965 |
+
37 54
|
| 1966 |
+
37 55
|
| 1967 |
+
37 56
|
| 1968 |
+
37 57
|
| 1969 |
+
37 59
|
| 1970 |
+
37 60
|
| 1971 |
+
37 62
|
| 1972 |
+
37 63
|
| 1973 |
+
37 64
|
| 1974 |
+
37 65
|
| 1975 |
+
37 66
|
| 1976 |
+
37 69
|
| 1977 |
+
37 80
|
| 1978 |
+
37 85
|
| 1979 |
+
37 97
|
| 1980 |
+
37 98
|
| 1981 |
+
37 99
|
| 1982 |
+
37 101
|
| 1983 |
+
37 103
|
| 1984 |
+
37 104
|
| 1985 |
+
37 105
|
| 1986 |
+
37 106
|
| 1987 |
+
37 107
|
| 1988 |
+
37 110
|
| 1989 |
+
37 111
|
| 1990 |
+
37 116
|
| 1991 |
+
37 117
|
| 1992 |
+
37 118
|
| 1993 |
+
37 120
|
| 1994 |
+
37 121
|
| 1995 |
+
37 122
|
| 1996 |
+
37 123
|
| 1997 |
+
37 126
|
| 1998 |
+
37 127
|
| 1999 |
+
37 128
|
| 2000 |
+
37 130
|
| 2001 |
+
37 131
|
| 2002 |
+
37 137
|
| 2003 |
+
37 161
|
| 2004 |
+
37 164
|
| 2005 |
+
37 202
|
| 2006 |
+
38 39
|
| 2007 |
+
38 40
|
| 2008 |
+
38 41
|
| 2009 |
+
38 42
|
| 2010 |
+
38 43
|
| 2011 |
+
38 45
|
| 2012 |
+
38 46
|
| 2013 |
+
38 47
|
| 2014 |
+
38 48
|
| 2015 |
+
38 49
|
| 2016 |
+
38 50
|
| 2017 |
+
38 51
|
| 2018 |
+
38 52
|
| 2019 |
+
38 53
|
| 2020 |
+
38 54
|
| 2021 |
+
38 55
|
| 2022 |
+
38 56
|
| 2023 |
+
38 57
|
| 2024 |
+
38 62
|
| 2025 |
+
38 64
|
| 2026 |
+
38 66
|
| 2027 |
+
38 87
|
| 2028 |
+
38 95
|
| 2029 |
+
38 97
|
| 2030 |
+
38 99
|
| 2031 |
+
38 102
|
| 2032 |
+
38 103
|
| 2033 |
+
38 104
|
| 2034 |
+
38 105
|
| 2035 |
+
38 106
|
| 2036 |
+
38 107
|
| 2037 |
+
38 108
|
| 2038 |
+
38 112
|
| 2039 |
+
38 115
|
| 2040 |
+
38 116
|
| 2041 |
+
38 117
|
| 2042 |
+
38 118
|
| 2043 |
+
38 119
|
| 2044 |
+
38 120
|
| 2045 |
+
38 121
|
| 2046 |
+
38 123
|
| 2047 |
+
38 125
|
| 2048 |
+
38 126
|
| 2049 |
+
38 127
|
| 2050 |
+
38 128
|
| 2051 |
+
38 131
|
| 2052 |
+
38 164
|
| 2053 |
+
38 175
|
| 2054 |
+
38 197
|
| 2055 |
+
38 202
|
| 2056 |
+
39 40
|
| 2057 |
+
39 42
|
| 2058 |
+
39 47
|
| 2059 |
+
39 51
|
| 2060 |
+
39 55
|
| 2061 |
+
39 57
|
| 2062 |
+
39 101
|
| 2063 |
+
39 103
|
| 2064 |
+
39 112
|
| 2065 |
+
39 116
|
| 2066 |
+
39 118
|
| 2067 |
+
39 122
|
| 2068 |
+
39 126
|
| 2069 |
+
39 127
|
| 2070 |
+
39 131
|
| 2071 |
+
39 137
|
| 2072 |
+
39 162
|
| 2073 |
+
40 41
|
| 2074 |
+
40 46
|
| 2075 |
+
40 48
|
| 2076 |
+
40 51
|
| 2077 |
+
40 57
|
| 2078 |
+
40 59
|
| 2079 |
+
40 63
|
| 2080 |
+
40 67
|
| 2081 |
+
40 68
|
| 2082 |
+
40 83
|
| 2083 |
+
40 102
|
| 2084 |
+
40 103
|
| 2085 |
+
40 104
|
| 2086 |
+
40 112
|
| 2087 |
+
40 122
|
| 2088 |
+
40 128
|
| 2089 |
+
40 131
|
| 2090 |
+
40 135
|
| 2091 |
+
40 136
|
| 2092 |
+
41 42
|
| 2093 |
+
41 46
|
| 2094 |
+
41 47
|
| 2095 |
+
41 48
|
| 2096 |
+
41 50
|
| 2097 |
+
41 51
|
| 2098 |
+
41 55
|
| 2099 |
+
41 57
|
| 2100 |
+
41 69
|
| 2101 |
+
41 95
|
| 2102 |
+
41 97
|
| 2103 |
+
41 101
|
| 2104 |
+
41 103
|
| 2105 |
+
41 104
|
| 2106 |
+
41 115
|
| 2107 |
+
41 116
|
| 2108 |
+
41 120
|
| 2109 |
+
41 122
|
| 2110 |
+
41 124
|
| 2111 |
+
41 127
|
| 2112 |
+
41 131
|
| 2113 |
+
41 135
|
| 2114 |
+
41 164
|
| 2115 |
+
42 43
|
| 2116 |
+
42 44
|
| 2117 |
+
42 45
|
| 2118 |
+
42 46
|
| 2119 |
+
42 47
|
| 2120 |
+
42 48
|
| 2121 |
+
42 49
|
| 2122 |
+
42 50
|
| 2123 |
+
42 51
|
| 2124 |
+
42 53
|
| 2125 |
+
42 54
|
| 2126 |
+
42 55
|
| 2127 |
+
42 56
|
| 2128 |
+
42 57
|
| 2129 |
+
42 59
|
| 2130 |
+
42 60
|
| 2131 |
+
42 61
|
| 2132 |
+
42 63
|
| 2133 |
+
42 65
|
| 2134 |
+
42 69
|
| 2135 |
+
42 82
|
| 2136 |
+
42 87
|
| 2137 |
+
42 89
|
| 2138 |
+
42 91
|
| 2139 |
+
42 97
|
| 2140 |
+
42 98
|
| 2141 |
+
42 99
|
| 2142 |
+
42 100
|
| 2143 |
+
42 101
|
| 2144 |
+
42 102
|
| 2145 |
+
42 103
|
| 2146 |
+
42 104
|
| 2147 |
+
42 105
|
| 2148 |
+
42 106
|
| 2149 |
+
42 107
|
| 2150 |
+
42 108
|
| 2151 |
+
42 109
|
| 2152 |
+
42 110
|
| 2153 |
+
42 111
|
| 2154 |
+
42 112
|
| 2155 |
+
42 115
|
| 2156 |
+
42 116
|
| 2157 |
+
42 117
|
| 2158 |
+
42 118
|
| 2159 |
+
42 119
|
| 2160 |
+
42 120
|
| 2161 |
+
42 121
|
| 2162 |
+
42 122
|
| 2163 |
+
42 123
|
| 2164 |
+
42 126
|
| 2165 |
+
42 128
|
| 2166 |
+
42 137
|
| 2167 |
+
42 154
|
| 2168 |
+
42 156
|
| 2169 |
+
42 157
|
| 2170 |
+
42 160
|
| 2171 |
+
42 164
|
| 2172 |
+
42 175
|
| 2173 |
+
42 196
|
| 2174 |
+
42 197
|
| 2175 |
+
43 44
|
| 2176 |
+
43 45
|
| 2177 |
+
43 46
|
| 2178 |
+
43 47
|
| 2179 |
+
43 48
|
| 2180 |
+
43 49
|
| 2181 |
+
43 50
|
| 2182 |
+
43 51
|
| 2183 |
+
43 53
|
| 2184 |
+
43 54
|
| 2185 |
+
43 56
|
| 2186 |
+
43 62
|
| 2187 |
+
43 64
|
| 2188 |
+
43 66
|
| 2189 |
+
43 68
|
| 2190 |
+
43 69
|
| 2191 |
+
43 80
|
| 2192 |
+
43 95
|
| 2193 |
+
43 97
|
| 2194 |
+
43 98
|
| 2195 |
+
43 99
|
| 2196 |
+
43 100
|
| 2197 |
+
43 102
|
| 2198 |
+
43 105
|
| 2199 |
+
43 106
|
| 2200 |
+
43 107
|
| 2201 |
+
43 108
|
| 2202 |
+
43 109
|
| 2203 |
+
43 110
|
| 2204 |
+
43 111
|
| 2205 |
+
43 112
|
| 2206 |
+
43 113
|
| 2207 |
+
43 114
|
| 2208 |
+
43 115
|
| 2209 |
+
43 117
|
| 2210 |
+
43 118
|
| 2211 |
+
43 119
|
| 2212 |
+
43 120
|
| 2213 |
+
43 122
|
| 2214 |
+
43 123
|
| 2215 |
+
43 124
|
| 2216 |
+
43 126
|
| 2217 |
+
43 128
|
| 2218 |
+
43 137
|
| 2219 |
+
43 139
|
| 2220 |
+
43 144
|
| 2221 |
+
43 164
|
| 2222 |
+
43 202
|
| 2223 |
+
44 45
|
| 2224 |
+
44 46
|
| 2225 |
+
44 47
|
| 2226 |
+
44 48
|
| 2227 |
+
44 49
|
| 2228 |
+
44 55
|
| 2229 |
+
44 57
|
| 2230 |
+
44 68
|
| 2231 |
+
44 80
|
| 2232 |
+
44 92
|
| 2233 |
+
44 97
|
| 2234 |
+
44 99
|
| 2235 |
+
44 102
|
| 2236 |
+
44 104
|
| 2237 |
+
44 105
|
| 2238 |
+
44 107
|
| 2239 |
+
44 108
|
| 2240 |
+
44 109
|
| 2241 |
+
44 110
|
| 2242 |
+
44 111
|
| 2243 |
+
44 112
|
| 2244 |
+
44 117
|
| 2245 |
+
44 120
|
| 2246 |
+
44 123
|
| 2247 |
+
44 124
|
| 2248 |
+
44 128
|
| 2249 |
+
44 137
|
| 2250 |
+
44 139
|
| 2251 |
+
44 150
|
| 2252 |
+
44 151
|
| 2253 |
+
44 154
|
| 2254 |
+
44 175
|
| 2255 |
+
45 46
|
| 2256 |
+
45 47
|
| 2257 |
+
45 48
|
| 2258 |
+
45 49
|
| 2259 |
+
45 53
|
| 2260 |
+
45 54
|
| 2261 |
+
45 55
|
| 2262 |
+
45 57
|
| 2263 |
+
45 60
|
| 2264 |
+
45 64
|
| 2265 |
+
45 68
|
| 2266 |
+
45 80
|
| 2267 |
+
45 92
|
| 2268 |
+
45 97
|
| 2269 |
+
45 99
|
| 2270 |
+
45 104
|
| 2271 |
+
45 105
|
| 2272 |
+
45 106
|
| 2273 |
+
45 107
|
| 2274 |
+
45 109
|
| 2275 |
+
45 111
|
| 2276 |
+
45 117
|
| 2277 |
+
45 119
|
| 2278 |
+
45 120
|
| 2279 |
+
45 123
|
| 2280 |
+
45 124
|
| 2281 |
+
45 128
|
| 2282 |
+
45 139
|
| 2283 |
+
45 150
|
| 2284 |
+
45 151
|
| 2285 |
+
45 152
|
| 2286 |
+
45 175
|
| 2287 |
+
45 176
|
| 2288 |
+
45 204
|
| 2289 |
+
46 47
|
| 2290 |
+
46 48
|
| 2291 |
+
46 49
|
| 2292 |
+
46 51
|
| 2293 |
+
46 53
|
| 2294 |
+
46 54
|
| 2295 |
+
46 55
|
| 2296 |
+
46 56
|
| 2297 |
+
46 57
|
| 2298 |
+
46 60
|
| 2299 |
+
46 64
|
| 2300 |
+
46 66
|
| 2301 |
+
46 68
|
| 2302 |
+
46 80
|
| 2303 |
+
46 95
|
| 2304 |
+
46 97
|
| 2305 |
+
46 98
|
| 2306 |
+
46 99
|
| 2307 |
+
46 100
|
| 2308 |
+
46 103
|
| 2309 |
+
46 104
|
| 2310 |
+
46 105
|
| 2311 |
+
46 106
|
| 2312 |
+
46 107
|
| 2313 |
+
46 108
|
| 2314 |
+
46 109
|
| 2315 |
+
46 110
|
| 2316 |
+
46 111
|
| 2317 |
+
46 112
|
| 2318 |
+
46 114
|
| 2319 |
+
46 115
|
| 2320 |
+
46 117
|
| 2321 |
+
46 118
|
| 2322 |
+
46 119
|
| 2323 |
+
46 120
|
| 2324 |
+
46 122
|
| 2325 |
+
46 123
|
| 2326 |
+
46 124
|
| 2327 |
+
46 128
|
| 2328 |
+
46 131
|
| 2329 |
+
46 137
|
| 2330 |
+
46 154
|
| 2331 |
+
46 175
|
| 2332 |
+
47 48
|
| 2333 |
+
47 49
|
| 2334 |
+
47 50
|
| 2335 |
+
47 52
|
| 2336 |
+
47 53
|
| 2337 |
+
47 54
|
| 2338 |
+
47 55
|
| 2339 |
+
47 56
|
| 2340 |
+
47 57
|
| 2341 |
+
47 60
|
| 2342 |
+
47 62
|
| 2343 |
+
47 64
|
| 2344 |
+
47 66
|
| 2345 |
+
47 68
|
| 2346 |
+
47 69
|
| 2347 |
+
47 80
|
| 2348 |
+
47 95
|
| 2349 |
+
47 97
|
| 2350 |
+
47 98
|
| 2351 |
+
47 99
|
| 2352 |
+
47 100
|
| 2353 |
+
47 103
|
| 2354 |
+
47 104
|
| 2355 |
+
47 105
|
| 2356 |
+
47 106
|
| 2357 |
+
47 107
|
| 2358 |
+
47 108
|
| 2359 |
+
47 110
|
| 2360 |
+
47 111
|
| 2361 |
+
47 112
|
| 2362 |
+
47 114
|
| 2363 |
+
47 115
|
| 2364 |
+
47 117
|
| 2365 |
+
47 118
|
| 2366 |
+
47 120
|
| 2367 |
+
47 121
|
| 2368 |
+
47 123
|
| 2369 |
+
47 124
|
| 2370 |
+
47 127
|
| 2371 |
+
47 128
|
| 2372 |
+
47 130
|
| 2373 |
+
47 137
|
| 2374 |
+
47 139
|
| 2375 |
+
47 145
|
| 2376 |
+
47 154
|
| 2377 |
+
47 160
|
| 2378 |
+
47 164
|
| 2379 |
+
47 165
|
| 2380 |
+
47 175
|
| 2381 |
+
47 183
|
| 2382 |
+
47 197
|
| 2383 |
+
47 202
|
| 2384 |
+
47 204
|
| 2385 |
+
47 214
|
| 2386 |
+
48 49
|
| 2387 |
+
48 50
|
| 2388 |
+
48 55
|
| 2389 |
+
48 56
|
| 2390 |
+
48 67
|
| 2391 |
+
48 68
|
| 2392 |
+
48 95
|
| 2393 |
+
48 97
|
| 2394 |
+
48 98
|
| 2395 |
+
48 99
|
| 2396 |
+
48 100
|
| 2397 |
+
48 102
|
| 2398 |
+
48 104
|
| 2399 |
+
48 105
|
| 2400 |
+
48 106
|
| 2401 |
+
48 107
|
| 2402 |
+
48 108
|
| 2403 |
+
48 112
|
| 2404 |
+
48 114
|
| 2405 |
+
48 115
|
| 2406 |
+
48 118
|
| 2407 |
+
48 119
|
| 2408 |
+
48 120
|
| 2409 |
+
48 123
|
| 2410 |
+
48 124
|
| 2411 |
+
48 128
|
| 2412 |
+
48 164
|
| 2413 |
+
48 175
|
| 2414 |
+
49 50
|
| 2415 |
+
49 53
|
| 2416 |
+
49 54
|
| 2417 |
+
49 55
|
| 2418 |
+
49 56
|
| 2419 |
+
49 57
|
| 2420 |
+
49 60
|
| 2421 |
+
49 62
|
| 2422 |
+
49 64
|
| 2423 |
+
49 95
|
| 2424 |
+
49 97
|
| 2425 |
+
49 98
|
| 2426 |
+
49 99
|
| 2427 |
+
49 100
|
| 2428 |
+
49 102
|
| 2429 |
+
49 104
|
| 2430 |
+
49 105
|
| 2431 |
+
49 106
|
| 2432 |
+
49 107
|
| 2433 |
+
49 108
|
| 2434 |
+
49 110
|
| 2435 |
+
49 112
|
| 2436 |
+
49 114
|
| 2437 |
+
49 115
|
| 2438 |
+
49 117
|
| 2439 |
+
49 119
|
| 2440 |
+
49 123
|
| 2441 |
+
49 128
|
| 2442 |
+
49 164
|
| 2443 |
+
49 175
|
| 2444 |
+
49 202
|
| 2445 |
+
50 54
|
| 2446 |
+
50 56
|
| 2447 |
+
50 64
|
| 2448 |
+
50 97
|
| 2449 |
+
50 98
|
| 2450 |
+
50 100
|
| 2451 |
+
50 102
|
| 2452 |
+
50 106
|
| 2453 |
+
50 107
|
| 2454 |
+
50 108
|
| 2455 |
+
50 115
|
| 2456 |
+
50 117
|
| 2457 |
+
50 119
|
| 2458 |
+
50 121
|
| 2459 |
+
50 122
|
| 2460 |
+
50 128
|
| 2461 |
+
50 197
|
| 2462 |
+
51 52
|
| 2463 |
+
51 54
|
| 2464 |
+
51 56
|
| 2465 |
+
51 64
|
| 2466 |
+
51 97
|
| 2467 |
+
51 98
|
| 2468 |
+
51 115
|
| 2469 |
+
51 126
|
| 2470 |
+
51 128
|
| 2471 |
+
51 162
|
| 2472 |
+
51 165
|
| 2473 |
+
52 53
|
| 2474 |
+
52 106
|
| 2475 |
+
53 54
|
| 2476 |
+
53 55
|
| 2477 |
+
53 56
|
| 2478 |
+
53 57
|
| 2479 |
+
53 60
|
| 2480 |
+
53 64
|
| 2481 |
+
53 68
|
| 2482 |
+
53 87
|
| 2483 |
+
53 95
|
| 2484 |
+
53 97
|
| 2485 |
+
53 99
|
| 2486 |
+
53 104
|
| 2487 |
+
53 105
|
| 2488 |
+
53 106
|
| 2489 |
+
53 107
|
| 2490 |
+
53 108
|
| 2491 |
+
53 110
|
| 2492 |
+
53 117
|
| 2493 |
+
53 119
|
| 2494 |
+
53 120
|
| 2495 |
+
53 123
|
| 2496 |
+
53 128
|
| 2497 |
+
53 137
|
| 2498 |
+
53 154
|
| 2499 |
+
53 175
|
| 2500 |
+
53 197
|
| 2501 |
+
53 202
|
| 2502 |
+
54 55
|
| 2503 |
+
54 57
|
| 2504 |
+
54 64
|
| 2505 |
+
54 99
|
| 2506 |
+
54 100
|
| 2507 |
+
54 102
|
| 2508 |
+
54 106
|
| 2509 |
+
54 107
|
| 2510 |
+
54 108
|
| 2511 |
+
54 109
|
| 2512 |
+
54 110
|
| 2513 |
+
54 117
|
| 2514 |
+
54 119
|
| 2515 |
+
54 120
|
| 2516 |
+
54 123
|
| 2517 |
+
54 128
|
| 2518 |
+
54 175
|
| 2519 |
+
54 202
|
| 2520 |
+
55 56
|
| 2521 |
+
55 60
|
| 2522 |
+
55 62
|
| 2523 |
+
55 64
|
| 2524 |
+
55 66
|
| 2525 |
+
55 68
|
| 2526 |
+
55 95
|
| 2527 |
+
55 96
|
| 2528 |
+
55 97
|
| 2529 |
+
55 99
|
| 2530 |
+
55 104
|
| 2531 |
+
55 106
|
| 2532 |
+
55 107
|
| 2533 |
+
55 108
|
| 2534 |
+
55 110
|
| 2535 |
+
55 112
|
| 2536 |
+
55 115
|
| 2537 |
+
55 117
|
| 2538 |
+
55 118
|
| 2539 |
+
55 120
|
| 2540 |
+
55 123
|
| 2541 |
+
55 124
|
| 2542 |
+
55 128
|
| 2543 |
+
55 131
|
| 2544 |
+
55 137
|
| 2545 |
+
55 154
|
| 2546 |
+
55 164
|
| 2547 |
+
55 165
|
| 2548 |
+
55 175
|
| 2549 |
+
55 214
|
| 2550 |
+
56 57
|
| 2551 |
+
56 60
|
| 2552 |
+
56 62
|
| 2553 |
+
56 64
|
| 2554 |
+
56 66
|
| 2555 |
+
56 68
|
| 2556 |
+
56 97
|
| 2557 |
+
56 98
|
| 2558 |
+
56 99
|
| 2559 |
+
56 100
|
| 2560 |
+
56 105
|
| 2561 |
+
56 106
|
| 2562 |
+
56 107
|
| 2563 |
+
56 108
|
| 2564 |
+
56 110
|
| 2565 |
+
56 117
|
| 2566 |
+
56 119
|
| 2567 |
+
56 120
|
| 2568 |
+
56 123
|
| 2569 |
+
56 137
|
| 2570 |
+
56 175
|
| 2571 |
+
56 202
|
| 2572 |
+
57 60
|
| 2573 |
+
57 64
|
| 2574 |
+
57 95
|
| 2575 |
+
57 96
|
| 2576 |
+
57 97
|
| 2577 |
+
57 99
|
| 2578 |
+
57 104
|
| 2579 |
+
57 106
|
| 2580 |
+
57 107
|
| 2581 |
+
57 110
|
| 2582 |
+
57 112
|
| 2583 |
+
57 117
|
| 2584 |
+
57 118
|
| 2585 |
+
57 120
|
| 2586 |
+
57 123
|
| 2587 |
+
57 128
|
| 2588 |
+
57 131
|
| 2589 |
+
57 137
|
| 2590 |
+
57 154
|
| 2591 |
+
57 175
|
| 2592 |
+
59 62
|
| 2593 |
+
59 67
|
| 2594 |
+
59 68
|
| 2595 |
+
59 82
|
| 2596 |
+
59 83
|
| 2597 |
+
59 87
|
| 2598 |
+
59 88
|
| 2599 |
+
59 102
|
| 2600 |
+
59 125
|
| 2601 |
+
59 129
|
| 2602 |
+
59 158
|
| 2603 |
+
59 159
|
| 2604 |
+
59 160
|
| 2605 |
+
59 161
|
| 2606 |
+
59 162
|
| 2607 |
+
59 163
|
| 2608 |
+
60 61
|
| 2609 |
+
60 64
|
| 2610 |
+
60 66
|
| 2611 |
+
60 97
|
| 2612 |
+
60 99
|
| 2613 |
+
60 104
|
| 2614 |
+
60 106
|
| 2615 |
+
60 107
|
| 2616 |
+
60 110
|
| 2617 |
+
60 115
|
| 2618 |
+
60 117
|
| 2619 |
+
60 120
|
| 2620 |
+
60 123
|
| 2621 |
+
60 128
|
| 2622 |
+
60 154
|
| 2623 |
+
60 155
|
| 2624 |
+
60 156
|
| 2625 |
+
60 157
|
| 2626 |
+
60 175
|
| 2627 |
+
60 177
|
| 2628 |
+
60 196
|
| 2629 |
+
61 62
|
| 2630 |
+
61 64
|
| 2631 |
+
61 66
|
| 2632 |
+
61 155
|
| 2633 |
+
61 156
|
| 2634 |
+
61 157
|
| 2635 |
+
61 196
|
| 2636 |
+
62 63
|
| 2637 |
+
62 65
|
| 2638 |
+
62 69
|
| 2639 |
+
62 97
|
| 2640 |
+
62 101
|
| 2641 |
+
62 108
|
| 2642 |
+
62 110
|
| 2643 |
+
63 66
|
| 2644 |
+
63 67
|
| 2645 |
+
63 68
|
| 2646 |
+
63 82
|
| 2647 |
+
63 83
|
| 2648 |
+
63 84
|
| 2649 |
+
63 87
|
| 2650 |
+
63 88
|
| 2651 |
+
63 97
|
| 2652 |
+
63 104
|
| 2653 |
+
63 111
|
| 2654 |
+
63 122
|
| 2655 |
+
63 125
|
| 2656 |
+
63 129
|
| 2657 |
+
63 145
|
| 2658 |
+
63 158
|
| 2659 |
+
63 160
|
| 2660 |
+
63 161
|
| 2661 |
+
63 162
|
| 2662 |
+
63 163
|
| 2663 |
+
64 65
|
| 2664 |
+
64 69
|
| 2665 |
+
64 80
|
| 2666 |
+
64 97
|
| 2667 |
+
64 98
|
| 2668 |
+
64 101
|
| 2669 |
+
64 104
|
| 2670 |
+
64 106
|
| 2671 |
+
64 107
|
| 2672 |
+
64 108
|
| 2673 |
+
64 110
|
| 2674 |
+
64 115
|
| 2675 |
+
64 116
|
| 2676 |
+
64 117
|
| 2677 |
+
64 119
|
| 2678 |
+
64 120
|
| 2679 |
+
64 123
|
| 2680 |
+
64 128
|
| 2681 |
+
64 164
|
| 2682 |
+
64 175
|
| 2683 |
+
64 202
|
| 2684 |
+
65 66
|
| 2685 |
+
65 67
|
| 2686 |
+
65 80
|
| 2687 |
+
65 84
|
| 2688 |
+
65 87
|
| 2689 |
+
65 88
|
| 2690 |
+
65 97
|
| 2691 |
+
65 100
|
| 2692 |
+
65 104
|
| 2693 |
+
65 120
|
| 2694 |
+
65 122
|
| 2695 |
+
65 125
|
| 2696 |
+
65 129
|
| 2697 |
+
65 160
|
| 2698 |
+
65 161
|
| 2699 |
+
65 162
|
| 2700 |
+
66 69
|
| 2701 |
+
66 97
|
| 2702 |
+
66 104
|
| 2703 |
+
66 107
|
| 2704 |
+
66 108
|
| 2705 |
+
66 120
|
| 2706 |
+
66 128
|
| 2707 |
+
66 155
|
| 2708 |
+
66 156
|
| 2709 |
+
66 157
|
| 2710 |
+
66 196
|
| 2711 |
+
67 68
|
| 2712 |
+
67 69
|
| 2713 |
+
67 84
|
| 2714 |
+
67 85
|
| 2715 |
+
67 99
|
| 2716 |
+
67 104
|
| 2717 |
+
67 115
|
| 2718 |
+
67 131
|
| 2719 |
+
67 161
|
| 2720 |
+
67 172
|
| 2721 |
+
67 195
|
| 2722 |
+
68 82
|
| 2723 |
+
68 83
|
| 2724 |
+
68 85
|
| 2725 |
+
68 97
|
| 2726 |
+
68 102
|
| 2727 |
+
68 105
|
| 2728 |
+
68 107
|
| 2729 |
+
68 128
|
| 2730 |
+
68 129
|
| 2731 |
+
68 130
|
| 2732 |
+
68 143
|
| 2733 |
+
68 163
|
| 2734 |
+
69 80
|
| 2735 |
+
69 97
|
| 2736 |
+
69 100
|
| 2737 |
+
69 104
|
| 2738 |
+
69 111
|
| 2739 |
+
69 114
|
| 2740 |
+
69 122
|
| 2741 |
+
69 125
|
| 2742 |
+
69 145
|
| 2743 |
+
69 160
|
| 2744 |
+
69 161
|
| 2745 |
+
69 162
|
| 2746 |
+
70 71
|
| 2747 |
+
70 72
|
| 2748 |
+
70 73
|
| 2749 |
+
70 74
|
| 2750 |
+
70 76
|
| 2751 |
+
70 77
|
| 2752 |
+
70 79
|
| 2753 |
+
70 90
|
| 2754 |
+
70 91
|
| 2755 |
+
70 133
|
| 2756 |
+
70 138
|
| 2757 |
+
70 140
|
| 2758 |
+
70 142
|
| 2759 |
+
70 146
|
| 2760 |
+
70 147
|
| 2761 |
+
70 148
|
| 2762 |
+
70 150
|
| 2763 |
+
70 153
|
| 2764 |
+
70 176
|
| 2765 |
+
71 73
|
| 2766 |
+
71 74
|
| 2767 |
+
71 75
|
| 2768 |
+
71 76
|
| 2769 |
+
71 77
|
| 2770 |
+
71 90
|
| 2771 |
+
71 91
|
| 2772 |
+
71 92
|
| 2773 |
+
71 93
|
| 2774 |
+
71 94
|
| 2775 |
+
71 120
|
| 2776 |
+
71 132
|
| 2777 |
+
71 133
|
| 2778 |
+
71 138
|
| 2779 |
+
71 140
|
| 2780 |
+
71 142
|
| 2781 |
+
71 146
|
| 2782 |
+
71 147
|
| 2783 |
+
71 148
|
| 2784 |
+
71 149
|
| 2785 |
+
71 150
|
| 2786 |
+
71 151
|
| 2787 |
+
71 152
|
| 2788 |
+
71 153
|
| 2789 |
+
71 176
|
| 2790 |
+
72 73
|
| 2791 |
+
72 74
|
| 2792 |
+
72 92
|
| 2793 |
+
72 93
|
| 2794 |
+
72 94
|
| 2795 |
+
72 133
|
| 2796 |
+
72 138
|
| 2797 |
+
72 140
|
| 2798 |
+
72 142
|
| 2799 |
+
72 147
|
| 2800 |
+
72 148
|
| 2801 |
+
72 151
|
| 2802 |
+
72 152
|
| 2803 |
+
72 153
|
| 2804 |
+
72 176
|
| 2805 |
+
73 77
|
| 2806 |
+
73 79
|
| 2807 |
+
73 132
|
| 2808 |
+
73 134
|
| 2809 |
+
73 140
|
| 2810 |
+
74 77
|
| 2811 |
+
74 79
|
| 2812 |
+
74 132
|
| 2813 |
+
74 134
|
| 2814 |
+
74 140
|
| 2815 |
+
75 133
|
| 2816 |
+
75 134
|
| 2817 |
+
75 140
|
| 2818 |
+
75 147
|
| 2819 |
+
76 77
|
| 2820 |
+
76 93
|
| 2821 |
+
76 94
|
| 2822 |
+
76 132
|
| 2823 |
+
76 133
|
| 2824 |
+
76 134
|
| 2825 |
+
76 140
|
| 2826 |
+
76 147
|
| 2827 |
+
76 150
|
| 2828 |
+
76 152
|
| 2829 |
+
76 153
|
| 2830 |
+
76 176
|
| 2831 |
+
77 132
|
| 2832 |
+
77 133
|
| 2833 |
+
77 134
|
| 2834 |
+
77 138
|
| 2835 |
+
77 140
|
| 2836 |
+
77 142
|
| 2837 |
+
77 146
|
| 2838 |
+
77 147
|
| 2839 |
+
77 148
|
| 2840 |
+
77 150
|
| 2841 |
+
77 151
|
| 2842 |
+
77 153
|
| 2843 |
+
78 91
|
| 2844 |
+
78 93
|
| 2845 |
+
78 94
|
| 2846 |
+
78 132
|
| 2847 |
+
78 133
|
| 2848 |
+
78 146
|
| 2849 |
+
78 147
|
| 2850 |
+
78 148
|
| 2851 |
+
78 149
|
| 2852 |
+
79 92
|
| 2853 |
+
79 93
|
| 2854 |
+
79 132
|
| 2855 |
+
79 133
|
| 2856 |
+
79 138
|
| 2857 |
+
79 140
|
| 2858 |
+
79 142
|
| 2859 |
+
79 147
|
| 2860 |
+
79 148
|
| 2861 |
+
79 149
|
| 2862 |
+
79 150
|
| 2863 |
+
79 151
|
| 2864 |
+
79 153
|
| 2865 |
+
79 176
|
| 2866 |
+
80 92
|
| 2867 |
+
80 97
|
| 2868 |
+
80 98
|
| 2869 |
+
80 100
|
| 2870 |
+
80 103
|
| 2871 |
+
80 105
|
| 2872 |
+
80 107
|
| 2873 |
+
80 108
|
| 2874 |
+
80 110
|
| 2875 |
+
80 115
|
| 2876 |
+
80 117
|
| 2877 |
+
80 120
|
| 2878 |
+
80 122
|
| 2879 |
+
80 124
|
| 2880 |
+
80 128
|
| 2881 |
+
80 151
|
| 2882 |
+
80 162
|
| 2883 |
+
80 176
|
| 2884 |
+
81 83
|
| 2885 |
+
81 84
|
| 2886 |
+
81 88
|
| 2887 |
+
81 183
|
| 2888 |
+
81 184
|
| 2889 |
+
81 185
|
| 2890 |
+
82 83
|
| 2891 |
+
82 87
|
| 2892 |
+
82 88
|
| 2893 |
+
82 89
|
| 2894 |
+
82 102
|
| 2895 |
+
82 143
|
| 2896 |
+
82 183
|
| 2897 |
+
83 85
|
| 2898 |
+
83 86
|
| 2899 |
+
83 88
|
| 2900 |
+
83 89
|
| 2901 |
+
83 102
|
| 2902 |
+
83 143
|
| 2903 |
+
84 86
|
| 2904 |
+
84 87
|
| 2905 |
+
84 88
|
| 2906 |
+
84 211
|
| 2907 |
+
85 88
|
| 2908 |
+
85 129
|
| 2909 |
+
85 158
|
| 2910 |
+
85 159
|
| 2911 |
+
85 161
|
| 2912 |
+
85 162
|
| 2913 |
+
86 88
|
| 2914 |
+
87 88
|
| 2915 |
+
87 102
|
| 2916 |
+
87 107
|
| 2917 |
+
87 118
|
| 2918 |
+
87 202
|
| 2919 |
+
88 183
|
| 2920 |
+
88 185
|
| 2921 |
+
88 215
|
| 2922 |
+
89 184
|
| 2923 |
+
90 93
|
| 2924 |
+
90 140
|
| 2925 |
+
90 147
|
| 2926 |
+
90 149
|
| 2927 |
+
90 152
|
| 2928 |
+
91 132
|
| 2929 |
+
92 120
|
| 2930 |
+
92 132
|
| 2931 |
+
92 134
|
| 2932 |
+
93 132
|
| 2933 |
+
93 134
|
| 2934 |
+
94 110
|
| 2935 |
+
95 106
|
| 2936 |
+
95 108
|
| 2937 |
+
95 112
|
| 2938 |
+
95 127
|
| 2939 |
+
95 128
|
| 2940 |
+
96 128
|
| 2941 |
+
97 98
|
| 2942 |
+
97 99
|
| 2943 |
+
97 100
|
| 2944 |
+
97 102
|
| 2945 |
+
97 104
|
| 2946 |
+
97 105
|
| 2947 |
+
97 106
|
| 2948 |
+
97 107
|
| 2949 |
+
97 108
|
| 2950 |
+
97 110
|
| 2951 |
+
97 111
|
| 2952 |
+
97 112
|
| 2953 |
+
97 114
|
| 2954 |
+
97 115
|
| 2955 |
+
97 117
|
| 2956 |
+
97 122
|
| 2957 |
+
97 124
|
| 2958 |
+
97 125
|
| 2959 |
+
97 128
|
| 2960 |
+
97 137
|
| 2961 |
+
97 145
|
| 2962 |
+
97 177
|
| 2963 |
+
98 104
|
| 2964 |
+
98 106
|
| 2965 |
+
98 107
|
| 2966 |
+
98 108
|
| 2967 |
+
98 115
|
| 2968 |
+
98 116
|
| 2969 |
+
98 118
|
| 2970 |
+
98 128
|
| 2971 |
+
98 204
|
| 2972 |
+
99 104
|
| 2973 |
+
99 106
|
| 2974 |
+
99 107
|
| 2975 |
+
99 108
|
| 2976 |
+
99 110
|
| 2977 |
+
99 117
|
| 2978 |
+
99 120
|
| 2979 |
+
99 123
|
| 2980 |
+
99 131
|
| 2981 |
+
99 154
|
| 2982 |
+
99 175
|
| 2983 |
+
100 108
|
| 2984 |
+
100 109
|
| 2985 |
+
100 111
|
| 2986 |
+
100 112
|
| 2987 |
+
100 113
|
| 2988 |
+
100 114
|
| 2989 |
+
100 122
|
| 2990 |
+
100 128
|
| 2991 |
+
100 144
|
| 2992 |
+
100 145
|
| 2993 |
+
101 118
|
| 2994 |
+
101 126
|
| 2995 |
+
101 165
|
| 2996 |
+
101 197
|
| 2997 |
+
102 105
|
| 2998 |
+
102 107
|
| 2999 |
+
102 108
|
| 3000 |
+
102 112
|
| 3001 |
+
102 117
|
| 3002 |
+
102 143
|
| 3003 |
+
102 183
|
| 3004 |
+
103 111
|
| 3005 |
+
103 112
|
| 3006 |
+
103 115
|
| 3007 |
+
103 118
|
| 3008 |
+
103 121
|
| 3009 |
+
103 122
|
| 3010 |
+
103 126
|
| 3011 |
+
103 128
|
| 3012 |
+
103 129
|
| 3013 |
+
103 131
|
| 3014 |
+
103 165
|
| 3015 |
+
103 197
|
| 3016 |
+
104 106
|
| 3017 |
+
104 107
|
| 3018 |
+
104 110
|
| 3019 |
+
104 115
|
| 3020 |
+
104 117
|
| 3021 |
+
104 120
|
| 3022 |
+
104 123
|
| 3023 |
+
104 124
|
| 3024 |
+
104 125
|
| 3025 |
+
104 137
|
| 3026 |
+
104 154
|
| 3027 |
+
104 164
|
| 3028 |
+
104 177
|
| 3029 |
+
105 107
|
| 3030 |
+
105 108
|
| 3031 |
+
105 111
|
| 3032 |
+
105 112
|
| 3033 |
+
105 114
|
| 3034 |
+
105 117
|
| 3035 |
+
105 119
|
| 3036 |
+
105 128
|
| 3037 |
+
106 107
|
| 3038 |
+
106 108
|
| 3039 |
+
106 110
|
| 3040 |
+
106 119
|
| 3041 |
+
106 120
|
| 3042 |
+
106 123
|
| 3043 |
+
106 124
|
| 3044 |
+
106 128
|
| 3045 |
+
106 154
|
| 3046 |
+
106 175
|
| 3047 |
+
106 204
|
| 3048 |
+
107 108
|
| 3049 |
+
107 109
|
| 3050 |
+
107 110
|
| 3051 |
+
107 112
|
| 3052 |
+
107 115
|
| 3053 |
+
107 117
|
| 3054 |
+
107 119
|
| 3055 |
+
107 120
|
| 3056 |
+
107 123
|
| 3057 |
+
107 124
|
| 3058 |
+
107 128
|
| 3059 |
+
107 137
|
| 3060 |
+
107 164
|
| 3061 |
+
107 175
|
| 3062 |
+
107 202
|
| 3063 |
+
107 204
|
| 3064 |
+
108 112
|
| 3065 |
+
108 114
|
| 3066 |
+
108 115
|
| 3067 |
+
108 119
|
| 3068 |
+
108 120
|
| 3069 |
+
108 122
|
| 3070 |
+
108 128
|
| 3071 |
+
109 114
|
| 3072 |
+
109 128
|
| 3073 |
+
110 111
|
| 3074 |
+
110 117
|
| 3075 |
+
110 119
|
| 3076 |
+
110 120
|
| 3077 |
+
110 123
|
| 3078 |
+
110 124
|
| 3079 |
+
110 128
|
| 3080 |
+
111 115
|
| 3081 |
+
111 117
|
| 3082 |
+
111 120
|
| 3083 |
+
111 122
|
| 3084 |
+
111 124
|
| 3085 |
+
111 128
|
| 3086 |
+
111 162
|
| 3087 |
+
111 176
|
| 3088 |
+
112 114
|
| 3089 |
+
112 118
|
| 3090 |
+
112 122
|
| 3091 |
+
112 126
|
| 3092 |
+
112 128
|
| 3093 |
+
112 129
|
| 3094 |
+
113 114
|
| 3095 |
+
113 128
|
| 3096 |
+
114 117
|
| 3097 |
+
114 122
|
| 3098 |
+
114 126
|
| 3099 |
+
114 128
|
| 3100 |
+
115 116
|
| 3101 |
+
115 117
|
| 3102 |
+
115 118
|
| 3103 |
+
115 120
|
| 3104 |
+
115 124
|
| 3105 |
+
115 125
|
| 3106 |
+
115 128
|
| 3107 |
+
115 162
|
| 3108 |
+
115 177
|
| 3109 |
+
116 165
|
| 3110 |
+
117 118
|
| 3111 |
+
117 120
|
| 3112 |
+
117 123
|
| 3113 |
+
117 127
|
| 3114 |
+
117 128
|
| 3115 |
+
117 164
|
| 3116 |
+
118 126
|
| 3117 |
+
118 127
|
| 3118 |
+
118 128
|
| 3119 |
+
118 131
|
| 3120 |
+
119 123
|
| 3121 |
+
119 128
|
| 3122 |
+
119 175
|
| 3123 |
+
120 122
|
| 3124 |
+
120 123
|
| 3125 |
+
120 128
|
| 3126 |
+
120 137
|
| 3127 |
+
120 139
|
| 3128 |
+
120 150
|
| 3129 |
+
120 154
|
| 3130 |
+
120 164
|
| 3131 |
+
120 175
|
| 3132 |
+
120 176
|
| 3133 |
+
121 122
|
| 3134 |
+
121 126
|
| 3135 |
+
121 128
|
| 3136 |
+
122 126
|
| 3137 |
+
122 128
|
| 3138 |
+
122 162
|
| 3139 |
+
123 137
|
| 3140 |
+
123 154
|
| 3141 |
+
123 175
|
| 3142 |
+
124 137
|
| 3143 |
+
126 129
|
| 3144 |
+
126 131
|
| 3145 |
+
126 162
|
| 3146 |
+
126 167
|
| 3147 |
+
126 168
|
| 3148 |
+
126 170
|
| 3149 |
+
126 171
|
| 3150 |
+
126 172
|
| 3151 |
+
127 165
|
| 3152 |
+
127 197
|
| 3153 |
+
128 202
|
| 3154 |
+
129 168
|
| 3155 |
+
129 170
|
| 3156 |
+
130 145
|
| 3157 |
+
130 159
|
| 3158 |
+
130 160
|
| 3159 |
+
130 162
|
| 3160 |
+
132 133
|
| 3161 |
+
132 138
|
| 3162 |
+
132 140
|
| 3163 |
+
132 142
|
| 3164 |
+
132 146
|
| 3165 |
+
132 147
|
| 3166 |
+
132 148
|
| 3167 |
+
132 149
|
| 3168 |
+
132 150
|
| 3169 |
+
132 151
|
| 3170 |
+
132 152
|
| 3171 |
+
132 153
|
| 3172 |
+
133 134
|
| 3173 |
+
133 140
|
| 3174 |
+
133 153
|
| 3175 |
+
134 138
|
| 3176 |
+
134 140
|
| 3177 |
+
134 142
|
| 3178 |
+
134 148
|
| 3179 |
+
134 150
|
| 3180 |
+
134 153
|
| 3181 |
+
134 176
|
| 3182 |
+
138 140
|
| 3183 |
+
138 147
|
| 3184 |
+
138 150
|
| 3185 |
+
141 181
|
| 3186 |
+
141 206
|
| 3187 |
+
142 153
|
| 3188 |
+
145 160
|
| 3189 |
+
145 210
|
| 3190 |
+
146 153
|
| 3191 |
+
154 175
|
| 3192 |
+
155 156
|
| 3193 |
+
155 157
|
| 3194 |
+
156 157
|
| 3195 |
+
158 166
|
| 3196 |
+
158 167
|
| 3197 |
+
158 168
|
| 3198 |
+
158 169
|
| 3199 |
+
158 170
|
| 3200 |
+
158 171
|
| 3201 |
+
158 172
|
| 3202 |
+
163 208
|
| 3203 |
+
164 175
|
| 3204 |
+
166 172
|
| 3205 |
+
167 168
|
| 3206 |
+
168 170
|
| 3207 |
+
168 172
|
| 3208 |
+
173 174
|
| 3209 |
+
174 179
|
| 3210 |
+
174 182
|
| 3211 |
+
174 203
|
| 3212 |
+
174 213
|
| 3213 |
+
178 179
|
| 3214 |
+
178 180
|
| 3215 |
+
178 181
|
| 3216 |
+
179 180
|
| 3217 |
+
179 203
|
| 3218 |
+
179 205
|
| 3219 |
+
179 206
|
| 3220 |
+
180 181
|
| 3221 |
+
180 203
|
| 3222 |
+
180 213
|
| 3223 |
+
181 207
|
| 3224 |
+
181 213
|
| 3225 |
+
182 205
|
| 3226 |
+
182 206
|
| 3227 |
+
183 208
|
| 3228 |
+
186 187
|
| 3229 |
+
186 191
|
| 3230 |
+
186 193
|
| 3231 |
+
186 194
|
| 3232 |
+
186 199
|
| 3233 |
+
187 190
|
| 3234 |
+
187 191
|
| 3235 |
+
187 193
|
| 3236 |
+
187 201
|
| 3237 |
+
188 189
|
| 3238 |
+
188 193
|
| 3239 |
+
188 194
|
| 3240 |
+
188 199
|
| 3241 |
+
188 200
|
| 3242 |
+
188 212
|
| 3243 |
+
189 190
|
| 3244 |
+
189 193
|
| 3245 |
+
189 201
|
| 3246 |
+
190 193
|
| 3247 |
+
190 194
|
| 3248 |
+
190 199
|
| 3249 |
+
190 200
|
| 3250 |
+
191 194
|
| 3251 |
+
191 198
|
| 3252 |
+
191 199
|
| 3253 |
+
191 200
|
| 3254 |
+
192 194
|
| 3255 |
+
193 194
|
| 3256 |
+
193 198
|
| 3257 |
+
193 199
|
| 3258 |
+
193 212
|
| 3259 |
+
193 216
|
| 3260 |
+
194 200
|
| 3261 |
+
194 212
|
| 3262 |
+
198 200
|
| 3263 |
+
198 201
|
| 3264 |
+
199 200
|
| 3265 |
+
200 201
|
| 3266 |
+
201 216
|
| 3267 |
+
205 206
|
| 3268 |
+
205 207
|
| 3269 |
+
208 209
|
analysis/rdkit_functions.py
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import torch
|
| 3 |
+
import re
|
| 4 |
+
import wandb
|
| 5 |
+
try:
|
| 6 |
+
from rdkit import Chem
|
| 7 |
+
print("Found rdkit, all good")
|
| 8 |
+
except ModuleNotFoundError as e:
|
| 9 |
+
use_rdkit = False
|
| 10 |
+
from warnings import warn
|
| 11 |
+
warn("Didn't find rdkit, this will fail")
|
| 12 |
+
assert use_rdkit, "Didn't find rdkit"
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
allowed_bonds = {'H': 1, 'C': 4, 'N': 3, 'O': 2, 'F': 1, 'B': 3, 'Al': 3, 'Si': 4, 'P': [3, 5],
|
| 16 |
+
'S': 4, 'Cl': 1, 'As': 3, 'Br': 1, 'I': 1, 'Hg': [1, 2], 'Bi': [3, 5], 'Se': [2, 4, 6]}
|
| 17 |
+
bond_dict = [None, Chem.rdchem.BondType.SINGLE, Chem.rdchem.BondType.DOUBLE, Chem.rdchem.BondType.TRIPLE,
|
| 18 |
+
Chem.rdchem.BondType.AROMATIC]
|
| 19 |
+
ATOM_VALENCY = {6: 4, 7: 3, 8: 2, 9: 1, 15: 3, 16: 2, 17: 1, 35: 1, 53: 1}
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class BasicMolecularMetrics(object):
|
| 23 |
+
def __init__(self, dataset_info, train_smiles=None):
|
| 24 |
+
self.atom_decoder = dataset_info.atom_decoder
|
| 25 |
+
self.dataset_info = dataset_info
|
| 26 |
+
|
| 27 |
+
# Retrieve dataset smiles only for qm9 currently.
|
| 28 |
+
self.dataset_smiles_list = train_smiles
|
| 29 |
+
|
| 30 |
+
def compute_validity(self, generated):
|
| 31 |
+
""" generated: list of couples (positions, atom_types)"""
|
| 32 |
+
valid = []
|
| 33 |
+
num_components = []
|
| 34 |
+
all_smiles = []
|
| 35 |
+
for graph in generated:
|
| 36 |
+
atom_types, edge_types = graph
|
| 37 |
+
mol = build_molecule(atom_types, edge_types, self.dataset_info.atom_decoder)
|
| 38 |
+
smiles = mol2smiles(mol)
|
| 39 |
+
try:
|
| 40 |
+
mol_frags = Chem.rdmolops.GetMolFrags(mol, asMols=True, sanitizeFrags=True)
|
| 41 |
+
num_components.append(len(mol_frags))
|
| 42 |
+
except:
|
| 43 |
+
pass
|
| 44 |
+
if smiles is not None:
|
| 45 |
+
try:
|
| 46 |
+
mol_frags = Chem.rdmolops.GetMolFrags(mol, asMols=True, sanitizeFrags=True)
|
| 47 |
+
largest_mol = max(mol_frags, default=mol, key=lambda m: m.GetNumAtoms())
|
| 48 |
+
smiles = mol2smiles(largest_mol)
|
| 49 |
+
valid.append(smiles)
|
| 50 |
+
all_smiles.append(smiles)
|
| 51 |
+
except Chem.rdchem.AtomValenceException:
|
| 52 |
+
print("Valence error in GetmolFrags")
|
| 53 |
+
all_smiles.append(None)
|
| 54 |
+
except Chem.rdchem.KekulizeException:
|
| 55 |
+
print("Can't kekulize molecule")
|
| 56 |
+
all_smiles.append(None)
|
| 57 |
+
else:
|
| 58 |
+
all_smiles.append(None)
|
| 59 |
+
|
| 60 |
+
return valid, len(valid) / len(generated), np.array(num_components), all_smiles
|
| 61 |
+
|
| 62 |
+
def compute_uniqueness(self, valid):
|
| 63 |
+
""" valid: list of SMILES strings."""
|
| 64 |
+
return list(set(valid)), len(set(valid)) / len(valid)
|
| 65 |
+
|
| 66 |
+
def compute_novelty(self, unique):
|
| 67 |
+
num_novel = 0
|
| 68 |
+
novel = []
|
| 69 |
+
if self.dataset_smiles_list is None:
|
| 70 |
+
print("Dataset smiles is None, novelty computation skipped")
|
| 71 |
+
return 1, 1
|
| 72 |
+
for smiles in unique:
|
| 73 |
+
if smiles not in self.dataset_smiles_list:
|
| 74 |
+
novel.append(smiles)
|
| 75 |
+
num_novel += 1
|
| 76 |
+
return novel, num_novel / len(unique)
|
| 77 |
+
|
| 78 |
+
def compute_relaxed_validity(self, generated):
|
| 79 |
+
valid = []
|
| 80 |
+
for graph in generated:
|
| 81 |
+
atom_types, edge_types = graph
|
| 82 |
+
mol = build_molecule_with_partial_charges(atom_types, edge_types, self.dataset_info.atom_decoder)
|
| 83 |
+
smiles = mol2smiles(mol)
|
| 84 |
+
if smiles is not None:
|
| 85 |
+
try:
|
| 86 |
+
mol_frags = Chem.rdmolops.GetMolFrags(mol, asMols=True, sanitizeFrags=True)
|
| 87 |
+
largest_mol = max(mol_frags, default=mol, key=lambda m: m.GetNumAtoms())
|
| 88 |
+
smiles = mol2smiles(largest_mol)
|
| 89 |
+
valid.append(smiles)
|
| 90 |
+
except Chem.rdchem.AtomValenceException:
|
| 91 |
+
print("Valence error in GetmolFrags")
|
| 92 |
+
except Chem.rdchem.KekulizeException:
|
| 93 |
+
print("Can't kekulize molecule")
|
| 94 |
+
return valid, len(valid) / len(generated)
|
| 95 |
+
|
| 96 |
+
def evaluate(self, generated):
|
| 97 |
+
""" generated: list of pairs (positions: n x 3, atom_types: n [int])
|
| 98 |
+
the positions and atom types should already be masked. """
|
| 99 |
+
valid, validity, num_components, all_smiles = self.compute_validity(generated)
|
| 100 |
+
nc_mu = num_components.mean() if len(num_components) > 0 else 0
|
| 101 |
+
nc_min = num_components.min() if len(num_components) > 0 else 0
|
| 102 |
+
nc_max = num_components.max() if len(num_components) > 0 else 0
|
| 103 |
+
print(f"Validity over {len(generated)} molecules: {validity * 100 :.2f}%")
|
| 104 |
+
print(f"Number of connected components of {len(generated)} molecules: min:{nc_min:.2f} mean:{nc_mu:.2f} max:{nc_max:.2f}")
|
| 105 |
+
|
| 106 |
+
relaxed_valid, relaxed_validity = self.compute_relaxed_validity(generated)
|
| 107 |
+
print(f"Relaxed validity over {len(generated)} molecules: {relaxed_validity * 100 :.2f}%")
|
| 108 |
+
if relaxed_validity > 0:
|
| 109 |
+
unique, uniqueness = self.compute_uniqueness(relaxed_valid)
|
| 110 |
+
print(f"Uniqueness over {len(relaxed_valid)} valid molecules: {uniqueness * 100 :.2f}%")
|
| 111 |
+
|
| 112 |
+
if self.dataset_smiles_list is not None:
|
| 113 |
+
_, novelty = self.compute_novelty(unique)
|
| 114 |
+
print(f"Novelty over {len(unique)} unique valid molecules: {novelty * 100 :.2f}%")
|
| 115 |
+
else:
|
| 116 |
+
novelty = -1.0
|
| 117 |
+
else:
|
| 118 |
+
novelty = -1.0
|
| 119 |
+
uniqueness = 0.0
|
| 120 |
+
unique = []
|
| 121 |
+
return ([validity, relaxed_validity, uniqueness, novelty], unique,
|
| 122 |
+
dict(nc_min=nc_min, nc_max=nc_max, nc_mu=nc_mu), all_smiles)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def mol2smiles(mol):
|
| 126 |
+
try:
|
| 127 |
+
Chem.SanitizeMol(mol)
|
| 128 |
+
except ValueError:
|
| 129 |
+
return None
|
| 130 |
+
return Chem.MolToSmiles(mol)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def build_molecule(atom_types, edge_types, atom_decoder, verbose=False):
|
| 134 |
+
if verbose:
|
| 135 |
+
print("building new molecule")
|
| 136 |
+
|
| 137 |
+
mol = Chem.RWMol()
|
| 138 |
+
for atom in atom_types:
|
| 139 |
+
a = Chem.Atom(atom_decoder[atom.item()])
|
| 140 |
+
mol.AddAtom(a)
|
| 141 |
+
if verbose:
|
| 142 |
+
print("Atom added: ", atom.item(), atom_decoder[atom.item()])
|
| 143 |
+
|
| 144 |
+
edge_types = torch.triu(edge_types)
|
| 145 |
+
all_bonds = torch.nonzero(edge_types)
|
| 146 |
+
for i, bond in enumerate(all_bonds):
|
| 147 |
+
if bond[0].item() != bond[1].item():
|
| 148 |
+
mol.AddBond(bond[0].item(), bond[1].item(), bond_dict[edge_types[bond[0], bond[1]].item()])
|
| 149 |
+
if verbose:
|
| 150 |
+
print("bond added:", bond[0].item(), bond[1].item(), edge_types[bond[0], bond[1]].item(),
|
| 151 |
+
bond_dict[edge_types[bond[0], bond[1]].item()] )
|
| 152 |
+
return mol
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def build_molecule_with_partial_charges(atom_types, edge_types, atom_decoder, verbose=False):
|
| 156 |
+
if verbose:
|
| 157 |
+
print("\nbuilding new molecule")
|
| 158 |
+
|
| 159 |
+
mol = Chem.RWMol()
|
| 160 |
+
for atom in atom_types:
|
| 161 |
+
a = Chem.Atom(atom_decoder[atom.item()])
|
| 162 |
+
mol.AddAtom(a)
|
| 163 |
+
if verbose:
|
| 164 |
+
print("Atom added: ", atom.item(), atom_decoder[atom.item()])
|
| 165 |
+
edge_types = torch.triu(edge_types)
|
| 166 |
+
all_bonds = torch.nonzero(edge_types)
|
| 167 |
+
|
| 168 |
+
for i, bond in enumerate(all_bonds):
|
| 169 |
+
if bond[0].item() != bond[1].item():
|
| 170 |
+
mol.AddBond(bond[0].item(), bond[1].item(), bond_dict[edge_types[bond[0], bond[1]].item()])
|
| 171 |
+
if verbose:
|
| 172 |
+
print("bond added:", bond[0].item(), bond[1].item(), edge_types[bond[0], bond[1]].item(),
|
| 173 |
+
bond_dict[edge_types[bond[0], bond[1]].item()])
|
| 174 |
+
# add formal charge to atom: e.g. [O+], [N+], [S+]
|
| 175 |
+
# not support [O-], [N-], [S-], [NH+] etc.
|
| 176 |
+
flag, atomid_valence = check_valency(mol)
|
| 177 |
+
if verbose:
|
| 178 |
+
print("flag, valence", flag, atomid_valence)
|
| 179 |
+
if flag:
|
| 180 |
+
continue
|
| 181 |
+
else:
|
| 182 |
+
assert len(atomid_valence) == 2
|
| 183 |
+
idx = atomid_valence[0]
|
| 184 |
+
v = atomid_valence[1]
|
| 185 |
+
an = mol.GetAtomWithIdx(idx).GetAtomicNum()
|
| 186 |
+
if verbose:
|
| 187 |
+
print("atomic num of atom with a large valence", an)
|
| 188 |
+
if an in (7, 8, 16) and (v - ATOM_VALENCY[an]) == 1:
|
| 189 |
+
mol.GetAtomWithIdx(idx).SetFormalCharge(1)
|
| 190 |
+
# print("Formal charge added")
|
| 191 |
+
return mol
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
# Functions from GDSS
|
| 195 |
+
def check_valency(mol):
|
| 196 |
+
try:
|
| 197 |
+
Chem.SanitizeMol(mol, sanitizeOps=Chem.SanitizeFlags.SANITIZE_PROPERTIES)
|
| 198 |
+
return True, None
|
| 199 |
+
except ValueError as e:
|
| 200 |
+
e = str(e)
|
| 201 |
+
p = e.find('#')
|
| 202 |
+
e_sub = e[p:]
|
| 203 |
+
atomid_valence = list(map(int, re.findall(r'\d+', e_sub)))
|
| 204 |
+
return False, atomid_valence
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
def correct_mol(m):
|
| 208 |
+
# xsm = Chem.MolToSmiles(x, isomericSmiles=True)
|
| 209 |
+
mol = m
|
| 210 |
+
|
| 211 |
+
#####
|
| 212 |
+
no_correct = False
|
| 213 |
+
flag, _ = check_valency(mol)
|
| 214 |
+
if flag:
|
| 215 |
+
no_correct = True
|
| 216 |
+
|
| 217 |
+
while True:
|
| 218 |
+
flag, atomid_valence = check_valency(mol)
|
| 219 |
+
if flag:
|
| 220 |
+
break
|
| 221 |
+
else:
|
| 222 |
+
assert len(atomid_valence) == 2
|
| 223 |
+
idx = atomid_valence[0]
|
| 224 |
+
v = atomid_valence[1]
|
| 225 |
+
queue = []
|
| 226 |
+
check_idx = 0
|
| 227 |
+
for b in mol.GetAtomWithIdx(idx).GetBonds():
|
| 228 |
+
type = int(b.GetBondType())
|
| 229 |
+
queue.append((b.GetIdx(), type, b.GetBeginAtomIdx(), b.GetEndAtomIdx()))
|
| 230 |
+
if type == 12:
|
| 231 |
+
check_idx += 1
|
| 232 |
+
queue.sort(key=lambda tup: tup[1], reverse=True)
|
| 233 |
+
|
| 234 |
+
if queue[-1][1] == 12:
|
| 235 |
+
return None, no_correct
|
| 236 |
+
elif len(queue) > 0:
|
| 237 |
+
start = queue[check_idx][2]
|
| 238 |
+
end = queue[check_idx][3]
|
| 239 |
+
t = queue[check_idx][1] - 1
|
| 240 |
+
mol.RemoveBond(start, end)
|
| 241 |
+
if t >= 1:
|
| 242 |
+
mol.AddBond(start, end, bond_dict[t])
|
| 243 |
+
return mol, no_correct
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def valid_mol_can_with_seg(m, largest_connected_comp=True):
|
| 247 |
+
if m is None:
|
| 248 |
+
return None
|
| 249 |
+
sm = Chem.MolToSmiles(m, isomericSmiles=True)
|
| 250 |
+
if largest_connected_comp and '.' in sm:
|
| 251 |
+
vsm = [(s, len(s)) for s in sm.split('.')] # 'C.CC.CCc1ccc(N)cc1CCC=O'.split('.')
|
| 252 |
+
vsm.sort(key=lambda tup: tup[1], reverse=True)
|
| 253 |
+
mol = Chem.MolFromSmiles(vsm[0][0])
|
| 254 |
+
else:
|
| 255 |
+
mol = Chem.MolFromSmiles(sm)
|
| 256 |
+
return mol
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
if __name__ == '__main__':
|
| 260 |
+
smiles_mol = 'C1CCC1'
|
| 261 |
+
print("Smiles mol %s" % smiles_mol)
|
| 262 |
+
chem_mol = Chem.MolFromSmiles(smiles_mol)
|
| 263 |
+
block_mol = Chem.MolToMolBlock(chem_mol)
|
| 264 |
+
print("Block mol:")
|
| 265 |
+
print(block_mol)
|
| 266 |
+
|
| 267 |
+
use_rdkit = True
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
def check_stability(atom_types, edge_types, dataset_info, debug=False,atom_decoder=None):
|
| 271 |
+
if atom_decoder is None:
|
| 272 |
+
atom_decoder = dataset_info.atom_decoder
|
| 273 |
+
|
| 274 |
+
n_bonds = np.zeros(len(atom_types), dtype='int')
|
| 275 |
+
|
| 276 |
+
for i in range(len(atom_types)):
|
| 277 |
+
for j in range(i + 1, len(atom_types)):
|
| 278 |
+
n_bonds[i] += abs((edge_types[i, j] + edge_types[j, i])/2)
|
| 279 |
+
n_bonds[j] += abs((edge_types[i, j] + edge_types[j, i])/2)
|
| 280 |
+
n_stable_bonds = 0
|
| 281 |
+
for atom_type, atom_n_bond in zip(atom_types, n_bonds):
|
| 282 |
+
possible_bonds = allowed_bonds[atom_decoder[atom_type]]
|
| 283 |
+
if type(possible_bonds) == int:
|
| 284 |
+
is_stable = possible_bonds == atom_n_bond
|
| 285 |
+
else:
|
| 286 |
+
is_stable = atom_n_bond in possible_bonds
|
| 287 |
+
if not is_stable and debug:
|
| 288 |
+
print("Invalid bonds for molecule %s with %d bonds" % (atom_decoder[atom_type], atom_n_bond))
|
| 289 |
+
n_stable_bonds += int(is_stable)
|
| 290 |
+
|
| 291 |
+
molecule_stable = n_stable_bonds == len(atom_types)
|
| 292 |
+
return molecule_stable, n_stable_bonds, len(atom_types)
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
def compute_molecular_metrics(molecule_list, train_smiles, dataset_info):
|
| 296 |
+
""" molecule_list: (dict) """
|
| 297 |
+
|
| 298 |
+
if not dataset_info.remove_h:
|
| 299 |
+
print(f'Analyzing molecule stability...')
|
| 300 |
+
|
| 301 |
+
molecule_stable = 0
|
| 302 |
+
nr_stable_bonds = 0
|
| 303 |
+
n_atoms = 0
|
| 304 |
+
n_molecules = len(molecule_list)
|
| 305 |
+
|
| 306 |
+
for i, mol in enumerate(molecule_list):
|
| 307 |
+
atom_types, edge_types = mol
|
| 308 |
+
|
| 309 |
+
validity_results = check_stability(atom_types, edge_types, dataset_info)
|
| 310 |
+
|
| 311 |
+
molecule_stable += int(validity_results[0])
|
| 312 |
+
nr_stable_bonds += int(validity_results[1])
|
| 313 |
+
n_atoms += int(validity_results[2])
|
| 314 |
+
|
| 315 |
+
# Validity
|
| 316 |
+
fraction_mol_stable = molecule_stable / float(n_molecules)
|
| 317 |
+
fraction_atm_stable = nr_stable_bonds / float(n_atoms)
|
| 318 |
+
validity_dict = {'mol_stable': fraction_mol_stable, 'atm_stable': fraction_atm_stable}
|
| 319 |
+
if wandb.run:
|
| 320 |
+
wandb.log(validity_dict)
|
| 321 |
+
else:
|
| 322 |
+
validity_dict = {'mol_stable': -1, 'atm_stable': -1}
|
| 323 |
+
|
| 324 |
+
metrics = BasicMolecularMetrics(dataset_info, train_smiles)
|
| 325 |
+
rdkit_metrics = metrics.evaluate(molecule_list)
|
| 326 |
+
all_smiles = rdkit_metrics[-1]
|
| 327 |
+
if wandb.run:
|
| 328 |
+
nc = rdkit_metrics[-2]
|
| 329 |
+
dic = {'Validity': rdkit_metrics[0][0], 'Relaxed Validity': rdkit_metrics[0][1],
|
| 330 |
+
'Uniqueness': rdkit_metrics[0][2], 'Novelty': rdkit_metrics[0][3],
|
| 331 |
+
'nc_max': nc['nc_max'], 'nc_mu': nc['nc_mu']}
|
| 332 |
+
wandb.log(dic)
|
| 333 |
+
|
| 334 |
+
return validity_dict, rdkit_metrics, all_smiles
|
analysis/spectre_utils.py
ADDED
|
@@ -0,0 +1,928 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
###############################################################################
|
| 2 |
+
#
|
| 3 |
+
# Adapted from https://github.com/lrjconan/GRAN/ which in turn is adapted from https://github.com/JiaxuanYou/graph-generation
|
| 4 |
+
#
|
| 5 |
+
###############################################################################
|
| 6 |
+
# import graph_tool.all as gt
|
| 7 |
+
##Navigate to the ./util/orca directory and compile orca.cpp
|
| 8 |
+
# g++ -O2 -std=c++11 -o orca orca.cpp
|
| 9 |
+
import os
|
| 10 |
+
import copy
|
| 11 |
+
import torch
|
| 12 |
+
import torch.nn as nn
|
| 13 |
+
import numpy as np
|
| 14 |
+
import networkx as nx
|
| 15 |
+
import subprocess as sp
|
| 16 |
+
import concurrent.futures
|
| 17 |
+
|
| 18 |
+
import pygsp as pg
|
| 19 |
+
import secrets
|
| 20 |
+
from string import ascii_uppercase, digits
|
| 21 |
+
from datetime import datetime
|
| 22 |
+
from scipy.linalg import eigvalsh
|
| 23 |
+
from scipy.stats import chi2
|
| 24 |
+
from analysis.dist_helper import compute_mmd, gaussian_emd, gaussian, emd, gaussian_tv, disc
|
| 25 |
+
from torch_geometric.utils import to_networkx
|
| 26 |
+
import wandb
|
| 27 |
+
from collections import defaultdict
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
PRINT_TIME = False
|
| 31 |
+
__all__ = ['degree_stats', 'clustering_stats', 'orbit_stats_all', 'spectral_stats', 'eval_acc_lobster_graph']
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def degree_worker(G):
|
| 35 |
+
return np.array(nx.degree_histogram(G))
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def degree_stats(graph_ref_list, graph_pred_list, is_parallel=True, compute_emd=False):
|
| 39 |
+
''' Compute the distance between the degree distributions of two unordered sets of graphs.
|
| 40 |
+
Args:
|
| 41 |
+
graph_ref_list, graph_target_list: two lists of networkx graphs to be evaluated
|
| 42 |
+
'''
|
| 43 |
+
sample_ref = []
|
| 44 |
+
sample_pred = []
|
| 45 |
+
# in case an empty graph is generated
|
| 46 |
+
graph_pred_list_remove_empty = [
|
| 47 |
+
G for G in graph_pred_list if not G.number_of_nodes() == 0
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
prev = datetime.now()
|
| 51 |
+
if is_parallel:
|
| 52 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 53 |
+
for deg_hist in executor.map(degree_worker, graph_ref_list):
|
| 54 |
+
sample_ref.append(deg_hist)
|
| 55 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 56 |
+
for deg_hist in executor.map(degree_worker, graph_pred_list_remove_empty):
|
| 57 |
+
sample_pred.append(deg_hist)
|
| 58 |
+
else:
|
| 59 |
+
for i in range(len(graph_ref_list)):
|
| 60 |
+
degree_temp = np.array(nx.degree_histogram(graph_ref_list[i]))
|
| 61 |
+
sample_ref.append(degree_temp)
|
| 62 |
+
for i in range(len(graph_pred_list_remove_empty)):
|
| 63 |
+
degree_temp = np.array(
|
| 64 |
+
nx.degree_histogram(graph_pred_list_remove_empty[i]))
|
| 65 |
+
sample_pred.append(degree_temp)
|
| 66 |
+
|
| 67 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_emd)
|
| 68 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=emd)
|
| 69 |
+
if compute_emd:
|
| 70 |
+
# EMD option uses the same computation as GraphRNN, the alternative is MMD as computed by GRAN
|
| 71 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=emd)
|
| 72 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_emd)
|
| 73 |
+
else:
|
| 74 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_tv)
|
| 75 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian)
|
| 76 |
+
|
| 77 |
+
elapsed = datetime.now() - prev
|
| 78 |
+
if PRINT_TIME:
|
| 79 |
+
print('Time computing degree mmd: ', elapsed)
|
| 80 |
+
return mmd_dist
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
###############################################################################
|
| 84 |
+
|
| 85 |
+
def spectral_worker(G, n_eigvals=-1):
|
| 86 |
+
# eigs = nx.laplacian_spectrum(G)
|
| 87 |
+
try:
|
| 88 |
+
eigs = eigvalsh(nx.normalized_laplacian_matrix(G).todense())
|
| 89 |
+
except:
|
| 90 |
+
eigs = np.zeros(G.number_of_nodes())
|
| 91 |
+
if n_eigvals > 0:
|
| 92 |
+
eigs = eigs[1:n_eigvals + 1]
|
| 93 |
+
spectral_pmf, _ = np.histogram(eigs, bins=200, range=(-1e-5, 2), density=False)
|
| 94 |
+
spectral_pmf = spectral_pmf / spectral_pmf.sum()
|
| 95 |
+
return spectral_pmf
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def get_spectral_pmf(eigs, max_eig):
|
| 99 |
+
spectral_pmf, _ = np.histogram(np.clip(eigs, 0, max_eig), bins=200, range=(-1e-5, max_eig), density=False)
|
| 100 |
+
spectral_pmf = spectral_pmf / spectral_pmf.sum()
|
| 101 |
+
return spectral_pmf
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
def eigval_stats(eig_ref_list, eig_pred_list, max_eig=20, is_parallel=True, compute_emd=False):
|
| 105 |
+
''' Compute the distance between the degree distributions of two unordered sets of graphs.
|
| 106 |
+
Args:
|
| 107 |
+
graph_ref_list, graph_target_list: two lists of networkx graphs to be evaluated
|
| 108 |
+
'''
|
| 109 |
+
sample_ref = []
|
| 110 |
+
sample_pred = []
|
| 111 |
+
|
| 112 |
+
prev = datetime.now()
|
| 113 |
+
if is_parallel:
|
| 114 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 115 |
+
for spectral_density in executor.map(get_spectral_pmf, eig_ref_list,
|
| 116 |
+
[max_eig for i in range(len(eig_ref_list))]):
|
| 117 |
+
sample_ref.append(spectral_density)
|
| 118 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 119 |
+
for spectral_density in executor.map(get_spectral_pmf, eig_pred_list,
|
| 120 |
+
[max_eig for i in range(len(eig_ref_list))]):
|
| 121 |
+
sample_pred.append(spectral_density)
|
| 122 |
+
else:
|
| 123 |
+
for i in range(len(eig_ref_list)):
|
| 124 |
+
spectral_temp = get_spectral_pmf(eig_ref_list[i])
|
| 125 |
+
sample_ref.append(spectral_temp)
|
| 126 |
+
for i in range(len(eig_pred_list)):
|
| 127 |
+
spectral_temp = get_spectral_pmf(eig_pred_list[i])
|
| 128 |
+
sample_pred.append(spectral_temp)
|
| 129 |
+
|
| 130 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_emd)
|
| 131 |
+
if compute_emd:
|
| 132 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=emd)
|
| 133 |
+
else:
|
| 134 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_tv)
|
| 135 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian)
|
| 136 |
+
|
| 137 |
+
elapsed = datetime.now() - prev
|
| 138 |
+
if PRINT_TIME:
|
| 139 |
+
print('Time computing eig mmd: ', elapsed)
|
| 140 |
+
return mmd_dist
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def eigh_worker(G):
|
| 144 |
+
L = nx.normalized_laplacian_matrix(G).todense()
|
| 145 |
+
try:
|
| 146 |
+
eigvals, eigvecs = np.linalg.eigh(L)
|
| 147 |
+
except:
|
| 148 |
+
eigvals = np.zeros(L[0, :].shape)
|
| 149 |
+
eigvecs = np.zeros(L.shape)
|
| 150 |
+
return (eigvals, eigvecs)
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def compute_list_eigh(graph_list, is_parallel=False):
|
| 154 |
+
eigval_list = []
|
| 155 |
+
eigvec_list = []
|
| 156 |
+
if is_parallel:
|
| 157 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 158 |
+
for e_U in executor.map(eigh_worker, graph_list):
|
| 159 |
+
eigval_list.append(e_U[0])
|
| 160 |
+
eigvec_list.append(e_U[1])
|
| 161 |
+
else:
|
| 162 |
+
for i in range(len(graph_list)):
|
| 163 |
+
e_U = eigh_worker(graph_list[i])
|
| 164 |
+
eigval_list.append(e_U[0])
|
| 165 |
+
eigvec_list.append(e_U[1])
|
| 166 |
+
return eigval_list, eigvec_list
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def get_spectral_filter_worker(eigvec, eigval, filters, bound=1.4):
|
| 170 |
+
ges = filters.evaluate(eigval)
|
| 171 |
+
linop = []
|
| 172 |
+
for ge in ges:
|
| 173 |
+
linop.append(eigvec @ np.diag(ge) @ eigvec.T)
|
| 174 |
+
linop = np.array(linop)
|
| 175 |
+
norm_filt = np.sum(linop ** 2, axis=2)
|
| 176 |
+
hist_range = [0, bound]
|
| 177 |
+
hist = np.array([np.histogram(x, range=hist_range, bins=100)[0] for x in norm_filt]) # NOTE: change number of bins
|
| 178 |
+
return hist.flatten()
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def spectral_filter_stats(eigvec_ref_list, eigval_ref_list, eigvec_pred_list, eigval_pred_list, is_parallel=False,
|
| 182 |
+
compute_emd=False):
|
| 183 |
+
''' Compute the distance between the eigvector sets.
|
| 184 |
+
Args:
|
| 185 |
+
graph_ref_list, graph_target_list: two lists of networkx graphs to be evaluated
|
| 186 |
+
'''
|
| 187 |
+
prev = datetime.now()
|
| 188 |
+
|
| 189 |
+
class DMG(object):
|
| 190 |
+
"""Dummy Normalized Graph"""
|
| 191 |
+
lmax = 2
|
| 192 |
+
|
| 193 |
+
n_filters = 12
|
| 194 |
+
filters = pg.filters.Abspline(DMG, n_filters)
|
| 195 |
+
bound = np.max(filters.evaluate(np.arange(0, 2, 0.01)))
|
| 196 |
+
sample_ref = []
|
| 197 |
+
sample_pred = []
|
| 198 |
+
if is_parallel:
|
| 199 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 200 |
+
for spectral_density in executor.map(get_spectral_filter_worker, eigvec_ref_list, eigval_ref_list,
|
| 201 |
+
[filters for i in range(len(eigval_ref_list))],
|
| 202 |
+
[bound for i in range(len(eigval_ref_list))]):
|
| 203 |
+
sample_ref.append(spectral_density)
|
| 204 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 205 |
+
for spectral_density in executor.map(get_spectral_filter_worker, eigvec_pred_list, eigval_pred_list,
|
| 206 |
+
[filters for i in range(len(eigval_ref_list))],
|
| 207 |
+
[bound for i in range(len(eigval_ref_list))]):
|
| 208 |
+
sample_pred.append(spectral_density)
|
| 209 |
+
else:
|
| 210 |
+
for i in range(len(eigval_ref_list)):
|
| 211 |
+
try:
|
| 212 |
+
spectral_temp = get_spectral_filter_worker(eigvec_ref_list[i], eigval_ref_list[i], filters, bound)
|
| 213 |
+
sample_ref.append(spectral_temp)
|
| 214 |
+
except:
|
| 215 |
+
pass
|
| 216 |
+
for i in range(len(eigval_pred_list)):
|
| 217 |
+
try:
|
| 218 |
+
spectral_temp = get_spectral_filter_worker(eigvec_pred_list[i], eigval_pred_list[i], filters, bound)
|
| 219 |
+
sample_pred.append(spectral_temp)
|
| 220 |
+
except:
|
| 221 |
+
pass
|
| 222 |
+
|
| 223 |
+
if compute_emd:
|
| 224 |
+
# EMD option uses the same computation as GraphRNN, the alternative is MMD as computed by GRAN
|
| 225 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=emd)
|
| 226 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_emd)
|
| 227 |
+
else:
|
| 228 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_tv)
|
| 229 |
+
|
| 230 |
+
elapsed = datetime.now() - prev
|
| 231 |
+
if PRINT_TIME:
|
| 232 |
+
print('Time computing spectral filter stats: ', elapsed)
|
| 233 |
+
return mmd_dist
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
def spectral_stats(graph_ref_list, graph_pred_list, is_parallel=True, n_eigvals=-1, compute_emd=False):
|
| 237 |
+
''' Compute the distance between the degree distributions of two unordered sets of graphs.
|
| 238 |
+
Args:
|
| 239 |
+
graph_ref_list, graph_target_list: two lists of networkx graphs to be evaluated
|
| 240 |
+
'''
|
| 241 |
+
sample_ref = []
|
| 242 |
+
sample_pred = []
|
| 243 |
+
# in case an empty graph is generated
|
| 244 |
+
graph_pred_list_remove_empty = [
|
| 245 |
+
G for G in graph_pred_list if not G.number_of_nodes() == 0
|
| 246 |
+
]
|
| 247 |
+
|
| 248 |
+
prev = datetime.now()
|
| 249 |
+
if is_parallel:
|
| 250 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 251 |
+
for spectral_density in executor.map(spectral_worker, graph_ref_list, [n_eigvals for i in graph_ref_list]):
|
| 252 |
+
sample_ref.append(spectral_density)
|
| 253 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 254 |
+
for spectral_density in executor.map(spectral_worker, graph_pred_list_remove_empty,
|
| 255 |
+
[n_eigvals for i in graph_ref_list]):
|
| 256 |
+
sample_pred.append(spectral_density)
|
| 257 |
+
else:
|
| 258 |
+
for i in range(len(graph_ref_list)):
|
| 259 |
+
spectral_temp = spectral_worker(graph_ref_list[i], n_eigvals)
|
| 260 |
+
sample_ref.append(spectral_temp)
|
| 261 |
+
for i in range(len(graph_pred_list_remove_empty)):
|
| 262 |
+
spectral_temp = spectral_worker(graph_pred_list_remove_empty[i], n_eigvals)
|
| 263 |
+
sample_pred.append(spectral_temp)
|
| 264 |
+
|
| 265 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_emd)
|
| 266 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=emd)
|
| 267 |
+
if compute_emd:
|
| 268 |
+
# EMD option uses the same computation as GraphRNN, the alternative is MMD as computed by GRAN
|
| 269 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=emd)
|
| 270 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_emd)
|
| 271 |
+
else:
|
| 272 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_tv)
|
| 273 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian)
|
| 274 |
+
|
| 275 |
+
elapsed = datetime.now() - prev
|
| 276 |
+
if PRINT_TIME:
|
| 277 |
+
print('Time computing degree mmd: ', elapsed)
|
| 278 |
+
return mmd_dist
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
###############################################################################
|
| 282 |
+
|
| 283 |
+
def clustering_worker(param):
|
| 284 |
+
G, bins = param
|
| 285 |
+
clustering_coeffs_list = list(nx.clustering(G).values())
|
| 286 |
+
hist, _ = np.histogram(
|
| 287 |
+
clustering_coeffs_list, bins=bins, range=(0.0, 1.0), density=False)
|
| 288 |
+
return hist
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
def clustering_stats(graph_ref_list,
|
| 292 |
+
graph_pred_list,
|
| 293 |
+
bins=100,
|
| 294 |
+
is_parallel=True, compute_emd=False):
|
| 295 |
+
sample_ref = []
|
| 296 |
+
sample_pred = []
|
| 297 |
+
graph_pred_list_remove_empty = [
|
| 298 |
+
G for G in graph_pred_list if not G.number_of_nodes() == 0
|
| 299 |
+
]
|
| 300 |
+
|
| 301 |
+
prev = datetime.now()
|
| 302 |
+
if is_parallel:
|
| 303 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 304 |
+
for clustering_hist in executor.map(clustering_worker,
|
| 305 |
+
[(G, bins) for G in graph_ref_list]):
|
| 306 |
+
sample_ref.append(clustering_hist)
|
| 307 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 308 |
+
for clustering_hist in executor.map(
|
| 309 |
+
clustering_worker, [(G, bins) for G in graph_pred_list_remove_empty]):
|
| 310 |
+
sample_pred.append(clustering_hist)
|
| 311 |
+
|
| 312 |
+
# check non-zero elements in hist
|
| 313 |
+
# total = 0
|
| 314 |
+
# for i in range(len(sample_pred)):
|
| 315 |
+
# nz = np.nonzero(sample_pred[i])[0].shape[0]
|
| 316 |
+
# total += nz
|
| 317 |
+
# print(total)
|
| 318 |
+
else:
|
| 319 |
+
for i in range(len(graph_ref_list)):
|
| 320 |
+
clustering_coeffs_list = list(nx.clustering(graph_ref_list[i]).values())
|
| 321 |
+
hist, _ = np.histogram(
|
| 322 |
+
clustering_coeffs_list, bins=bins, range=(0.0, 1.0), density=False)
|
| 323 |
+
sample_ref.append(hist)
|
| 324 |
+
|
| 325 |
+
for i in range(len(graph_pred_list_remove_empty)):
|
| 326 |
+
clustering_coeffs_list = list(
|
| 327 |
+
nx.clustering(graph_pred_list_remove_empty[i]).values())
|
| 328 |
+
hist, _ = np.histogram(
|
| 329 |
+
clustering_coeffs_list, bins=bins, range=(0.0, 1.0), density=False)
|
| 330 |
+
sample_pred.append(hist)
|
| 331 |
+
|
| 332 |
+
if compute_emd:
|
| 333 |
+
# EMD option uses the same computation as GraphRNN, the alternative is MMD as computed by GRAN
|
| 334 |
+
# mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=emd, sigma=1.0 / 10)
|
| 335 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_emd, sigma=1.0 / 10, distance_scaling=bins)
|
| 336 |
+
else:
|
| 337 |
+
mmd_dist = compute_mmd(sample_ref, sample_pred, kernel=gaussian_tv, sigma=1.0 / 10)
|
| 338 |
+
|
| 339 |
+
elapsed = datetime.now() - prev
|
| 340 |
+
if PRINT_TIME:
|
| 341 |
+
print('Time computing clustering mmd: ', elapsed)
|
| 342 |
+
return mmd_dist
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
# maps motif/orbit name string to its corresponding list of indices from orca output
|
| 346 |
+
motif_to_indices = {
|
| 347 |
+
'3path': [1, 2],
|
| 348 |
+
'4cycle': [8],
|
| 349 |
+
}
|
| 350 |
+
COUNT_START_STR = 'orbit counts:'
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
def edge_list_reindexed(G):
|
| 354 |
+
idx = 0
|
| 355 |
+
id2idx = dict()
|
| 356 |
+
for u in G.nodes():
|
| 357 |
+
id2idx[str(u)] = idx
|
| 358 |
+
idx += 1
|
| 359 |
+
|
| 360 |
+
edges = []
|
| 361 |
+
for (u, v) in G.edges():
|
| 362 |
+
edges.append((id2idx[str(u)], id2idx[str(v)]))
|
| 363 |
+
return edges
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
def orca(graph):
|
| 367 |
+
# tmp_fname = f'analysis/orca/tmp_{"".join(secrets.choice(ascii_uppercase + digits) for i in range(8))}.txt'
|
| 368 |
+
tmp_fname = f'orca/tmp_{"".join(secrets.choice(ascii_uppercase + digits) for i in range(8))}.txt'
|
| 369 |
+
tmp_fname = os.path.join(os.path.dirname(os.path.realpath(__file__)), tmp_fname)
|
| 370 |
+
# print(tmp_fname, flush=True)
|
| 371 |
+
f = open(tmp_fname, 'w')
|
| 372 |
+
f.write(
|
| 373 |
+
str(graph.number_of_nodes()) + ' ' + str(graph.number_of_edges()) + '\n')
|
| 374 |
+
for (u, v) in edge_list_reindexed(graph):
|
| 375 |
+
f.write(str(u) + ' ' + str(v) + '\n')
|
| 376 |
+
f.close()
|
| 377 |
+
output = sp.check_output(
|
| 378 |
+
[str(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'orca/orca')), 'node', '4', tmp_fname, 'std'])
|
| 379 |
+
output = output.decode('utf8').strip()
|
| 380 |
+
idx = output.find(COUNT_START_STR) + len(COUNT_START_STR) + 2
|
| 381 |
+
output = output[idx:]
|
| 382 |
+
node_orbit_counts = np.array([
|
| 383 |
+
list(map(int,
|
| 384 |
+
node_cnts.strip().split(' ')))
|
| 385 |
+
for node_cnts in output.strip('\n').split('\n')
|
| 386 |
+
])
|
| 387 |
+
|
| 388 |
+
try:
|
| 389 |
+
os.remove(tmp_fname)
|
| 390 |
+
except OSError:
|
| 391 |
+
pass
|
| 392 |
+
|
| 393 |
+
return node_orbit_counts
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
def motif_stats(graph_ref_list, graph_pred_list, motif_type='4cycle', ground_truth_match=None,
|
| 397 |
+
bins=100, compute_emd=False):
|
| 398 |
+
# graph motif counts (int for each graph)
|
| 399 |
+
# normalized by graph size
|
| 400 |
+
total_counts_ref = []
|
| 401 |
+
total_counts_pred = []
|
| 402 |
+
|
| 403 |
+
num_matches_ref = []
|
| 404 |
+
num_matches_pred = []
|
| 405 |
+
|
| 406 |
+
graph_pred_list_remove_empty = [G for G in graph_pred_list if not G.number_of_nodes() == 0]
|
| 407 |
+
indices = motif_to_indices[motif_type]
|
| 408 |
+
|
| 409 |
+
for G in graph_ref_list:
|
| 410 |
+
orbit_counts = orca(G)
|
| 411 |
+
motif_counts = np.sum(orbit_counts[:, indices], axis=1)
|
| 412 |
+
|
| 413 |
+
if ground_truth_match is not None:
|
| 414 |
+
match_cnt = 0
|
| 415 |
+
for elem in motif_counts:
|
| 416 |
+
if elem == ground_truth_match:
|
| 417 |
+
match_cnt += 1
|
| 418 |
+
num_matches_ref.append(match_cnt / G.number_of_nodes())
|
| 419 |
+
|
| 420 |
+
# hist, _ = np.histogram(
|
| 421 |
+
# motif_counts, bins=bins, density=False)
|
| 422 |
+
motif_temp = np.sum(motif_counts) / G.number_of_nodes()
|
| 423 |
+
total_counts_ref.append(motif_temp)
|
| 424 |
+
|
| 425 |
+
for G in graph_pred_list_remove_empty:
|
| 426 |
+
orbit_counts = orca(G)
|
| 427 |
+
motif_counts = np.sum(orbit_counts[:, indices], axis=1)
|
| 428 |
+
|
| 429 |
+
if ground_truth_match is not None:
|
| 430 |
+
match_cnt = 0
|
| 431 |
+
for elem in motif_counts:
|
| 432 |
+
if elem == ground_truth_match:
|
| 433 |
+
match_cnt += 1
|
| 434 |
+
num_matches_pred.append(match_cnt / G.number_of_nodes())
|
| 435 |
+
|
| 436 |
+
motif_temp = np.sum(motif_counts) / G.number_of_nodes()
|
| 437 |
+
total_counts_pred.append(motif_temp)
|
| 438 |
+
|
| 439 |
+
total_counts_ref = np.array(total_counts_ref)[:, None]
|
| 440 |
+
total_counts_pred = np.array(total_counts_pred)[:, None]
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
if compute_emd:
|
| 444 |
+
# EMD option uses the same computation as GraphRNN, the alternative is MMD as computed by GRAN
|
| 445 |
+
# mmd_dist = compute_mmd(total_counts_ref, total_counts_pred, kernel=emd, is_hist=False)
|
| 446 |
+
mmd_dist = compute_mmd(total_counts_ref, total_counts_pred, kernel=gaussian, is_hist=False)
|
| 447 |
+
else:
|
| 448 |
+
mmd_dist = compute_mmd(total_counts_ref, total_counts_pred, kernel=gaussian, is_hist=False)
|
| 449 |
+
return mmd_dist
|
| 450 |
+
|
| 451 |
+
|
| 452 |
+
def orbit_stats_all(graph_ref_list, graph_pred_list, compute_emd=False):
|
| 453 |
+
total_counts_ref = []
|
| 454 |
+
total_counts_pred = []
|
| 455 |
+
|
| 456 |
+
graph_pred_list_remove_empty = [
|
| 457 |
+
G for G in graph_pred_list if not G.number_of_nodes() == 0
|
| 458 |
+
]
|
| 459 |
+
|
| 460 |
+
for G in graph_ref_list:
|
| 461 |
+
orbit_counts = orca(G)
|
| 462 |
+
orbit_counts_graph = np.sum(orbit_counts, axis=0) / G.number_of_nodes()
|
| 463 |
+
total_counts_ref.append(orbit_counts_graph)
|
| 464 |
+
|
| 465 |
+
for G in graph_pred_list:
|
| 466 |
+
orbit_counts = orca(G)
|
| 467 |
+
orbit_counts_graph = np.sum(orbit_counts, axis=0) / G.number_of_nodes()
|
| 468 |
+
total_counts_pred.append(orbit_counts_graph)
|
| 469 |
+
|
| 470 |
+
total_counts_ref = np.array(total_counts_ref)
|
| 471 |
+
total_counts_pred = np.array(total_counts_pred)
|
| 472 |
+
|
| 473 |
+
# mmd_dist = compute_mmd(
|
| 474 |
+
# total_counts_ref,
|
| 475 |
+
# total_counts_pred,
|
| 476 |
+
# kernel=gaussian,
|
| 477 |
+
# is_hist=False,
|
| 478 |
+
# sigma=30.0)
|
| 479 |
+
|
| 480 |
+
# mmd_dist = compute_mmd(
|
| 481 |
+
# total_counts_ref,
|
| 482 |
+
# total_counts_pred,
|
| 483 |
+
# kernel=gaussian_tv,
|
| 484 |
+
# is_hist=False,
|
| 485 |
+
# sigma=30.0)
|
| 486 |
+
|
| 487 |
+
if compute_emd:
|
| 488 |
+
# mmd_dist = compute_mmd(total_counts_ref, total_counts_pred, kernel=emd, sigma=30.0)
|
| 489 |
+
# EMD option uses the same computation as GraphRNN, the alternative is MMD as computed by GRAN
|
| 490 |
+
mmd_dist = compute_mmd(total_counts_ref, total_counts_pred, kernel=gaussian, is_hist=False, sigma=30.0)
|
| 491 |
+
else:
|
| 492 |
+
mmd_dist = compute_mmd(total_counts_ref, total_counts_pred, kernel=gaussian_tv, is_hist=False, sigma=30.0)
|
| 493 |
+
return mmd_dist
|
| 494 |
+
|
| 495 |
+
|
| 496 |
+
def eval_acc_lobster_graph(G_list):
|
| 497 |
+
G_list = [copy.deepcopy(gg) for gg in G_list]
|
| 498 |
+
count = 0
|
| 499 |
+
for gg in G_list:
|
| 500 |
+
if is_lobster_graph(gg):
|
| 501 |
+
count += 1
|
| 502 |
+
return count / float(len(G_list))
|
| 503 |
+
|
| 504 |
+
|
| 505 |
+
def eval_acc_tree_graph(G_list):
|
| 506 |
+
count = 0
|
| 507 |
+
for gg in G_list:
|
| 508 |
+
if nx.is_tree(gg):
|
| 509 |
+
count += 1
|
| 510 |
+
return count / float(len(G_list))
|
| 511 |
+
|
| 512 |
+
|
| 513 |
+
def eval_acc_grid_graph(G_list, grid_start=10, grid_end=20):
|
| 514 |
+
count = 0
|
| 515 |
+
for gg in G_list:
|
| 516 |
+
if is_grid_graph(gg):
|
| 517 |
+
count += 1
|
| 518 |
+
return count / float(len(G_list))
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
def eval_acc_sbm_graph(G_list, p_intra=0.3, p_inter=0.005, strict=True, refinement_steps=1000, is_parallel=True):
|
| 522 |
+
count = 0.0
|
| 523 |
+
if is_parallel:
|
| 524 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 525 |
+
for prob in executor.map(is_sbm_graph,
|
| 526 |
+
[gg for gg in G_list], [p_intra for i in range(len(G_list))],
|
| 527 |
+
[p_inter for i in range(len(G_list))],
|
| 528 |
+
[strict for i in range(len(G_list))],
|
| 529 |
+
[refinement_steps for i in range(len(G_list))]):
|
| 530 |
+
count += prob
|
| 531 |
+
else:
|
| 532 |
+
for gg in G_list:
|
| 533 |
+
count += is_sbm_graph(gg, p_intra=p_intra, p_inter=p_inter, strict=strict,
|
| 534 |
+
refinement_steps=refinement_steps)
|
| 535 |
+
return count / float(len(G_list))
|
| 536 |
+
|
| 537 |
+
|
| 538 |
+
def eval_acc_planar_graph(G_list):
|
| 539 |
+
count = 0
|
| 540 |
+
for gg in G_list:
|
| 541 |
+
if is_planar_graph(gg):
|
| 542 |
+
count += 1
|
| 543 |
+
return count / float(len(G_list))
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def is_planar_graph(G):
|
| 547 |
+
return nx.is_connected(G) and nx.check_planarity(G)[0]
|
| 548 |
+
|
| 549 |
+
|
| 550 |
+
def is_lobster_graph(G):
|
| 551 |
+
"""
|
| 552 |
+
Check a given graph is a lobster graph or not
|
| 553 |
+
|
| 554 |
+
Removing leaf nodes twice:
|
| 555 |
+
|
| 556 |
+
lobster -> caterpillar -> path
|
| 557 |
+
|
| 558 |
+
"""
|
| 559 |
+
### Check if G is a tree
|
| 560 |
+
if nx.is_tree(G):
|
| 561 |
+
G = G.copy()
|
| 562 |
+
### Check if G is a path after removing leaves twice
|
| 563 |
+
leaves = [n for n, d in G.degree() if d == 1]
|
| 564 |
+
G.remove_nodes_from(leaves)
|
| 565 |
+
|
| 566 |
+
leaves = [n for n, d in G.degree() if d == 1]
|
| 567 |
+
G.remove_nodes_from(leaves)
|
| 568 |
+
|
| 569 |
+
num_nodes = len(G.nodes())
|
| 570 |
+
num_degree_one = [d for n, d in G.degree() if d == 1]
|
| 571 |
+
num_degree_two = [d for n, d in G.degree() if d == 2]
|
| 572 |
+
|
| 573 |
+
if sum(num_degree_one) == 2 and sum(num_degree_two) == 2 * (num_nodes - 2):
|
| 574 |
+
return True
|
| 575 |
+
elif sum(num_degree_one) == 0 and sum(num_degree_two) == 0:
|
| 576 |
+
return True
|
| 577 |
+
else:
|
| 578 |
+
return False
|
| 579 |
+
else:
|
| 580 |
+
return False
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
def is_grid_graph(G):
|
| 584 |
+
"""
|
| 585 |
+
Check if the graph is grid, by comparing with all the real grids with the same node count
|
| 586 |
+
"""
|
| 587 |
+
all_grid_file = f"data/all_grids.pt"
|
| 588 |
+
if os.path.isfile(all_grid_file):
|
| 589 |
+
all_grids = torch.load(all_grid_file)
|
| 590 |
+
else:
|
| 591 |
+
all_grids = {}
|
| 592 |
+
for i in range(2, 20):
|
| 593 |
+
for j in range(2, 20):
|
| 594 |
+
G_grid = nx.grid_2d_graph(i, j)
|
| 595 |
+
n_nodes = f"{len(G_grid.nodes())}"
|
| 596 |
+
all_grids[n_nodes] = all_grids.get(n_nodes, []) + [G_grid]
|
| 597 |
+
torch.save(all_grids, all_grid_file)
|
| 598 |
+
|
| 599 |
+
n_nodes = f"{len(G.nodes())}"
|
| 600 |
+
if n_nodes in all_grids:
|
| 601 |
+
for G_grid in all_grids[n_nodes]:
|
| 602 |
+
if nx.faster_could_be_isomorphic(G, G_grid):
|
| 603 |
+
if nx.is_isomorphic(G, G_grid):
|
| 604 |
+
return True
|
| 605 |
+
return False
|
| 606 |
+
else:
|
| 607 |
+
return False
|
| 608 |
+
|
| 609 |
+
|
| 610 |
+
# def is_sbm_graph(G, p_intra=0.3, p_inter=0.005, strict=True, refinement_steps=1000):
|
| 611 |
+
# """
|
| 612 |
+
# Check if how closely given graph matches a SBM with given probabilites by computing mean probability of Wald test statistic for each recovered parameter
|
| 613 |
+
# """
|
| 614 |
+
|
| 615 |
+
# adj = nx.adjacency_matrix(G).toarray()
|
| 616 |
+
# idx = adj.nonzero()
|
| 617 |
+
# g = gt.Graph()
|
| 618 |
+
# g.add_edge_list(np.transpose(idx))
|
| 619 |
+
# try:
|
| 620 |
+
# state = gt.minimize_blockmodel_dl(g)
|
| 621 |
+
# except ValueError:
|
| 622 |
+
# if strict:
|
| 623 |
+
# return False
|
| 624 |
+
# else:
|
| 625 |
+
# return 0.0
|
| 626 |
+
|
| 627 |
+
# # Refine using merge-split MCMC
|
| 628 |
+
# for i in range(refinement_steps):
|
| 629 |
+
# state.multiflip_mcmc_sweep(beta=np.inf, niter=10)
|
| 630 |
+
|
| 631 |
+
# b = state.get_blocks()
|
| 632 |
+
# b = gt.contiguous_map(state.get_blocks())
|
| 633 |
+
# state = state.copy(b=b)
|
| 634 |
+
# e = state.get_matrix()
|
| 635 |
+
# n_blocks = state.get_nonempty_B()
|
| 636 |
+
# node_counts = state.get_nr().get_array()[:n_blocks]
|
| 637 |
+
# edge_counts = e.todense()[:n_blocks, :n_blocks]
|
| 638 |
+
# if strict:
|
| 639 |
+
# if (node_counts > 40).sum() > 0 or (node_counts < 20).sum() > 0 or n_blocks > 5 or n_blocks < 2:
|
| 640 |
+
# return False
|
| 641 |
+
|
| 642 |
+
# max_intra_edges = node_counts * (node_counts - 1)
|
| 643 |
+
# est_p_intra = np.diagonal(edge_counts) / (max_intra_edges + 1e-6)
|
| 644 |
+
|
| 645 |
+
# max_inter_edges = node_counts.reshape((-1, 1)) @ node_counts.reshape((1, -1))
|
| 646 |
+
# np.fill_diagonal(edge_counts, 0)
|
| 647 |
+
# est_p_inter = edge_counts / (max_inter_edges + 1e-6)
|
| 648 |
+
|
| 649 |
+
# W_p_intra = (est_p_intra - p_intra) ** 2 / (est_p_intra * (1 - est_p_intra) + 1e-6)
|
| 650 |
+
# W_p_inter = (est_p_inter - p_inter) ** 2 / (est_p_inter * (1 - est_p_inter) + 1e-6)
|
| 651 |
+
|
| 652 |
+
# W = W_p_inter.copy()
|
| 653 |
+
# np.fill_diagonal(W, W_p_intra)
|
| 654 |
+
# p = 1 - chi2.cdf(abs(W), 1)
|
| 655 |
+
# p = p.mean()
|
| 656 |
+
# if strict:
|
| 657 |
+
# return p > 0.9 # p value < 10 %
|
| 658 |
+
# else:
|
| 659 |
+
# return p
|
| 660 |
+
|
| 661 |
+
|
| 662 |
+
def eval_fraction_isomorphic(fake_graphs, train_graphs):
|
| 663 |
+
count = 0
|
| 664 |
+
for fake_g in fake_graphs:
|
| 665 |
+
for train_g in train_graphs:
|
| 666 |
+
if nx.faster_could_be_isomorphic(fake_g, train_g):
|
| 667 |
+
if nx.is_isomorphic(fake_g, train_g):
|
| 668 |
+
count += 1
|
| 669 |
+
break
|
| 670 |
+
return count / float(len(fake_graphs))
|
| 671 |
+
|
| 672 |
+
|
| 673 |
+
def eval_fraction_unique(fake_graphs, precise=False):
|
| 674 |
+
count_non_unique = 0
|
| 675 |
+
fake_evaluated = []
|
| 676 |
+
for fake_g in fake_graphs:
|
| 677 |
+
unique = True
|
| 678 |
+
if not fake_g.number_of_nodes() == 0:
|
| 679 |
+
for fake_old in fake_evaluated:
|
| 680 |
+
if precise:
|
| 681 |
+
if nx.faster_could_be_isomorphic(fake_g, fake_old):
|
| 682 |
+
if nx.is_isomorphic(fake_g, fake_old):
|
| 683 |
+
count_non_unique += 1
|
| 684 |
+
unique = False
|
| 685 |
+
break
|
| 686 |
+
else:
|
| 687 |
+
if nx.faster_could_be_isomorphic(fake_g, fake_old):
|
| 688 |
+
if nx.could_be_isomorphic(fake_g, fake_old):
|
| 689 |
+
count_non_unique += 1
|
| 690 |
+
unique = False
|
| 691 |
+
break
|
| 692 |
+
if unique:
|
| 693 |
+
fake_evaluated.append(fake_g)
|
| 694 |
+
|
| 695 |
+
frac_unique = (float(len(fake_graphs)) - count_non_unique) / float(
|
| 696 |
+
len(fake_graphs)) # Fraction of distinct isomorphism classes in the fake graphs
|
| 697 |
+
|
| 698 |
+
return frac_unique
|
| 699 |
+
|
| 700 |
+
|
| 701 |
+
def eval_fraction_unique_non_isomorphic_valid(fake_graphs, train_graphs, validity_func=(lambda x: True)):
|
| 702 |
+
count_valid = 0
|
| 703 |
+
count_isomorphic = 0
|
| 704 |
+
count_non_unique = 0
|
| 705 |
+
fake_evaluated = []
|
| 706 |
+
for fake_g in fake_graphs:
|
| 707 |
+
unique = True
|
| 708 |
+
|
| 709 |
+
for fake_old in fake_evaluated:
|
| 710 |
+
if nx.faster_could_be_isomorphic(fake_g, fake_old):
|
| 711 |
+
if nx.is_isomorphic(fake_g, fake_old):
|
| 712 |
+
count_non_unique += 1
|
| 713 |
+
unique = False
|
| 714 |
+
break
|
| 715 |
+
if unique:
|
| 716 |
+
fake_evaluated.append(fake_g)
|
| 717 |
+
non_isomorphic = True
|
| 718 |
+
for train_g in train_graphs:
|
| 719 |
+
if nx.faster_could_be_isomorphic(fake_g, train_g):
|
| 720 |
+
if nx.is_isomorphic(fake_g, train_g):
|
| 721 |
+
count_isomorphic += 1
|
| 722 |
+
non_isomorphic = False
|
| 723 |
+
break
|
| 724 |
+
if non_isomorphic:
|
| 725 |
+
if validity_func(fake_g):
|
| 726 |
+
count_valid += 1
|
| 727 |
+
|
| 728 |
+
frac_unique = (float(len(fake_graphs)) - count_non_unique) / float(
|
| 729 |
+
len(fake_graphs)) # Fraction of distinct isomorphism classes in the fake graphs
|
| 730 |
+
frac_unique_non_isomorphic = (float(len(fake_graphs)) - count_non_unique - count_isomorphic) / float(
|
| 731 |
+
len(fake_graphs)) # Fraction of distinct isomorphism classes in the fake graphs that are not in the training set
|
| 732 |
+
frac_unique_non_isomorphic_valid = count_valid / float(
|
| 733 |
+
len(fake_graphs)) # Fraction of distinct isomorphism classes in the fake graphs that are not in the training set and are valid
|
| 734 |
+
return frac_unique, frac_unique_non_isomorphic, frac_unique_non_isomorphic_valid
|
| 735 |
+
|
| 736 |
+
|
| 737 |
+
class SpectreSamplingMetrics(nn.Module):
|
| 738 |
+
def __init__(self, data_loaders, compute_emd, metrics_list):
|
| 739 |
+
super().__init__()
|
| 740 |
+
|
| 741 |
+
self.train_graphs = self.loader_to_nx(data_loaders['train'])
|
| 742 |
+
self.val_graphs = self.loader_to_nx(data_loaders['val'])
|
| 743 |
+
self.test_graphs = self.loader_to_nx(data_loaders['test'])
|
| 744 |
+
self.num_graphs_test = len(self.test_graphs)
|
| 745 |
+
self.num_graphs_val = len(self.val_graphs)
|
| 746 |
+
self.compute_emd = compute_emd
|
| 747 |
+
self.metrics_list = metrics_list
|
| 748 |
+
|
| 749 |
+
def loader_to_nx(self, loader):
|
| 750 |
+
networkx_graphs = []
|
| 751 |
+
for i, batch in enumerate(loader):
|
| 752 |
+
data_list = batch.to_data_list()
|
| 753 |
+
for j, data in enumerate(data_list):
|
| 754 |
+
networkx_graphs.append(to_networkx(data, node_attrs=None, edge_attrs=None, to_undirected=True,
|
| 755 |
+
remove_self_loops=True))
|
| 756 |
+
return networkx_graphs
|
| 757 |
+
|
| 758 |
+
def forward(self, generated_graphs: list, local_rank, test=False):
|
| 759 |
+
reference_graphs = self.test_graphs if test else self.val_graphs
|
| 760 |
+
if local_rank == 0:
|
| 761 |
+
print(f"Computing sampling metrics between {len(generated_graphs)} generated graphs and {len(reference_graphs)}"
|
| 762 |
+
f" test graphs -- emd computation: {self.compute_emd}")
|
| 763 |
+
networkx_graphs = []
|
| 764 |
+
adjacency_matrices = []
|
| 765 |
+
if local_rank == 0:
|
| 766 |
+
print("Building networkx graphs...")
|
| 767 |
+
for graph in generated_graphs:
|
| 768 |
+
node_types, edge_types = graph
|
| 769 |
+
A = edge_types.bool().cpu().numpy()
|
| 770 |
+
adjacency_matrices.append(A)
|
| 771 |
+
|
| 772 |
+
nx_graph = nx.from_numpy_array(A)
|
| 773 |
+
networkx_graphs.append(nx_graph)
|
| 774 |
+
|
| 775 |
+
np.savez('generated_adjs.npz', *adjacency_matrices)
|
| 776 |
+
|
| 777 |
+
to_log = {}
|
| 778 |
+
if 'degree' in self.metrics_list:
|
| 779 |
+
if local_rank == 0:
|
| 780 |
+
print("Computing degree stats..")
|
| 781 |
+
degree = degree_stats(reference_graphs, networkx_graphs, is_parallel=True,
|
| 782 |
+
compute_emd=self.compute_emd)
|
| 783 |
+
|
| 784 |
+
to_log['degree'] = degree
|
| 785 |
+
|
| 786 |
+
if wandb.run:
|
| 787 |
+
wandb.run.summary['degree'] = degree
|
| 788 |
+
|
| 789 |
+
# val_eigvals = [graph["eigval"][1:self.k + 1].cpu().detach().numpy() for graph in self.val]
|
| 790 |
+
# train_eigvals = [graph["eigval"][1:self.k + 1].cpu().detach().numpy() for graph in self.train]
|
| 791 |
+
|
| 792 |
+
# eigval_stats(eig_ref_list, eig_pred_list, max_eig=20, is_parallel=True, compute_emd=False)
|
| 793 |
+
# spectral_filter_stats(eigvec_ref_list, eigval_ref_list, eigvec_pred_list, eigval_pred_list, is_parallel=False,
|
| 794 |
+
# compute_emd=False) # This is the one called wavelet
|
| 795 |
+
|
| 796 |
+
|
| 797 |
+
if 'spectre' in self.metrics_list:
|
| 798 |
+
if local_rank == 0:
|
| 799 |
+
print("Computing spectre stats...")
|
| 800 |
+
spectre = spectral_stats(reference_graphs, networkx_graphs, is_parallel=True, n_eigvals=-1,
|
| 801 |
+
compute_emd=self.compute_emd)
|
| 802 |
+
|
| 803 |
+
to_log['spectre'] = spectre
|
| 804 |
+
if wandb.run:
|
| 805 |
+
wandb.run.summary['spectre'] = spectre
|
| 806 |
+
|
| 807 |
+
if 'clustering' in self.metrics_list:
|
| 808 |
+
if local_rank == 0:
|
| 809 |
+
print("Computing clustering stats...")
|
| 810 |
+
clustering = clustering_stats(reference_graphs, networkx_graphs, bins=100, is_parallel=True,
|
| 811 |
+
compute_emd=self.compute_emd)
|
| 812 |
+
to_log['clustering'] = clustering
|
| 813 |
+
if wandb.run:
|
| 814 |
+
wandb.run.summary['clustering'] = clustering
|
| 815 |
+
|
| 816 |
+
if 'motif' in self.metrics_list:
|
| 817 |
+
if local_rank == 0:
|
| 818 |
+
print("Computing motif stats")
|
| 819 |
+
motif = motif_stats(reference_graphs, networkx_graphs, motif_type='4cycle', ground_truth_match=None, bins=100,
|
| 820 |
+
compute_emd=self.compute_emd)
|
| 821 |
+
to_log['motif'] = motif
|
| 822 |
+
if wandb.run:
|
| 823 |
+
wandb.run.summary['motif'] = motif
|
| 824 |
+
|
| 825 |
+
if 'orbit' in self.metrics_list:
|
| 826 |
+
if local_rank == 0:
|
| 827 |
+
print("Computing orbit stats...")
|
| 828 |
+
orbit = orbit_stats_all(reference_graphs, networkx_graphs, compute_emd=self.compute_emd)
|
| 829 |
+
to_log['orbit'] = orbit
|
| 830 |
+
if wandb.run:
|
| 831 |
+
wandb.run.summary['orbit'] = orbit
|
| 832 |
+
|
| 833 |
+
if 'sbm' in self.metrics_list:
|
| 834 |
+
if local_rank == 0:
|
| 835 |
+
print("Computing accuracy...")
|
| 836 |
+
acc = eval_acc_sbm_graph(networkx_graphs, refinement_steps=100, strict=True)
|
| 837 |
+
to_log['sbm_acc'] = acc
|
| 838 |
+
if wandb.run:
|
| 839 |
+
wandb.run.summary['sbmacc'] = acc
|
| 840 |
+
|
| 841 |
+
if 'planar' in self.metrics_list:
|
| 842 |
+
if local_rank ==0:
|
| 843 |
+
print('Computing planar accuracy...')
|
| 844 |
+
planar_acc = eval_acc_planar_graph(networkx_graphs)
|
| 845 |
+
to_log['planar_acc'] = planar_acc
|
| 846 |
+
if wandb.run:
|
| 847 |
+
wandb.run.summary['planar_acc'] = planar_acc
|
| 848 |
+
|
| 849 |
+
if 'sbm' or 'planar' in self.metrics_list:
|
| 850 |
+
if local_rank == 0:
|
| 851 |
+
print("Computing all fractions...")
|
| 852 |
+
frac_unique, frac_unique_non_isomorphic, fraction_unique_non_isomorphic_valid = eval_fraction_unique_non_isomorphic_valid(
|
| 853 |
+
networkx_graphs, self.train_graphs, is_sbm_graph if 'sbm' in self.metrics_list else is_planar_graph)
|
| 854 |
+
frac_non_isomorphic = 1.0 - eval_fraction_isomorphic(networkx_graphs, self.train_graphs)
|
| 855 |
+
to_log.update({'sampling/frac_unique': frac_unique,
|
| 856 |
+
'sampling/frac_unique_non_iso': frac_unique_non_isomorphic,
|
| 857 |
+
'sampling/frac_unic_non_iso_valid': fraction_unique_non_isomorphic_valid,
|
| 858 |
+
'sampling/frac_non_iso': frac_non_isomorphic})
|
| 859 |
+
|
| 860 |
+
if local_rank == 0:
|
| 861 |
+
print("Sampling statistics", to_log)
|
| 862 |
+
if wandb.run:
|
| 863 |
+
wandb.log(to_log, commit=False)
|
| 864 |
+
|
| 865 |
+
def reset(self):
|
| 866 |
+
pass
|
| 867 |
+
|
| 868 |
+
|
| 869 |
+
def loader_to_nx(loader):
|
| 870 |
+
networkx_graphs = {}
|
| 871 |
+
for i, batch in enumerate(loader):
|
| 872 |
+
data_list = batch.to_data_list()
|
| 873 |
+
for j, data in enumerate(data_list):
|
| 874 |
+
networkx_graphs[data.prompt_id.squeeze(0).item()] = [to_networkx(data, node_attrs=None, edge_attrs=None, to_undirected=True, remove_self_loops=True)]
|
| 875 |
+
|
| 876 |
+
return networkx_graphs
|
| 877 |
+
|
| 878 |
+
def compute_metrics(generated_graphs, referenced_graphs):
|
| 879 |
+
networkx_graphs = defaultdict(list)
|
| 880 |
+
adjacency_matrices = defaultdict(list)
|
| 881 |
+
for key in generated_graphs:
|
| 882 |
+
for graph in generated_graphs[key]:
|
| 883 |
+
node_types, edge_types = graph
|
| 884 |
+
A = edge_types.bool().cpu().numpy()
|
| 885 |
+
nx_graph = nx.from_numpy_array(A)
|
| 886 |
+
|
| 887 |
+
networkx_graphs[key].append(nx_graph)
|
| 888 |
+
adjacency_matrices[key].append(A)
|
| 889 |
+
|
| 890 |
+
new_referenced_graphs = []
|
| 891 |
+
for key in referenced_graphs:
|
| 892 |
+
new_referenced_graphs.extend(referenced_graphs[key])
|
| 893 |
+
referenced_graphs = new_referenced_graphs
|
| 894 |
+
|
| 895 |
+
nx_graphs = []
|
| 896 |
+
for key in networkx_graphs:
|
| 897 |
+
nx_graphs.extend(networkx_graphs[key])
|
| 898 |
+
|
| 899 |
+
return nx_graphs
|
| 900 |
+
|
| 901 |
+
|
| 902 |
+
|
| 903 |
+
|
| 904 |
+
class Comm20SamplingMetrics(SpectreSamplingMetrics):
|
| 905 |
+
def __init__(self, data_loaders):
|
| 906 |
+
super().__init__(data_loaders=data_loaders,
|
| 907 |
+
compute_emd=True,
|
| 908 |
+
metrics_list=['degree', 'clustering', 'orbit'])
|
| 909 |
+
|
| 910 |
+
|
| 911 |
+
class PlanarSamplingMetrics(SpectreSamplingMetrics):
|
| 912 |
+
def __init__(self, data_loaders):
|
| 913 |
+
super().__init__(data_loaders=data_loaders,
|
| 914 |
+
compute_emd=False,
|
| 915 |
+
metrics_list=['degree', 'clustering', 'orbit', 'spectre', 'planar'])
|
| 916 |
+
|
| 917 |
+
|
| 918 |
+
class SBMSamplingMetrics(SpectreSamplingMetrics):
|
| 919 |
+
def __init__(self, data_loaders):
|
| 920 |
+
super().__init__(data_loaders=data_loaders,
|
| 921 |
+
compute_emd=False,
|
| 922 |
+
metrics_list=['degree', 'clustering', 'orbit', 'spectre', 'sbm'])
|
| 923 |
+
|
| 924 |
+
class CrossDomainSamplingMetrics(SpectreSamplingMetrics):
|
| 925 |
+
def __init__(self, data_loaders):
|
| 926 |
+
super().__init__(data_loaders=data_loaders,
|
| 927 |
+
compute_emd=False,
|
| 928 |
+
metrics_list=['degree', 'clustering', 'orbit', 'spectre'])
|
analysis/visualization.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
from rdkit import Chem
|
| 4 |
+
from rdkit.Chem import Draw, AllChem
|
| 5 |
+
from rdkit.Geometry import Point3D
|
| 6 |
+
from rdkit import RDLogger
|
| 7 |
+
import imageio
|
| 8 |
+
import networkx as nx
|
| 9 |
+
import numpy as np
|
| 10 |
+
import rdkit.Chem
|
| 11 |
+
import wandb
|
| 12 |
+
import matplotlib.pyplot as plt
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class MolecularVisualization:
|
| 19 |
+
def __init__(self, remove_h, dataset_infos):
|
| 20 |
+
self.remove_h = remove_h
|
| 21 |
+
self.dataset_infos = dataset_infos
|
| 22 |
+
|
| 23 |
+
def mol_from_graphs(self, node_list, adjacency_matrix):
|
| 24 |
+
"""
|
| 25 |
+
Convert graphs to rdkit molecules
|
| 26 |
+
node_list: the nodes of a batch of nodes (bs x n)
|
| 27 |
+
adjacency_matrix: the adjacency_matrix of the molecule (bs x n x n)
|
| 28 |
+
"""
|
| 29 |
+
# dictionary to map integer value to the char of atom
|
| 30 |
+
atom_decoder = self.dataset_infos.atom_decoder
|
| 31 |
+
|
| 32 |
+
# create empty editable mol object
|
| 33 |
+
mol = Chem.RWMol()
|
| 34 |
+
|
| 35 |
+
# add atoms to mol and keep track of index
|
| 36 |
+
node_to_idx = {}
|
| 37 |
+
for i in range(len(node_list)):
|
| 38 |
+
if node_list[i] == -1:
|
| 39 |
+
continue
|
| 40 |
+
a = Chem.Atom(atom_decoder[int(node_list[i])])
|
| 41 |
+
molIdx = mol.AddAtom(a)
|
| 42 |
+
node_to_idx[i] = molIdx
|
| 43 |
+
|
| 44 |
+
for ix, row in enumerate(adjacency_matrix):
|
| 45 |
+
for iy, bond in enumerate(row):
|
| 46 |
+
# only traverse half the symmetric matrix
|
| 47 |
+
if iy <= ix:
|
| 48 |
+
continue
|
| 49 |
+
if bond == 1:
|
| 50 |
+
bond_type = Chem.rdchem.BondType.SINGLE
|
| 51 |
+
elif bond == 2:
|
| 52 |
+
bond_type = Chem.rdchem.BondType.DOUBLE
|
| 53 |
+
elif bond == 3:
|
| 54 |
+
bond_type = Chem.rdchem.BondType.TRIPLE
|
| 55 |
+
elif bond == 4:
|
| 56 |
+
bond_type = Chem.rdchem.BondType.AROMATIC
|
| 57 |
+
else:
|
| 58 |
+
continue
|
| 59 |
+
mol.AddBond(node_to_idx[ix], node_to_idx[iy], bond_type)
|
| 60 |
+
|
| 61 |
+
try:
|
| 62 |
+
mol = mol.GetMol()
|
| 63 |
+
except rdkit.Chem.KekulizeException:
|
| 64 |
+
print("Can't kekulize molecule")
|
| 65 |
+
mol = None
|
| 66 |
+
return mol
|
| 67 |
+
|
| 68 |
+
def visualize(self, path: str, molecules: list, num_molecules_to_visualize: int, log='graph'):
|
| 69 |
+
# define path to save figures
|
| 70 |
+
if not os.path.exists(path):
|
| 71 |
+
os.makedirs(path)
|
| 72 |
+
|
| 73 |
+
# visualize the final molecules
|
| 74 |
+
print(f"Visualizing {num_molecules_to_visualize} of {len(molecules)}")
|
| 75 |
+
if num_molecules_to_visualize > len(molecules):
|
| 76 |
+
print(f"Shortening to {len(molecules)}")
|
| 77 |
+
num_molecules_to_visualize = len(molecules)
|
| 78 |
+
|
| 79 |
+
for i in range(num_molecules_to_visualize):
|
| 80 |
+
file_path = os.path.join(path, 'molecule_{}.png'.format(i))
|
| 81 |
+
mol = self.mol_from_graphs(molecules[i][0].numpy(), molecules[i][1].numpy())
|
| 82 |
+
try:
|
| 83 |
+
Draw.MolToFile(mol, file_path)
|
| 84 |
+
if wandb.run and log is not None:
|
| 85 |
+
print(f"Saving {file_path} to wandb")
|
| 86 |
+
wandb.log({log: wandb.Image(file_path)}, commit=True)
|
| 87 |
+
except rdkit.Chem.KekulizeException:
|
| 88 |
+
print("Can't kekulize molecule")
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def visualize_chain(self, path, nodes_list, adjacency_matrix, trainer=None):
|
| 92 |
+
RDLogger.DisableLog('rdApp.*')
|
| 93 |
+
# convert graphs to the rdkit molecules
|
| 94 |
+
mols = [self.mol_from_graphs(nodes_list[i], adjacency_matrix[i]) for i in range(nodes_list.shape[0])]
|
| 95 |
+
|
| 96 |
+
# find the coordinates of atoms in the final molecule
|
| 97 |
+
final_molecule = mols[-1]
|
| 98 |
+
AllChem.Compute2DCoords(final_molecule)
|
| 99 |
+
|
| 100 |
+
coords = []
|
| 101 |
+
for i, atom in enumerate(final_molecule.GetAtoms()):
|
| 102 |
+
positions = final_molecule.GetConformer().GetAtomPosition(i)
|
| 103 |
+
coords.append((positions.x, positions.y, positions.z))
|
| 104 |
+
|
| 105 |
+
# align all the molecules
|
| 106 |
+
for i, mol in enumerate(mols):
|
| 107 |
+
AllChem.Compute2DCoords(mol)
|
| 108 |
+
conf = mol.GetConformer()
|
| 109 |
+
for j, atom in enumerate(mol.GetAtoms()):
|
| 110 |
+
x, y, z = coords[j]
|
| 111 |
+
conf.SetAtomPosition(j, Point3D(x, y, z))
|
| 112 |
+
|
| 113 |
+
# draw gif
|
| 114 |
+
save_paths = []
|
| 115 |
+
num_frams = nodes_list.shape[0]
|
| 116 |
+
|
| 117 |
+
for frame in range(num_frams):
|
| 118 |
+
file_name = os.path.join(path, 'fram_{}.png'.format(frame))
|
| 119 |
+
Draw.MolToFile(mols[frame], file_name, size=(300, 300), legend=f"Frame {frame}")
|
| 120 |
+
save_paths.append(file_name)
|
| 121 |
+
|
| 122 |
+
imgs = [imageio.imread(fn) for fn in save_paths]
|
| 123 |
+
gif_path = os.path.join(os.path.dirname(path), '{}.gif'.format(path.split('/')[-1]))
|
| 124 |
+
imgs.extend([imgs[-1]] * 10)
|
| 125 |
+
imageio.mimsave(gif_path, imgs, subrectangles=True, duration=20)
|
| 126 |
+
|
| 127 |
+
if wandb.run:
|
| 128 |
+
print(f"Saving {gif_path} to wandb")
|
| 129 |
+
wandb.log({"chain": wandb.Video(gif_path, fps=5, format="gif")}, commit=True)
|
| 130 |
+
|
| 131 |
+
# draw grid image
|
| 132 |
+
try:
|
| 133 |
+
img = Draw.MolsToGridImage(mols, molsPerRow=10, subImgSize=(200, 200))
|
| 134 |
+
img.save(os.path.join(path, '{}_grid_image.png'.format(path.split('/')[-1])))
|
| 135 |
+
except Chem.rdchem.KekulizeException:
|
| 136 |
+
print("Can't kekulize molecule")
|
| 137 |
+
return mols
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
class NonMolecularVisualization:
|
| 141 |
+
def to_networkx(self, node_list, adjacency_matrix):
|
| 142 |
+
"""
|
| 143 |
+
Convert graphs to networkx graphs
|
| 144 |
+
node_list: the nodes of a batch of nodes (bs x n)
|
| 145 |
+
adjacency_matrix: the adjacency_matrix of the molecule (bs x n x n)
|
| 146 |
+
"""
|
| 147 |
+
graph = nx.Graph()
|
| 148 |
+
|
| 149 |
+
for i in range(len(node_list)):
|
| 150 |
+
if node_list[i] == -1:
|
| 151 |
+
continue
|
| 152 |
+
graph.add_node(i, number=i, symbol=node_list[i], color_val=node_list[i])
|
| 153 |
+
|
| 154 |
+
rows, cols = np.where(adjacency_matrix >= 1)
|
| 155 |
+
edges = zip(rows.tolist(), cols.tolist())
|
| 156 |
+
for edge in edges:
|
| 157 |
+
edge_type = adjacency_matrix[edge[0]][edge[1]]
|
| 158 |
+
graph.add_edge(edge[0], edge[1], color=float(edge_type), weight=3 * edge_type)
|
| 159 |
+
|
| 160 |
+
return graph
|
| 161 |
+
|
| 162 |
+
def visualize_non_molecule(self, graph, pos, path, iterations=100, node_size=100, largest_component=False):
|
| 163 |
+
if largest_component:
|
| 164 |
+
CGs = [graph.subgraph(c) for c in nx.connected_components(graph)]
|
| 165 |
+
CGs = sorted(CGs, key=lambda x: x.number_of_nodes(), reverse=True)
|
| 166 |
+
graph = CGs[0]
|
| 167 |
+
|
| 168 |
+
# Plot the graph structure with colors
|
| 169 |
+
if pos is None:
|
| 170 |
+
pos = nx.spring_layout(graph, iterations=iterations)
|
| 171 |
+
|
| 172 |
+
# Set node colors based on the eigenvectors
|
| 173 |
+
w, U = np.linalg.eigh(nx.normalized_laplacian_matrix(graph).toarray())
|
| 174 |
+
vmin, vmax = np.min(U[:, 1]), np.max(U[:, 1])
|
| 175 |
+
m = max(np.abs(vmin), vmax)
|
| 176 |
+
vmin, vmax = -m, m
|
| 177 |
+
|
| 178 |
+
plt.figure()
|
| 179 |
+
nx.draw(graph, pos, font_size=5, node_size=node_size, with_labels=False, node_color=U[:, 1],
|
| 180 |
+
cmap=plt.cm.coolwarm, vmin=vmin, vmax=vmax, edge_color='grey')
|
| 181 |
+
|
| 182 |
+
plt.tight_layout()
|
| 183 |
+
plt.savefig(path)
|
| 184 |
+
plt.close("all")
|
| 185 |
+
|
| 186 |
+
def visualize(self, path: str, graphs: list, num_graphs_to_visualize: int, log='graph'):
|
| 187 |
+
# define path to save figures
|
| 188 |
+
if not os.path.exists(path):
|
| 189 |
+
os.makedirs(path)
|
| 190 |
+
|
| 191 |
+
# visualize the final molecules
|
| 192 |
+
for i in range(num_graphs_to_visualize):
|
| 193 |
+
file_path = os.path.join(path, 'graph_{}.png'.format(i))
|
| 194 |
+
graph = self.to_networkx(graphs[i][0].numpy(), graphs[i][1].numpy())
|
| 195 |
+
self.visualize_non_molecule(graph=graph, pos=None, path=file_path)
|
| 196 |
+
im = plt.imread(file_path)
|
| 197 |
+
if wandb.run and log is not None:
|
| 198 |
+
wandb.log({log: [wandb.Image(im, caption=file_path)]})
|
| 199 |
+
|
| 200 |
+
def visualize_chain(self, path, nodes_list, adjacency_matrix):
|
| 201 |
+
# convert graphs to networkx
|
| 202 |
+
graphs = [self.to_networkx(nodes_list[i], adjacency_matrix[i]) for i in range(nodes_list.shape[0])]
|
| 203 |
+
# find the coordinates of atoms in the final molecule
|
| 204 |
+
final_graph = graphs[-1]
|
| 205 |
+
final_pos = nx.spring_layout(final_graph, seed=0)
|
| 206 |
+
|
| 207 |
+
# draw gif
|
| 208 |
+
save_paths = []
|
| 209 |
+
num_frams = nodes_list.shape[0]
|
| 210 |
+
|
| 211 |
+
for frame in range(num_frams):
|
| 212 |
+
file_name = os.path.join(path, 'fram_{}.png'.format(frame))
|
| 213 |
+
self.visualize_non_molecule(graph=graphs[frame], pos=final_pos, path=file_name)
|
| 214 |
+
save_paths.append(file_name)
|
| 215 |
+
|
| 216 |
+
imgs = [imageio.imread(fn) for fn in save_paths]
|
| 217 |
+
gif_path = os.path.join(os.path.dirname(path), '{}.gif'.format(path.split('/')[-1]))
|
| 218 |
+
imgs.extend([imgs[-1]] * 10)
|
| 219 |
+
imageio.mimsave(gif_path, imgs, subrectangles=True, duration=20)
|
| 220 |
+
if wandb.run:
|
| 221 |
+
wandb.log({'chain': [wandb.Video(gif_path, caption=gif_path, format="gif")]})
|
app.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from omegaconf import OmegaConf
|
| 2 |
+
import gradio as gr
|
| 3 |
+
|
| 4 |
+
from dataset import init_dataset, compute_input_output_dims
|
| 5 |
+
from extra_features import ExtraFeatures
|
| 6 |
+
from demo_model import LGGMText2Graph_Demo
|
| 7 |
+
from analysis.spectre_utils import CrossDomainSamplingMetrics
|
| 8 |
+
import networkx as nx
|
| 9 |
+
import numpy as np
|
| 10 |
+
import matplotlib.pyplot as plt
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
cfg = OmegaConf.load('./config.yaml')
|
| 14 |
+
hydra_path = '.'
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
data_loaders, num_classes, max_n_nodes, nodes_dist, edge_types, node_types, n_nodes, cond_dims, cond_emb = init_dataset(cfg.dataset.name, cfg.train.batch_size, hydra_path, cfg.general.condition, cfg.model.transition)
|
| 18 |
+
|
| 19 |
+
extra_features = ExtraFeatures(cfg.model.extra_features, max_n_nodes)
|
| 20 |
+
|
| 21 |
+
input_dims, output_dims = compute_input_output_dims(data_loaders['train'], extra_features)
|
| 22 |
+
|
| 23 |
+
sampling_metrics = CrossDomainSamplingMetrics(data_loaders)
|
| 24 |
+
|
| 25 |
+
model = LGGMText2Graph_Demo.load_from_checkpoint('last-v1.ckpt')
|
| 26 |
+
|
| 27 |
+
model.init_prompt_encoder()
|
| 28 |
+
|
| 29 |
+
def calculate_average_degree(graph):
|
| 30 |
+
num_nodes = graph.number_of_nodes()
|
| 31 |
+
num_edges = graph.number_of_edges()
|
| 32 |
+
return (2 * num_edges) / num_nodes if num_nodes > 0 else 0
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def predict(text, num_nodes = None):
|
| 36 |
+
# Assuming model.generate and other processes are defined as before
|
| 37 |
+
graphs = model.generate(text, int(num_nodes))
|
| 38 |
+
ccs = []
|
| 39 |
+
degs = []
|
| 40 |
+
images = []
|
| 41 |
+
|
| 42 |
+
for g in graphs:
|
| 43 |
+
ccs.append(nx.average_clustering(g))
|
| 44 |
+
degs.append(calculate_average_degree(g))
|
| 45 |
+
|
| 46 |
+
fig, ax = plt.subplots()
|
| 47 |
+
nx.draw(g, ax=ax)
|
| 48 |
+
fig.canvas.draw()
|
| 49 |
+
image = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
|
| 50 |
+
image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))
|
| 51 |
+
plt.close(fig)
|
| 52 |
+
|
| 53 |
+
images.append(image)
|
| 54 |
+
|
| 55 |
+
return images[0], images[1], images[2], images[3], images[4], ccs[0], ccs[1], ccs[2], ccs[3], ccs[4], degs[0], degs[1], degs[2], degs[3], degs[4]
|
| 56 |
+
|
| 57 |
+
def clear(input_text):
|
| 58 |
+
return None, None
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
with gr.Blocks() as demo:
|
| 62 |
+
gr.Markdown("## Text2Graph Generation Demo")
|
| 63 |
+
with gr.Row():
|
| 64 |
+
with gr.Column():
|
| 65 |
+
input_text = gr.Textbox(label="Input your text prompt here", placeholder="Type here...")
|
| 66 |
+
with gr.Column():
|
| 67 |
+
input_num = gr.Slider(5, 200, value=10, label="Count", info="Number of nodes in the graph to be generated")
|
| 68 |
+
with gr.Column():
|
| 69 |
+
gr.Markdown("### Suggested Prompts")
|
| 70 |
+
gr.Markdown("1. Create a complex network with high clustering coefficient.\n2. Create a graph with extremely low number of triangles.")
|
| 71 |
+
|
| 72 |
+
with gr.Row() as output_row:
|
| 73 |
+
output_images = [gr.Image(label = f"Generated Network #{_}") for _ in range(5)]
|
| 74 |
+
with gr.Row():
|
| 75 |
+
output_texts_cc = [gr.Textbox(label=f"CC #{_}") for _ in range(5)]
|
| 76 |
+
with gr.Row():
|
| 77 |
+
output_texts_deg = [gr.Textbox(label=f"DEG #{_}") for _ in range(5)]
|
| 78 |
+
|
| 79 |
+
with gr.Row():
|
| 80 |
+
submit_button = gr.Button("Submit")
|
| 81 |
+
clear_button = gr.Button("Clear")
|
| 82 |
+
|
| 83 |
+
# Change function is linked to the submit button
|
| 84 |
+
submit_button.click(fn=predict, inputs=[input_text, input_num], outputs=output_images + output_texts_cc + output_texts_deg)
|
| 85 |
+
|
| 86 |
+
# Clear function resets the text input and clears the outputs
|
| 87 |
+
clear_button.click(fn=clear, inputs=input_text, outputs=output_images + output_texts_cc + output_texts_deg)
|
| 88 |
+
|
| 89 |
+
demo.launch()
|
config.yaml
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
hydra:
|
| 2 |
+
job:
|
| 3 |
+
chdir: True
|
| 4 |
+
run:
|
| 5 |
+
dir: ../outputs/${general.name}
|
| 6 |
+
general:
|
| 7 |
+
name: 'cc_high'
|
| 8 |
+
wandb: 'online' # online | offline | disabled
|
| 9 |
+
gpus: 1
|
| 10 |
+
resume: null
|
| 11 |
+
test_only: null
|
| 12 |
+
sample_every_val: 4
|
| 13 |
+
check_val_every_n_epochs: 10
|
| 14 |
+
samples_to_generate: 100
|
| 15 |
+
samples_to_save: 3
|
| 16 |
+
chains_to_save: 1
|
| 17 |
+
log_every_steps: 50
|
| 18 |
+
number_chain_steps: 8
|
| 19 |
+
final_model_samples_to_generate: 100
|
| 20 |
+
final_model_samples_to_save: 30
|
| 21 |
+
final_model_chains_to_save: 20
|
| 22 |
+
condition: ' '
|
| 23 |
+
setting: 'train_scratch'
|
| 24 |
+
ckpt_path: null
|
| 25 |
+
model:
|
| 26 |
+
type: 'discrete'
|
| 27 |
+
transition: 'marginal'
|
| 28 |
+
model: 'graph_tf'
|
| 29 |
+
diffusion_steps: 500
|
| 30 |
+
diffusion_noise_schedule: 'cosine'
|
| 31 |
+
n_layers: 5
|
| 32 |
+
extra_features: 'all'
|
| 33 |
+
hidden_mlp_dims: {'X': 256, 'E': 128, 'y': 128}
|
| 34 |
+
hidden_dims: {'dx': 256, 'de': 64, 'dy': 64, 'n_head': 8, 'dim_ffX': 256, 'dim_ffE': 128, 'dim_ffy': 128}
|
| 35 |
+
lambda_train: [5, 0]
|
| 36 |
+
train:
|
| 37 |
+
n_epochs: 300
|
| 38 |
+
batch_size: 8
|
| 39 |
+
accumulate_grad_batches: 1
|
| 40 |
+
lr: 0.0002
|
| 41 |
+
clip_grad: null
|
| 42 |
+
save_model: True
|
| 43 |
+
num_workers: 0
|
| 44 |
+
ema_decay: 0
|
| 45 |
+
weight_decay: 1e-12
|
| 46 |
+
seed: 0
|
| 47 |
+
progress_bar: false
|
| 48 |
+
optimizer: adamw
|
| 49 |
+
dataset:
|
| 50 |
+
datadir: 'graph/'
|
| 51 |
+
name: cc_high
|
| 52 |
+
remove_h: null
|
| 53 |
+
sample: 'seed'
|
dataset.py
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from distributions import DistributionNodes
|
| 3 |
+
from utils import to_dense
|
| 4 |
+
from torch_geometric.loader import DataLoader
|
| 5 |
+
from torch_geometric.data import Data
|
| 6 |
+
from torch_geometric.utils import remove_self_loops, to_undirected
|
| 7 |
+
import os
|
| 8 |
+
from sentence_transformers import SentenceTransformer
|
| 9 |
+
import random
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def arrange_data(adj_matrix, cond_emb, ind):
|
| 13 |
+
n_nodes = adj_matrix.shape[0]
|
| 14 |
+
|
| 15 |
+
edge_index = adj_matrix.nonzero().t()
|
| 16 |
+
edge_attr = torch.tensor([[0, 1] for _ in range(edge_index.shape[1])])
|
| 17 |
+
|
| 18 |
+
edge_index, edge_attr = to_undirected(edge_index, edge_attr, n_nodes, reduce = 'mean')
|
| 19 |
+
edge_index, edge_attr = remove_self_loops(edge_index, edge_attr)
|
| 20 |
+
|
| 21 |
+
x = torch.ones((n_nodes, 1))
|
| 22 |
+
|
| 23 |
+
y = torch.empty(1, 0)
|
| 24 |
+
cond_emb = torch.tensor(cond_emb).unsqueeze(0)
|
| 25 |
+
|
| 26 |
+
return Data(x=x, edge_index=edge_index, edge_attr=edge_attr, y=y, prompt_id = torch.tensor(ind), cond_emb = cond_emb)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def load_dataset_cc(dataname, batch_size, hydra_path, condition):
|
| 31 |
+
domains = ['cc_high', 'cc_medium', 'cc_low']
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
model = SentenceTransformer("all-MiniLM-L6-v2")
|
| 35 |
+
cond_embs = model.encode(condition)
|
| 36 |
+
|
| 37 |
+
for domain in domains:
|
| 38 |
+
if not os.path.exists(f'{hydra_path}/graphs/{domain}/train.pt'):
|
| 39 |
+
|
| 40 |
+
data = torch.load(f'{hydra_path}/graphs/{domain}/{domain}.pt')
|
| 41 |
+
|
| 42 |
+
#fix seed
|
| 43 |
+
torch.manual_seed(0)
|
| 44 |
+
|
| 45 |
+
#random permute and split
|
| 46 |
+
n = len(data)
|
| 47 |
+
indices = torch.randperm(n)
|
| 48 |
+
|
| 49 |
+
if domain == 'eco':
|
| 50 |
+
train_indices = indices[:4].repeat(50)
|
| 51 |
+
val_indices = indices[4:5].repeat(50)
|
| 52 |
+
test_indices = indices[5:]
|
| 53 |
+
else:
|
| 54 |
+
train_indices = indices[:int(0.7 * n)]
|
| 55 |
+
val_indices = indices[int(0.7 * n):int(0.8 * n)]
|
| 56 |
+
test_indices = indices[int(0.8 * n):]
|
| 57 |
+
|
| 58 |
+
train_data = [data[_] for _ in train_indices]
|
| 59 |
+
val_data = [data[_] for _ in val_indices]
|
| 60 |
+
test_data = [data[_] for _ in test_indices]
|
| 61 |
+
|
| 62 |
+
torch.save(train_indices, f'{hydra_path}/graphs/{domain}/train_indices.pt')
|
| 63 |
+
torch.save(val_indices, f'{hydra_path}/graphs/{domain}/val_indices.pt')
|
| 64 |
+
torch.save(test_indices, f'{hydra_path}/graphs/{domain}/test_indices.pt')
|
| 65 |
+
|
| 66 |
+
torch.save(train_data, f'{hydra_path}/graphs/{domain}/train.pt')
|
| 67 |
+
torch.save(val_data, f'{hydra_path}/graphs/{domain}/val.pt')
|
| 68 |
+
torch.save(test_data, f'{hydra_path}/graphs/{domain}/test.pt')
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
train_data, val_data, test_data = [], [], []
|
| 72 |
+
|
| 73 |
+
if dataname in domains: #only for test
|
| 74 |
+
train_d = torch.load(f'{hydra_path}/graphs/{dataname}/train.pt')
|
| 75 |
+
val_d = torch.load(f'{hydra_path}/graphs/{dataname}/val.pt')
|
| 76 |
+
test_d = torch.load(f'{hydra_path}/graphs/{dataname}/test.pt')
|
| 77 |
+
|
| 78 |
+
train_indices = torch.load(f'{hydra_path}/graphs/{dataname}/train_indices.pt')
|
| 79 |
+
val_indices = torch.load(f'{hydra_path}/graphs/{dataname}/val_indices.pt')
|
| 80 |
+
test_indices = torch.load(f'{hydra_path}/graphs/{dataname}/test_indices.pt')
|
| 81 |
+
|
| 82 |
+
with open(f'{hydra_path}/graphs/{dataname}/text_prompt_order.txt', 'r') as f:
|
| 83 |
+
text_prompt = f.readlines()
|
| 84 |
+
text_prompt = [x.strip() for x in text_prompt]
|
| 85 |
+
|
| 86 |
+
# text_prompt = ['1111111shgowhgo234o234']*10000
|
| 87 |
+
print(text_prompt[0])
|
| 88 |
+
text_embs = model.encode(text_prompt)
|
| 89 |
+
cond_embs = torch.tensor(text_embs)
|
| 90 |
+
|
| 91 |
+
train_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(train_d, train_indices)])
|
| 92 |
+
val_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(val_d, val_indices)])
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
if dataname != 'eco':
|
| 96 |
+
# test_data = [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(test_d, test_indices)]
|
| 97 |
+
test_data = [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(test_d, test_indices)]
|
| 98 |
+
else:
|
| 99 |
+
test_data = [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(train_d, train_indices)] + [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(val_data, val_indices)] + [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(test_data, test_indices)]
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
elif dataname == 'all':
|
| 103 |
+
for i, domain in enumerate(domains):
|
| 104 |
+
train_d = torch.load(f'{hydra_path}/graphs/{domain}/train.pt')
|
| 105 |
+
val_d = torch.load(f'{hydra_path}/graphs/{domain}/val.pt')
|
| 106 |
+
test_d = torch.load(f'{hydra_path}/graphs/{domain}/test.pt')
|
| 107 |
+
|
| 108 |
+
train_indices = torch.load(f'{hydra_path}/graphs/{domain}/train_indices.pt')
|
| 109 |
+
val_indices = torch.load(f'{hydra_path}/graphs/{domain}/val_indices.pt')
|
| 110 |
+
test_indices = torch.load(f'{hydra_path}/graphs/{domain}/test_indices.pt')
|
| 111 |
+
|
| 112 |
+
# text_prompt = torch.load(f'{hydra_path}/graphs/{domain}/text_prompt_order.pt')
|
| 113 |
+
|
| 114 |
+
with open(f'{hydra_path}/graphs/{domain}/text_prompt_order.txt', 'r') as f:
|
| 115 |
+
text_prompt = f.readlines()
|
| 116 |
+
text_prompt = [x.strip() for x in text_prompt]
|
| 117 |
+
|
| 118 |
+
print(domain, text_prompt[0])
|
| 119 |
+
|
| 120 |
+
text_embs = model.encode(text_prompt)
|
| 121 |
+
|
| 122 |
+
train_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(train_d, train_indices)])
|
| 123 |
+
val_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(val_d, val_indices)])
|
| 124 |
+
test_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(test_d, test_indices)])
|
| 125 |
+
print(i, domain, len(train_data), len(val_data), len(test_data))
|
| 126 |
+
|
| 127 |
+
print('Size of dataset', len(train_data), len(val_data), len(test_data))
|
| 128 |
+
|
| 129 |
+
train_loader = DataLoader(train_data, batch_size = batch_size, shuffle=True)
|
| 130 |
+
val_loader = DataLoader(val_data, batch_size = batch_size, shuffle=False)
|
| 131 |
+
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False)
|
| 132 |
+
|
| 133 |
+
return train_loader, val_loader, test_loader, train_data, val_data, test_data, text_embs.shape[1], torch.tensor(cond_embs)
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def load_dataset_deg(dataname, batch_size, hydra_path, condition):
|
| 139 |
+
domains = ['deg_high', 'deg_medium', 'deg_low']
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
model = SentenceTransformer("all-MiniLM-L6-v2")
|
| 143 |
+
cond_embs = model.encode(condition)
|
| 144 |
+
|
| 145 |
+
for domain in domains:
|
| 146 |
+
if not os.path.exists(f'{hydra_path}/graphs/{domain}/train.pt'):
|
| 147 |
+
|
| 148 |
+
data = torch.load(f'{hydra_path}/graphs/{domain}/{domain}.pt')
|
| 149 |
+
|
| 150 |
+
#fix seed
|
| 151 |
+
torch.manual_seed(0)
|
| 152 |
+
|
| 153 |
+
#random permute and split
|
| 154 |
+
n = len(data)
|
| 155 |
+
indices = torch.randperm(n)
|
| 156 |
+
|
| 157 |
+
if domain == 'eco':
|
| 158 |
+
train_indices = indices[:4].repeat(50)
|
| 159 |
+
val_indices = indices[4:5].repeat(50)
|
| 160 |
+
test_indices = indices[5:]
|
| 161 |
+
else:
|
| 162 |
+
train_indices = indices[:int(0.7 * n)]
|
| 163 |
+
val_indices = indices[int(0.7 * n):int(0.8 * n)]
|
| 164 |
+
test_indices = indices[int(0.8 * n):]
|
| 165 |
+
|
| 166 |
+
train_data = [data[_] for _ in train_indices]
|
| 167 |
+
val_data = [data[_] for _ in val_indices]
|
| 168 |
+
test_data = [data[_] for _ in test_indices]
|
| 169 |
+
|
| 170 |
+
torch.save(train_indices, f'{hydra_path}/graphs/{domain}/train_indices.pt')
|
| 171 |
+
torch.save(val_indices, f'{hydra_path}/graphs/{domain}/val_indices.pt')
|
| 172 |
+
torch.save(test_indices, f'{hydra_path}/graphs/{domain}/test_indices.pt')
|
| 173 |
+
|
| 174 |
+
torch.save(train_data, f'{hydra_path}/graphs/{domain}/train.pt')
|
| 175 |
+
torch.save(val_data, f'{hydra_path}/graphs/{domain}/val.pt')
|
| 176 |
+
torch.save(test_data, f'{hydra_path}/graphs/{domain}/test.pt')
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
train_data, val_data, test_data = [], [], []
|
| 180 |
+
|
| 181 |
+
if dataname in domains: #only for test
|
| 182 |
+
train_d = torch.load(f'{hydra_path}/graphs/{dataname}/train.pt')
|
| 183 |
+
val_d = torch.load(f'{hydra_path}/graphs/{dataname}/val.pt')
|
| 184 |
+
test_d = torch.load(f'{hydra_path}/graphs/{dataname}/test.pt')
|
| 185 |
+
|
| 186 |
+
train_indices = torch.load(f'{hydra_path}/graphs/{dataname}/train_indices.pt')
|
| 187 |
+
val_indices = torch.load(f'{hydra_path}/graphs/{dataname}/val_indices.pt')
|
| 188 |
+
test_indices = torch.load(f'{hydra_path}/graphs/{dataname}/test_indices.pt')
|
| 189 |
+
|
| 190 |
+
with open(f'{hydra_path}/graphs/{dataname}/text_prompt_order.txt', 'r') as f:
|
| 191 |
+
text_prompt = f.readlines()
|
| 192 |
+
text_prompt = [x.strip() for x in text_prompt]
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
text_embs = model.encode(text_prompt)
|
| 196 |
+
cond_embs = torch.tensor(text_embs)
|
| 197 |
+
|
| 198 |
+
train_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(train_d, train_indices)])
|
| 199 |
+
val_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(val_d, val_indices)])
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
if dataname != 'eco':
|
| 203 |
+
test_data = [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(test_d, test_indices)]
|
| 204 |
+
else:
|
| 205 |
+
test_data = [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(train_d, train_indices)] + [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(val_data, val_indices)] + [arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(test_data, test_indices)]
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
elif dataname == 'all':
|
| 209 |
+
for i, domain in enumerate(domains):
|
| 210 |
+
train_d = torch.load(f'{hydra_path}/graphs/{domain}/train.pt')
|
| 211 |
+
val_d = torch.load(f'{hydra_path}/graphs/{domain}/val.pt')
|
| 212 |
+
test_d = torch.load(f'{hydra_path}/graphs/{domain}/test.pt')
|
| 213 |
+
|
| 214 |
+
train_indices = torch.load(f'{hydra_path}/graphs/{domain}/train_indices.pt')
|
| 215 |
+
val_indices = torch.load(f'{hydra_path}/graphs/{domain}/val_indices.pt')
|
| 216 |
+
test_indices = torch.load(f'{hydra_path}/graphs/{domain}/test_indices.pt')
|
| 217 |
+
|
| 218 |
+
# text_prompt = torch.load(f'{hydra_path}/graphs/{domain}/text_prompt_order.pt')
|
| 219 |
+
|
| 220 |
+
with open(f'{hydra_path}/graphs/{domain}/text_prompt_order.txt', 'r') as f:
|
| 221 |
+
text_prompt = f.readlines()
|
| 222 |
+
text_prompt = [x.strip() for x in text_prompt]
|
| 223 |
+
|
| 224 |
+
print(domain, text_prompt[0])
|
| 225 |
+
|
| 226 |
+
text_embs = model.encode(text_prompt)
|
| 227 |
+
|
| 228 |
+
train_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(train_d, train_indices)])
|
| 229 |
+
val_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(val_d, val_indices)])
|
| 230 |
+
test_data.extend([arrange_data(d, text_embs[ind.item()], ind.item()) for d, ind in zip(test_d, test_indices)])
|
| 231 |
+
print(i, domain, len(train_data), len(val_data), len(test_data))
|
| 232 |
+
|
| 233 |
+
print('Size of dataset', len(train_data), len(val_data), len(test_data))
|
| 234 |
+
|
| 235 |
+
train_loader = DataLoader(train_data, batch_size = batch_size, shuffle=True)
|
| 236 |
+
val_loader = DataLoader(val_data, batch_size = batch_size, shuffle=False)
|
| 237 |
+
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False)
|
| 238 |
+
|
| 239 |
+
return train_loader, val_loader, test_loader, train_data, val_data, test_data, text_embs.shape[1], torch.tensor(cond_embs)
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def init_dataset(dataname, batch_size, hydra_path, condition, transition):
|
| 245 |
+
train_loader, val_loader, test_loader, train_data, val_data, test_data, cond_dims, cond_emb = load_dataset_cc(dataname, batch_size, hydra_path, condition)
|
| 246 |
+
|
| 247 |
+
n_nodes = node_counts(1000, train_loader, val_loader)
|
| 248 |
+
node_types = torch.tensor([1]) #No node types
|
| 249 |
+
edge_types = edge_counts(train_loader)
|
| 250 |
+
|
| 251 |
+
num_classes = len(node_types)
|
| 252 |
+
max_n_nodes = len(n_nodes) - 1
|
| 253 |
+
nodes_dist = DistributionNodes(n_nodes)
|
| 254 |
+
|
| 255 |
+
print('Distribution of Number of Nodes:', n_nodes)
|
| 256 |
+
print('Distribution of Node Types:', node_types)
|
| 257 |
+
print('Distribution of Edge Types:', edge_types)
|
| 258 |
+
|
| 259 |
+
data_loaders = {'train': train_loader, 'val': val_loader, 'test': test_loader}
|
| 260 |
+
|
| 261 |
+
return data_loaders, num_classes, max_n_nodes, nodes_dist, edge_types, node_types, n_nodes, cond_dims, cond_emb
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def node_counts(max_nodes_possible, train_loader, val_loader):
|
| 265 |
+
#Count the distribution of graph size
|
| 266 |
+
all_counts = torch.zeros(max_nodes_possible)
|
| 267 |
+
|
| 268 |
+
for loader in [train_loader, val_loader]:
|
| 269 |
+
for data in loader:
|
| 270 |
+
unique, counts = torch.unique(data.batch, return_counts=True)
|
| 271 |
+
for count in counts:
|
| 272 |
+
all_counts[count] += 1
|
| 273 |
+
|
| 274 |
+
max_index = max(all_counts.nonzero())
|
| 275 |
+
all_counts = all_counts[:max_index + 1]
|
| 276 |
+
all_counts = all_counts / all_counts.sum()
|
| 277 |
+
|
| 278 |
+
return all_counts
|
| 279 |
+
|
| 280 |
+
def node_counts_meta(max_nodes_possible, train_data, val_data, num_classes):
|
| 281 |
+
#Count the distribution of graph size
|
| 282 |
+
|
| 283 |
+
all_counts = [torch.zeros(max_nodes_possible) for _ in range(num_classes)]
|
| 284 |
+
|
| 285 |
+
for dataset in [train_data, val_data]:
|
| 286 |
+
for data in dataset:
|
| 287 |
+
all_counts[data.cond_type.item()][data.x.shape[0]] += 1
|
| 288 |
+
|
| 289 |
+
for _ in range(num_classes):
|
| 290 |
+
tmp = all_counts[_].nonzero()
|
| 291 |
+
if len(tmp) == 0:
|
| 292 |
+
max_index = 1
|
| 293 |
+
all_counts[_][0] = 1
|
| 294 |
+
else:
|
| 295 |
+
max_index = max(tmp)
|
| 296 |
+
|
| 297 |
+
all_counts[_] = all_counts[_][:max_index + 1]
|
| 298 |
+
all_counts[_] = all_counts[_] / all_counts[_].sum()
|
| 299 |
+
|
| 300 |
+
return all_counts
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
def node_types(train_loader):
|
| 304 |
+
#Count the marginal distribution of node types
|
| 305 |
+
num_classes = None
|
| 306 |
+
for data in train_loader:
|
| 307 |
+
num_classes = data.x.shape[1]
|
| 308 |
+
break
|
| 309 |
+
|
| 310 |
+
counts = torch.zeros(num_classes)
|
| 311 |
+
|
| 312 |
+
for i, data in enumerate(train_loader):
|
| 313 |
+
counts += data.x.sum(dim=0)
|
| 314 |
+
|
| 315 |
+
counts = counts / counts.sum()
|
| 316 |
+
return counts
|
| 317 |
+
|
| 318 |
+
def edge_counts(train_loader):
|
| 319 |
+
#Count the marginal distribution of edge types
|
| 320 |
+
num_classes = None
|
| 321 |
+
for data in train_loader:
|
| 322 |
+
num_classes = data.edge_attr.shape[1]
|
| 323 |
+
break
|
| 324 |
+
|
| 325 |
+
d = torch.zeros(num_classes, dtype=torch.float)
|
| 326 |
+
|
| 327 |
+
for i, data in enumerate(train_loader):
|
| 328 |
+
unique, counts = torch.unique(data.batch, return_counts=True)
|
| 329 |
+
|
| 330 |
+
all_pairs = 0
|
| 331 |
+
for count in counts:
|
| 332 |
+
all_pairs += count * (count - 1)
|
| 333 |
+
|
| 334 |
+
|
| 335 |
+
num_edges = data.edge_index.shape[1]
|
| 336 |
+
num_non_edges = all_pairs - num_edges
|
| 337 |
+
|
| 338 |
+
edge_types = data.edge_attr.sum(dim=0)
|
| 339 |
+
assert num_non_edges >= 0
|
| 340 |
+
d[0] += num_non_edges
|
| 341 |
+
d[1:] += edge_types[1:]
|
| 342 |
+
|
| 343 |
+
d = d / d.sum()
|
| 344 |
+
return d
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
def edge_counts_meta(train_data, num_classes):
|
| 348 |
+
#Count the marginal distribution of edge types
|
| 349 |
+
num_edge_classes = None
|
| 350 |
+
for data in train_data:
|
| 351 |
+
num_edge_classes = data.edge_attr.shape[1]
|
| 352 |
+
break
|
| 353 |
+
|
| 354 |
+
d = [torch.ones(num_edge_classes, dtype=torch.float) for _ in range(num_classes)]
|
| 355 |
+
|
| 356 |
+
for i, data in enumerate(train_data):
|
| 357 |
+
n_nodes = data.x.shape[0]
|
| 358 |
+
|
| 359 |
+
all_pairs = n_nodes * (n_nodes - 1)
|
| 360 |
+
num_edges = data.edge_index.shape[1]
|
| 361 |
+
num_non_edges = all_pairs - num_edges
|
| 362 |
+
|
| 363 |
+
edge_types = data.edge_attr.sum(dim=0)
|
| 364 |
+
assert num_non_edges >= 0
|
| 365 |
+
d[data.cond_type.item()][0] += num_non_edges
|
| 366 |
+
d[data.cond_type.item()][1:] += edge_types[1:]
|
| 367 |
+
|
| 368 |
+
for i, _ in enumerate(d):
|
| 369 |
+
d[i] = d[i] / d[i].sum()
|
| 370 |
+
|
| 371 |
+
d = torch.stack(d)
|
| 372 |
+
|
| 373 |
+
return d
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
def compute_input_output_dims(train_loader, extra_features):
|
| 377 |
+
example_batch = next(iter(train_loader))
|
| 378 |
+
ex_dense, node_mask = to_dense(example_batch.x, example_batch.edge_index, example_batch.edge_attr, example_batch.batch)
|
| 379 |
+
|
| 380 |
+
example_data = {'X_t': ex_dense.X, 'E_t': ex_dense.E, 'y_t': example_batch['y'], 'node_mask': node_mask}
|
| 381 |
+
|
| 382 |
+
input_dims = {'X': example_batch['x'].size(1),
|
| 383 |
+
'E': example_batch['edge_attr'].size(1),
|
| 384 |
+
'y': example_batch['y'].size(1) + 1} # + 1 due to time conditioning
|
| 385 |
+
|
| 386 |
+
ex_extra_feat = extra_features(example_data)
|
| 387 |
+
input_dims['X'] += ex_extra_feat.X.size(-1)
|
| 388 |
+
input_dims['E'] += ex_extra_feat.E.size(-1)
|
| 389 |
+
input_dims['y'] += ex_extra_feat.y.size(-1)
|
| 390 |
+
|
| 391 |
+
output_dims = {'X': example_batch['x'].size(1),
|
| 392 |
+
'E': example_batch['edge_attr'].size(1),
|
| 393 |
+
'y': 0}
|
| 394 |
+
|
| 395 |
+
return input_dims, output_dims
|
demo_model.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import torch.nn as nn
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
from tqdm import tqdm
|
| 5 |
+
|
| 6 |
+
from models.transformer_model import GraphTransformer
|
| 7 |
+
from diffusion.noise_schedule import DiscreteUniformTransition, PredefinedNoiseScheduleDiscrete
|
| 8 |
+
from diffusion import diffusion_utils
|
| 9 |
+
import utils
|
| 10 |
+
import networkx as nx
|
| 11 |
+
from sentence_transformers import SentenceTransformer
|
| 12 |
+
import pytorch_lightning as pl
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class LGGMText2Graph_Demo(pl.LightningModule):
|
| 16 |
+
def __init__(self, cfg, input_dims, output_dims, cond_dims, cond_emb, \
|
| 17 |
+
nodes_dist, node_types, edge_types, extra_features, data_loaders):
|
| 18 |
+
super().__init__()
|
| 19 |
+
|
| 20 |
+
nodes_dist = nodes_dist
|
| 21 |
+
|
| 22 |
+
self.cfg = cfg
|
| 23 |
+
self.T = cfg.model.diffusion_steps
|
| 24 |
+
|
| 25 |
+
self.Xdim = input_dims['X']
|
| 26 |
+
self.Edim = input_dims['E']
|
| 27 |
+
self.ydim = input_dims['y']
|
| 28 |
+
self.Xdim_output = output_dims['X']
|
| 29 |
+
self.Edim_output = output_dims['E']
|
| 30 |
+
self.ydim_output = output_dims['y']
|
| 31 |
+
self.node_dist = nodes_dist
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
self.extra_features = extra_features
|
| 35 |
+
|
| 36 |
+
self.model = GraphTransformer(n_layers=cfg.model.n_layers,
|
| 37 |
+
input_dims=input_dims,
|
| 38 |
+
hidden_mlp_dims=cfg.model.hidden_mlp_dims,
|
| 39 |
+
hidden_dims=cfg.model.hidden_dims,
|
| 40 |
+
output_dims=output_dims,
|
| 41 |
+
cond_dims = cond_dims,
|
| 42 |
+
act_fn_in=nn.ReLU(),
|
| 43 |
+
act_fn_out=nn.ReLU()).to(self.device)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
self.noise_schedule = PredefinedNoiseScheduleDiscrete(cfg.model.diffusion_noise_schedule,
|
| 47 |
+
timesteps=cfg.model.diffusion_steps).to(self.device)
|
| 48 |
+
|
| 49 |
+
self.transition_model = DiscreteUniformTransition(x_classes=self.Xdim_output, e_classes=self.Edim_output,
|
| 50 |
+
y_classes=self.ydim_output)
|
| 51 |
+
x_limit = torch.ones(self.Xdim_output) / self.Xdim_output
|
| 52 |
+
e_limit = torch.ones(self.Edim_output) / self.Edim_output
|
| 53 |
+
y_limit = torch.ones(self.ydim_output) / self.ydim_output
|
| 54 |
+
|
| 55 |
+
self.limit_dist = utils.PlaceHolder(X=x_limit, E=e_limit, y=y_limit)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def generate(self, text, num_nodes) -> None:
|
| 59 |
+
print(num_nodes)
|
| 60 |
+
prompt_emb = torch.tensor(self.text_encoder.encode([text])).to(self.device)
|
| 61 |
+
samples = self.sample_batch(5, cond_emb = prompt_emb, num_nodes = num_nodes)
|
| 62 |
+
|
| 63 |
+
nx_graphs = []
|
| 64 |
+
for graph in samples:
|
| 65 |
+
node_types, edge_types = graph
|
| 66 |
+
A = edge_types.bool().cpu().numpy()
|
| 67 |
+
|
| 68 |
+
nx_graph = nx.from_numpy_array(A)
|
| 69 |
+
nx_graphs.append(nx_graph)
|
| 70 |
+
|
| 71 |
+
return nx_graphs
|
| 72 |
+
|
| 73 |
+
def init_prompt_encoder(self):
|
| 74 |
+
self.text_encoder = SentenceTransformer("all-MiniLM-L6-v2")
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
@torch.no_grad()
|
| 78 |
+
def sample_batch(self, batch_size: int, cond_emb = None, num_nodes = None):
|
| 79 |
+
"""
|
| 80 |
+
:param batch_id: int
|
| 81 |
+
:param batch_size: int
|
| 82 |
+
:param num_nodes: int, <int>tensor (batch_size) (optional) for specifying number of nodes
|
| 83 |
+
:param save_final: int: number of predictions to save to file
|
| 84 |
+
:param keep_chain: int: number of chains to save to file
|
| 85 |
+
:param keep_chain_steps: number of timesteps to save for each chain
|
| 86 |
+
:return: molecule_list. Each element of this list is a tuple (atom_types, charges, positions)
|
| 87 |
+
"""
|
| 88 |
+
if num_nodes is None:
|
| 89 |
+
n_nodes = self.node_dist.sample_n(batch_size, self.device)
|
| 90 |
+
elif type(num_nodes) == int:
|
| 91 |
+
n_nodes = num_nodes * torch.ones(batch_size, device=self.device, dtype=torch.int)
|
| 92 |
+
|
| 93 |
+
n_max = torch.max(n_nodes).item()
|
| 94 |
+
# Build the masks
|
| 95 |
+
arange = torch.arange(n_max, device=self.device).unsqueeze(0).expand(batch_size, -1)
|
| 96 |
+
node_mask = arange < n_nodes.unsqueeze(1)
|
| 97 |
+
# Sample noise -- z has size (n_samples, n_nodes, n_features)
|
| 98 |
+
|
| 99 |
+
z_T = diffusion_utils.sample_discrete_feature_noise(limit_dist=self.limit_dist, node_mask=node_mask, transition=self.cfg.model.transition)
|
| 100 |
+
X, E, y = z_T.X, z_T.E, z_T.y
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
# Iteratively sample p(z_s | z_t) for t = 1, ..., T, with s = t - 1.
|
| 104 |
+
for s_int in tqdm(reversed(range(0, self.T))):
|
| 105 |
+
s_array = s_int * torch.ones((batch_size, 1)).type_as(y)
|
| 106 |
+
t_array = s_array + 1
|
| 107 |
+
s_norm = s_array / self.T
|
| 108 |
+
t_norm = t_array / self.T
|
| 109 |
+
|
| 110 |
+
# Sample z_s
|
| 111 |
+
sampled_s = self.sample_p_zs_given_zt(s_norm, t_norm, X, E, y, node_mask, cond_emb)
|
| 112 |
+
X, E, y = sampled_s.X, sampled_s.E, sampled_s.y
|
| 113 |
+
|
| 114 |
+
# Sample
|
| 115 |
+
sampled_s = sampled_s.mask(node_mask, collapse=True)
|
| 116 |
+
X, E, y = sampled_s.X, sampled_s.E, sampled_s.y
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
graph_list = []
|
| 120 |
+
for i in range(batch_size):
|
| 121 |
+
n = n_nodes[i]
|
| 122 |
+
node_types = X[i, :n].cpu()
|
| 123 |
+
edge_types = E[i, :n, :n].cpu()
|
| 124 |
+
graph_list.append([node_types, edge_types])
|
| 125 |
+
|
| 126 |
+
return graph_list
|
| 127 |
+
|
| 128 |
+
def sample_p_zs_given_zt(self, s, t, X_t, E_t, y_t, node_mask, cond_emb):
|
| 129 |
+
"""Samples from zs ~ p(zs | zt). Only used during sampling.
|
| 130 |
+
if last_step, return the graph prediction as well"""
|
| 131 |
+
bs, n, dxs = X_t.shape
|
| 132 |
+
beta_t = self.noise_schedule(t_normalized=t) # (bs, 1)
|
| 133 |
+
alpha_s_bar = self.noise_schedule.get_alpha_bar(t_normalized=s)
|
| 134 |
+
alpha_t_bar = self.noise_schedule.get_alpha_bar(t_normalized=t)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
# Retrieve transitions matrix
|
| 138 |
+
Qtb = self.transition_model.get_Qt_bar(alpha_t_bar, self.device)
|
| 139 |
+
Qsb = self.transition_model.get_Qt_bar(alpha_s_bar, self.device)
|
| 140 |
+
Qt = self.transition_model.get_Qt(beta_t, self.device)
|
| 141 |
+
|
| 142 |
+
noisy_data = {'X_t': X_t, 'E_t': E_t, 'y_t': y_t, 't': t, 'node_mask': node_mask, 'cond_emb': cond_emb.repeat(X_t.shape[0], 1)}
|
| 143 |
+
extra_data = self.compute_extra_data(noisy_data)
|
| 144 |
+
pred = self.forward(noisy_data, extra_data, node_mask)
|
| 145 |
+
|
| 146 |
+
# Normalize predictions
|
| 147 |
+
pred_X = F.softmax(pred.X, dim=-1) # bs, n, d0
|
| 148 |
+
pred_E = F.softmax(pred.E, dim=-1) # bs, n, n, d0
|
| 149 |
+
|
| 150 |
+
p_s_and_t_given_0_X = diffusion_utils.compute_batched_over0_posterior_distribution(X_t=X_t,
|
| 151 |
+
Qt=Qt.X,
|
| 152 |
+
Qsb=Qsb.X,
|
| 153 |
+
Qtb=Qtb.X)
|
| 154 |
+
|
| 155 |
+
p_s_and_t_given_0_E = diffusion_utils.compute_batched_over0_posterior_distribution(X_t=E_t,
|
| 156 |
+
Qt=Qt.E,
|
| 157 |
+
Qsb=Qsb.E,
|
| 158 |
+
Qtb=Qtb.E)
|
| 159 |
+
# Dim of these two tensors: bs, N, d0, d_t-1
|
| 160 |
+
weighted_X = pred_X.unsqueeze(-1) * p_s_and_t_given_0_X # bs, n, d0, d_t-1
|
| 161 |
+
unnormalized_prob_X = weighted_X.sum(dim=2) # bs, n, d_t-1
|
| 162 |
+
unnormalized_prob_X[torch.sum(unnormalized_prob_X, dim=-1) == 0] = 1e-5
|
| 163 |
+
prob_X = unnormalized_prob_X / torch.sum(unnormalized_prob_X, dim=-1, keepdim=True) # bs, n, d_t-1
|
| 164 |
+
|
| 165 |
+
pred_E = pred_E.reshape((bs, -1, pred_E.shape[-1]))
|
| 166 |
+
weighted_E = pred_E.unsqueeze(-1) * p_s_and_t_given_0_E # bs, N, d0, d_t-1
|
| 167 |
+
unnormalized_prob_E = weighted_E.sum(dim=-2)
|
| 168 |
+
unnormalized_prob_E[torch.sum(unnormalized_prob_E, dim=-1) == 0] = 1e-5
|
| 169 |
+
prob_E = unnormalized_prob_E / torch.sum(unnormalized_prob_E, dim=-1, keepdim=True)
|
| 170 |
+
prob_E = prob_E.reshape(bs, n, n, pred_E.shape[-1])
|
| 171 |
+
|
| 172 |
+
assert ((prob_X.sum(dim=-1) - 1).abs() < 1e-4).all()
|
| 173 |
+
assert ((prob_E.sum(dim=-1) - 1).abs() < 1e-4).all()
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
sampled_s = diffusion_utils.sample_discrete_features(prob_X, prob_E, node_mask=node_mask)
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
X_s = F.one_hot(sampled_s.X, num_classes=self.Xdim_output).float()
|
| 180 |
+
E_s = F.one_hot(sampled_s.E, num_classes=self.Edim_output).float()
|
| 181 |
+
|
| 182 |
+
assert (E_s == torch.transpose(E_s, 1, 2)).all()
|
| 183 |
+
assert (X_t.shape == X_s.shape) and (E_t.shape == E_s.shape)
|
| 184 |
+
|
| 185 |
+
out_one_hot = utils.PlaceHolder(X=X_s, E=E_s, y=torch.zeros(y_t.shape[0], 0))
|
| 186 |
+
|
| 187 |
+
return out_one_hot.mask(node_mask).type_as(y_t)
|
| 188 |
+
|
| 189 |
+
def compute_extra_data(self, noisy_data):
|
| 190 |
+
""" At every training step (after adding noise) and step in sampling, compute extra information and append to
|
| 191 |
+
the network input. """
|
| 192 |
+
|
| 193 |
+
extra_features = self.extra_features(noisy_data)
|
| 194 |
+
|
| 195 |
+
# print(extra_features.X.shape, extra_features.E.shape, extra_features.y.shape)
|
| 196 |
+
extra_X = extra_features.X
|
| 197 |
+
extra_E = extra_features.E
|
| 198 |
+
extra_y = extra_features.y
|
| 199 |
+
|
| 200 |
+
t = noisy_data['t']
|
| 201 |
+
extra_y = torch.cat((extra_y, t), dim=1)
|
| 202 |
+
|
| 203 |
+
return utils.PlaceHolder(X=extra_X, E=extra_E, y=extra_y)
|
| 204 |
+
|
| 205 |
+
def forward(self, noisy_data, extra_data, node_mask):
|
| 206 |
+
# print(noisy_data['cond_emb'].sum())
|
| 207 |
+
B = noisy_data['cond_emb'].unsqueeze(1).unsqueeze(2).expand(-1, noisy_data['X_t'].shape[1], noisy_data['X_t'].shape[1], -1).to(self.device)
|
| 208 |
+
A = noisy_data['cond_emb'].unsqueeze(1).expand(-1, noisy_data['X_t'].shape[1], -1).to(self.device)
|
| 209 |
+
|
| 210 |
+
X = torch.cat((noisy_data['X_t'], extra_data.X, A), dim=2).float()
|
| 211 |
+
E = torch.cat((noisy_data['E_t'], extra_data.E, B), dim=3).float()
|
| 212 |
+
y = torch.hstack((noisy_data['y_t'], extra_data.y)).float()
|
| 213 |
+
|
| 214 |
+
return self.model(X, E, y, node_mask)
|
diffusion/__init__.py
ADDED
|
File without changes
|
diffusion/__pycache__/__init__.cpython-39.pyc
ADDED
|
Binary file (166 Bytes). View file
|
|
|
diffusion/__pycache__/diffusion_utils.cpython-39.pyc
ADDED
|
Binary file (13 kB). View file
|
|
|
diffusion/__pycache__/noise_schedule.cpython-39.pyc
ADDED
|
Binary file (7.85 kB). View file
|
|
|
diffusion/diffusion_utils.py
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from torch.nn import functional as F
|
| 3 |
+
import numpy as np
|
| 4 |
+
import math
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class PlaceHolder:
|
| 9 |
+
def __init__(self, X, E, y):
|
| 10 |
+
self.X = X
|
| 11 |
+
self.E = E
|
| 12 |
+
self.y = y
|
| 13 |
+
|
| 14 |
+
def type_as(self, x: torch.Tensor):
|
| 15 |
+
""" Changes the device and dtype of X, E, y. """
|
| 16 |
+
self.X = self.X.type_as(x)
|
| 17 |
+
self.E = self.E.type_as(x)
|
| 18 |
+
self.y = self.y.type_as(x)
|
| 19 |
+
return self
|
| 20 |
+
|
| 21 |
+
def mask(self, node_mask, collapse=False):
|
| 22 |
+
x_mask = node_mask.unsqueeze(-1) # bs, n, 1
|
| 23 |
+
e_mask1 = x_mask.unsqueeze(2) # bs, n, 1, 1
|
| 24 |
+
e_mask2 = x_mask.unsqueeze(1) # bs, 1, n, 1
|
| 25 |
+
|
| 26 |
+
if collapse:
|
| 27 |
+
self.X = torch.argmax(self.X, dim=-1)
|
| 28 |
+
self.E = torch.argmax(self.E, dim=-1)
|
| 29 |
+
|
| 30 |
+
self.X[node_mask == 0] = - 1
|
| 31 |
+
self.E[(e_mask1 * e_mask2).squeeze(-1) == 0] = - 1
|
| 32 |
+
else:
|
| 33 |
+
self.X = self.X * x_mask
|
| 34 |
+
self.E = self.E * e_mask1 * e_mask2
|
| 35 |
+
assert torch.allclose(self.E, torch.transpose(self.E, 1, 2))
|
| 36 |
+
return self
|
| 37 |
+
|
| 38 |
+
def setup_wandb(cfg):
|
| 39 |
+
config_dict = omegaconf.OmegaConf.to_container(cfg, resolve=True, throw_on_missing=True)
|
| 40 |
+
kwargs = {'name': cfg.general.name, 'project': f'graph_ddm_{cfg.dataset.name}', 'config': config_dict,
|
| 41 |
+
'settings': wandb.Settings(_disable_stats=True), 'reinit': True, 'mode': cfg.general.wandb}
|
| 42 |
+
wandb.init(**kwargs)
|
| 43 |
+
wandb.save('*.txt')
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def sum_except_batch(x):
|
| 47 |
+
return x.reshape(x.size(0), -1).sum(dim=-1)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def assert_correctly_masked(variable, node_mask):
|
| 51 |
+
assert (variable * (1 - node_mask.long())).abs().max().item() < 1e-4, \
|
| 52 |
+
'Variables not masked properly.'
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def sample_gaussian(size):
|
| 56 |
+
x = torch.randn(size)
|
| 57 |
+
return x
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def sample_gaussian_with_mask(size, node_mask):
|
| 61 |
+
x = torch.randn(size)
|
| 62 |
+
x = x.type_as(node_mask.float())
|
| 63 |
+
x_masked = x * node_mask
|
| 64 |
+
return x_masked
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def clip_noise_schedule(alphas2, clip_value=0.001):
|
| 68 |
+
"""
|
| 69 |
+
For a noise schedule given by alpha^2, this clips alpha_t / alpha_t-1. This may help improve stability during
|
| 70 |
+
sampling.
|
| 71 |
+
"""
|
| 72 |
+
alphas2 = np.concatenate([np.ones(1), alphas2], axis=0)
|
| 73 |
+
|
| 74 |
+
alphas_step = (alphas2[1:] / alphas2[:-1])
|
| 75 |
+
|
| 76 |
+
alphas_step = np.clip(alphas_step, a_min=clip_value, a_max=1.)
|
| 77 |
+
alphas2 = np.cumprod(alphas_step, axis=0)
|
| 78 |
+
|
| 79 |
+
return alphas2
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def cosine_beta_schedule(timesteps, s=0.008, raise_to_power: float = 1):
|
| 83 |
+
"""
|
| 84 |
+
cosine schedule
|
| 85 |
+
as proposed in https://openreview.net/forum?id=-NEXDKk8gZ
|
| 86 |
+
"""
|
| 87 |
+
steps = timesteps + 2
|
| 88 |
+
x = np.linspace(0, steps, steps)
|
| 89 |
+
alphas_cumprod = np.cos(((x / steps) + s) / (1 + s) * np.pi * 0.5) ** 2
|
| 90 |
+
alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
|
| 91 |
+
betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
|
| 92 |
+
betas = np.clip(betas, a_min=0, a_max=0.999)
|
| 93 |
+
alphas = 1. - betas
|
| 94 |
+
alphas_cumprod = np.cumprod(alphas, axis=0)
|
| 95 |
+
|
| 96 |
+
if raise_to_power != 1:
|
| 97 |
+
alphas_cumprod = np.power(alphas_cumprod, raise_to_power)
|
| 98 |
+
|
| 99 |
+
return alphas_cumprod
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def cosine_beta_schedule_discrete(timesteps, s=0.008):
|
| 103 |
+
""" Cosine schedule as proposed in https://openreview.net/forum?id=-NEXDKk8gZ. """
|
| 104 |
+
steps = timesteps + 2
|
| 105 |
+
x = np.linspace(0, steps, steps)
|
| 106 |
+
|
| 107 |
+
alphas_cumprod = np.cos(0.5 * np.pi * ((x / steps) + s) / (1 + s)) ** 2
|
| 108 |
+
alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
|
| 109 |
+
alphas = (alphas_cumprod[1:] / alphas_cumprod[:-1])
|
| 110 |
+
betas = 1 - alphas
|
| 111 |
+
return betas.squeeze()
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def custom_beta_schedule_discrete(timesteps, average_num_nodes=50, s=0.008):
|
| 115 |
+
""" Cosine schedule as proposed in https://openreview.net/forum?id=-NEXDKk8gZ. """
|
| 116 |
+
steps = timesteps + 2
|
| 117 |
+
x = np.linspace(0, steps, steps)
|
| 118 |
+
|
| 119 |
+
alphas_cumprod = np.cos(0.5 * np.pi * ((x / steps) + s) / (1 + s)) ** 2
|
| 120 |
+
alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
|
| 121 |
+
alphas = (alphas_cumprod[1:] / alphas_cumprod[:-1])
|
| 122 |
+
betas = 1 - alphas
|
| 123 |
+
|
| 124 |
+
assert timesteps >= 100
|
| 125 |
+
|
| 126 |
+
p = 4 / 5 # 1 - 1 / num_edge_classes
|
| 127 |
+
num_edges = average_num_nodes * (average_num_nodes - 1) / 2
|
| 128 |
+
|
| 129 |
+
# First 100 steps: only a few updates per graph
|
| 130 |
+
updates_per_graph = 1.2
|
| 131 |
+
beta_first = updates_per_graph / (p * num_edges)
|
| 132 |
+
|
| 133 |
+
betas[betas < beta_first] = beta_first
|
| 134 |
+
return np.array(betas)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def gaussian_KL(q_mu, q_sigma):
|
| 139 |
+
"""Computes the KL distance between a normal distribution and the standard normal.
|
| 140 |
+
Args:
|
| 141 |
+
q_mu: Mean of distribution q.
|
| 142 |
+
q_sigma: Standard deviation of distribution q.
|
| 143 |
+
p_mu: Mean of distribution p.
|
| 144 |
+
p_sigma: Standard deviation of distribution p.
|
| 145 |
+
Returns:
|
| 146 |
+
The KL distance, summed over all dimensions except the batch dim.
|
| 147 |
+
"""
|
| 148 |
+
return sum_except_batch((torch.log(1 / q_sigma) + 0.5 * (q_sigma ** 2 + q_mu ** 2) - 0.5))
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def cdf_std_gaussian(x):
|
| 152 |
+
return 0.5 * (1. + torch.erf(x / math.sqrt(2)))
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def SNR(gamma):
|
| 156 |
+
"""Computes signal to noise ratio (alpha^2/sigma^2) given gamma."""
|
| 157 |
+
return torch.exp(-gamma)
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def inflate_batch_array(array, target_shape):
|
| 161 |
+
"""
|
| 162 |
+
Inflates the batch array (array) with only a single axis (i.e. shape = (batch_size,), or possibly more empty
|
| 163 |
+
axes (i.e. shape (batch_size, 1, ..., 1)) to match the target shape.
|
| 164 |
+
"""
|
| 165 |
+
target_shape = (array.size(0),) + (1,) * (len(target_shape) - 1)
|
| 166 |
+
return array.view(target_shape)
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def sigma(gamma, target_shape):
|
| 170 |
+
"""Computes sigma given gamma."""
|
| 171 |
+
return inflate_batch_array(torch.sqrt(torch.sigmoid(gamma)), target_shape)
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def alpha(gamma, target_shape):
|
| 175 |
+
"""Computes alpha given gamma."""
|
| 176 |
+
return inflate_batch_array(torch.sqrt(torch.sigmoid(-gamma)), target_shape)
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def check_mask_correct(variables, node_mask):
|
| 180 |
+
for i, variable in enumerate(variables):
|
| 181 |
+
if len(variable) > 0:
|
| 182 |
+
assert_correctly_masked(variable, node_mask)
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
def check_tensor_same_size(*args):
|
| 186 |
+
for i, arg in enumerate(args):
|
| 187 |
+
if i == 0:
|
| 188 |
+
continue
|
| 189 |
+
assert args[0].size() == arg.size()
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def sigma_and_alpha_t_given_s(gamma_t: torch.Tensor, gamma_s: torch.Tensor, target_size: torch.Size):
|
| 193 |
+
"""
|
| 194 |
+
Computes sigma t given s, using gamma_t and gamma_s. Used during sampling.
|
| 195 |
+
|
| 196 |
+
These are defined as:
|
| 197 |
+
alpha t given s = alpha t / alpha s,
|
| 198 |
+
sigma t given s = sqrt(1 - (alpha t given s) ^2 ).
|
| 199 |
+
"""
|
| 200 |
+
sigma2_t_given_s = inflate_batch_array(
|
| 201 |
+
-torch.expm1(F.softplus(gamma_s) - F.softplus(gamma_t)), target_size
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
# alpha_t_given_s = alpha_t / alpha_s
|
| 205 |
+
log_alpha2_t = F.logsigmoid(-gamma_t)
|
| 206 |
+
log_alpha2_s = F.logsigmoid(-gamma_s)
|
| 207 |
+
log_alpha2_t_given_s = log_alpha2_t - log_alpha2_s
|
| 208 |
+
|
| 209 |
+
alpha_t_given_s = torch.exp(0.5 * log_alpha2_t_given_s)
|
| 210 |
+
alpha_t_given_s = inflate_batch_array(alpha_t_given_s, target_size)
|
| 211 |
+
|
| 212 |
+
sigma_t_given_s = torch.sqrt(sigma2_t_given_s)
|
| 213 |
+
|
| 214 |
+
return sigma2_t_given_s, sigma_t_given_s, alpha_t_given_s
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
def reverse_tensor(x):
|
| 218 |
+
return x[torch.arange(x.size(0) - 1, -1, -1)]
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def sample_feature_noise(X_size, E_size, y_size, node_mask):
|
| 222 |
+
"""Standard normal noise for all features.
|
| 223 |
+
Output size: X.size(), E.size(), y.size() """
|
| 224 |
+
# TODO: How to change this for the multi-gpu case?
|
| 225 |
+
epsX = sample_gaussian(X_size)
|
| 226 |
+
epsE = sample_gaussian(E_size)
|
| 227 |
+
epsy = sample_gaussian(y_size)
|
| 228 |
+
|
| 229 |
+
float_mask = node_mask.float()
|
| 230 |
+
epsX = epsX.type_as(float_mask)
|
| 231 |
+
epsE = epsE.type_as(float_mask)
|
| 232 |
+
epsy = epsy.type_as(float_mask)
|
| 233 |
+
|
| 234 |
+
# Get upper triangular part of edge noise, without main diagonal
|
| 235 |
+
upper_triangular_mask = torch.zeros_like(epsE)
|
| 236 |
+
indices = torch.triu_indices(row=epsE.size(1), col=epsE.size(2), offset=1)
|
| 237 |
+
upper_triangular_mask[:, indices[0], indices[1], :] = 1
|
| 238 |
+
|
| 239 |
+
epsE = epsE * upper_triangular_mask
|
| 240 |
+
epsE = (epsE + torch.transpose(epsE, 1, 2))
|
| 241 |
+
|
| 242 |
+
assert (epsE == torch.transpose(epsE, 1, 2)).all()
|
| 243 |
+
|
| 244 |
+
return PlaceHolder(X=epsX, E=epsE, y=epsy).mask(node_mask)
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
def sample_normal(mu_X, mu_E, mu_y, sigma, node_mask):
|
| 248 |
+
"""Samples from a Normal distribution."""
|
| 249 |
+
# TODO: change for multi-gpu case
|
| 250 |
+
eps = sample_feature_noise(mu_X.size(), mu_E.size(), mu_y.size(), node_mask).type_as(mu_X)
|
| 251 |
+
X = mu_X + sigma * eps.X
|
| 252 |
+
E = mu_E + sigma.unsqueeze(1) * eps.E
|
| 253 |
+
y = mu_y + sigma.squeeze(1) * eps.y
|
| 254 |
+
return PlaceHolder(X=X, E=E, y=y)
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
def check_issues_norm_values(gamma, norm_val1, norm_val2, num_stdevs=8):
|
| 258 |
+
""" Check if 1 / norm_value is still larger than 10 * standard deviation. """
|
| 259 |
+
zeros = torch.zeros((1, 1))
|
| 260 |
+
gamma_0 = gamma(zeros)
|
| 261 |
+
sigma_0 = sigma(gamma_0, target_shape=zeros.size()).item()
|
| 262 |
+
max_norm_value = max(norm_val1, norm_val2)
|
| 263 |
+
if sigma_0 * num_stdevs > 1. / max_norm_value:
|
| 264 |
+
raise ValueError(
|
| 265 |
+
f'Value for normalization value {max_norm_value} probably too '
|
| 266 |
+
f'large with sigma_0 {sigma_0:.5f} and '
|
| 267 |
+
f'1 / norm_value = {1. / max_norm_value}')
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
def sample_discrete_features(probX, probE, node_mask):
|
| 271 |
+
''' Sample features from multinomial distribution with given probabilities (probX, probE, proby)
|
| 272 |
+
:param probX: bs, n, dx_out node features
|
| 273 |
+
:param probE: bs, n, n, de_out edge features
|
| 274 |
+
:param proby: bs, dy_out global features.
|
| 275 |
+
'''
|
| 276 |
+
bs, n, _ = probX.shape
|
| 277 |
+
# Noise X
|
| 278 |
+
# The masked rows should define probability distributions as well
|
| 279 |
+
probX[~node_mask] = 1 / probX.shape[-1]
|
| 280 |
+
|
| 281 |
+
# Flatten the probability tensor to sample with multinomial
|
| 282 |
+
probX = probX.reshape(bs * n, -1) # (bs * n, dx_out)
|
| 283 |
+
|
| 284 |
+
# Sample X
|
| 285 |
+
X_t = probX.multinomial(1) # (bs * n, 1)
|
| 286 |
+
X_t = X_t.reshape(bs, n) # (bs, n)
|
| 287 |
+
|
| 288 |
+
# Noise E
|
| 289 |
+
# The masked rows should define probability distributions as well
|
| 290 |
+
inverse_edge_mask = ~(node_mask.unsqueeze(1) * node_mask.unsqueeze(2))
|
| 291 |
+
diag_mask = torch.eye(n).unsqueeze(0).expand(bs, -1, -1)
|
| 292 |
+
|
| 293 |
+
probE[inverse_edge_mask] = 1 / probE.shape[-1]
|
| 294 |
+
probE[diag_mask.bool()] = 1 / probE.shape[-1]
|
| 295 |
+
|
| 296 |
+
probE = probE.reshape(bs * n * n, -1) # (bs * n * n, de_out)
|
| 297 |
+
|
| 298 |
+
# Sample E
|
| 299 |
+
E_t = probE.multinomial(1).reshape(bs, n, n) # (bs, n, n)
|
| 300 |
+
E_t = torch.triu(E_t, diagonal=1)
|
| 301 |
+
E_t = (E_t + torch.transpose(E_t, 1, 2))
|
| 302 |
+
|
| 303 |
+
return PlaceHolder(X=X_t, E=E_t, y=torch.zeros(bs, 0).type_as(X_t))
|
| 304 |
+
|
| 305 |
+
|
| 306 |
+
def compute_posterior_distribution(M, M_t, Qt_M, Qsb_M, Qtb_M):
|
| 307 |
+
''' M: X or E
|
| 308 |
+
Compute xt @ Qt.T * x0 @ Qsb / x0 @ Qtb @ xt.T
|
| 309 |
+
'''
|
| 310 |
+
# Flatten feature tensors
|
| 311 |
+
M = M.flatten(start_dim=1, end_dim=-2).to(torch.float32) # (bs, N, d) with N = n or n * n
|
| 312 |
+
M_t = M_t.flatten(start_dim=1, end_dim=-2).to(torch.float32) # same
|
| 313 |
+
|
| 314 |
+
Qt_M_T = torch.transpose(Qt_M, -2, -1) # (bs, d, d)
|
| 315 |
+
|
| 316 |
+
left_term = M_t @ Qt_M_T # (bs, N, d)
|
| 317 |
+
right_term = M @ Qsb_M # (bs, N, d)
|
| 318 |
+
product = left_term * right_term # (bs, N, d)
|
| 319 |
+
|
| 320 |
+
denom = M @ Qtb_M # (bs, N, d) @ (bs, d, d) = (bs, N, d)
|
| 321 |
+
denom = (denom * M_t).sum(dim=-1) # (bs, N, d) * (bs, N, d) + sum = (bs, N)
|
| 322 |
+
# denom = product.sum(dim=-1)
|
| 323 |
+
# denom[denom == 0.] = 1
|
| 324 |
+
|
| 325 |
+
prob = product / denom.unsqueeze(-1) # (bs, N, d)
|
| 326 |
+
|
| 327 |
+
return prob
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
def compute_batched_over0_posterior_distribution(X_t, Qt, Qsb, Qtb):
|
| 331 |
+
""" M: X or E
|
| 332 |
+
Compute xt @ Qt.T * x0 @ Qsb / x0 @ Qtb @ xt.T for each possible value of x0
|
| 333 |
+
X_t: bs, n, dt or bs, n, n, dt
|
| 334 |
+
Qt: bs, d_t-1, dt
|
| 335 |
+
Qsb: bs, d0, d_t-1
|
| 336 |
+
Qtb: bs, d0, dt.
|
| 337 |
+
"""
|
| 338 |
+
# Flatten feature tensors
|
| 339 |
+
# Careful with this line. It does nothing if X is a node feature. If X is an edge features it maps to
|
| 340 |
+
# bs x (n ** 2) x d
|
| 341 |
+
X_t = X_t.flatten(start_dim=1, end_dim=-2).to(torch.float32) # bs x N x dt
|
| 342 |
+
|
| 343 |
+
Qt_T = Qt.transpose(-1, -2) # bs, dt, d_t-1
|
| 344 |
+
left_term = X_t @ Qt_T # bs, N, d_t-1
|
| 345 |
+
left_term = left_term.unsqueeze(dim=2) # bs, N, 1, d_t-1
|
| 346 |
+
|
| 347 |
+
right_term = Qsb.unsqueeze(1) # bs, 1, d0, d_t-1
|
| 348 |
+
numerator = left_term * right_term # bs, N, d0, d_t-1
|
| 349 |
+
|
| 350 |
+
X_t_transposed = X_t.transpose(-1, -2) # bs, dt, N
|
| 351 |
+
|
| 352 |
+
prod = Qtb @ X_t_transposed # bs, d0, N
|
| 353 |
+
prod = prod.transpose(-1, -2) # bs, N, d0
|
| 354 |
+
denominator = prod.unsqueeze(-1) # bs, N, d0, 1
|
| 355 |
+
denominator[denominator == 0] = 1e-6
|
| 356 |
+
|
| 357 |
+
out = numerator / denominator
|
| 358 |
+
return out
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
def mask_distributions(true_X, true_E, pred_X, pred_E, node_mask):
|
| 362 |
+
"""
|
| 363 |
+
Set masked rows to arbitrary distributions, so it doesn't contribute to loss
|
| 364 |
+
:param true_X: bs, n, dx_out
|
| 365 |
+
:param true_E: bs, n, n, de_out
|
| 366 |
+
:param pred_X: bs, n, dx_out
|
| 367 |
+
:param pred_E: bs, n, n, de_out
|
| 368 |
+
:param node_mask: bs, n
|
| 369 |
+
:return: same sizes as input
|
| 370 |
+
"""
|
| 371 |
+
|
| 372 |
+
row_X = torch.zeros(true_X.size(-1), dtype=torch.float, device=true_X.device)
|
| 373 |
+
row_X[0] = 1.
|
| 374 |
+
row_E = torch.zeros(true_E.size(-1), dtype=torch.float, device=true_E.device)
|
| 375 |
+
row_E[0] = 1.
|
| 376 |
+
|
| 377 |
+
diag_mask = ~torch.eye(node_mask.size(1), device=node_mask.device, dtype=torch.bool).unsqueeze(0)
|
| 378 |
+
true_X[~node_mask] = row_X
|
| 379 |
+
pred_X[~node_mask] = row_X
|
| 380 |
+
true_E[~(node_mask.unsqueeze(1) * node_mask.unsqueeze(2) * diag_mask), :] = row_E
|
| 381 |
+
pred_E[~(node_mask.unsqueeze(1) * node_mask.unsqueeze(2) * diag_mask), :] = row_E
|
| 382 |
+
|
| 383 |
+
true_X = true_X + 1e-7
|
| 384 |
+
pred_X = pred_X + 1e-7
|
| 385 |
+
true_E = true_E + 1e-7
|
| 386 |
+
pred_E = pred_E + 1e-7
|
| 387 |
+
|
| 388 |
+
true_X = true_X / torch.sum(true_X, dim=-1, keepdim=True)
|
| 389 |
+
pred_X = pred_X / torch.sum(pred_X, dim=-1, keepdim=True)
|
| 390 |
+
true_E = true_E / torch.sum(true_E, dim=-1, keepdim=True)
|
| 391 |
+
pred_E = pred_E / torch.sum(pred_E, dim=-1, keepdim=True)
|
| 392 |
+
|
| 393 |
+
return true_X, true_E, pred_X, pred_E
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
def posterior_distributions(X, E, y, X_t, E_t, y_t, Qt, Qsb, Qtb):
|
| 397 |
+
prob_X = compute_posterior_distribution(M=X, M_t=X_t, Qt_M=Qt.X, Qsb_M=Qsb.X, Qtb_M=Qtb.X) # (bs, n, dx)
|
| 398 |
+
prob_E = compute_posterior_distribution(M=E, M_t=E_t, Qt_M=Qt.E, Qsb_M=Qsb.E, Qtb_M=Qtb.E) # (bs, n * n, de)
|
| 399 |
+
|
| 400 |
+
return PlaceHolder(X=prob_X, E=prob_E, y=y_t)
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
def sample_discrete_feature_noise(limit_dist, node_mask, transition):
|
| 404 |
+
""" Sample from the limit distribution of the diffusion process"""
|
| 405 |
+
bs, n_max = node_mask.shape
|
| 406 |
+
|
| 407 |
+
x_limit = limit_dist.X[None, None, :].expand(bs, n_max, -1)
|
| 408 |
+
e_limit = limit_dist.E[None, None, None, :].expand(bs, n_max, n_max, -1)
|
| 409 |
+
y_limit = limit_dist.y[None, :].expand(bs, -1)
|
| 410 |
+
|
| 411 |
+
U_X = x_limit.flatten(end_dim=-2).multinomial(1).reshape(bs, n_max)
|
| 412 |
+
U_E = e_limit.flatten(end_dim=-2).multinomial(1).reshape(bs, n_max, n_max)
|
| 413 |
+
# print(U_E.shape, U_X.shape, y_limit.shape)
|
| 414 |
+
U_y = torch.empty((bs, 0))
|
| 415 |
+
|
| 416 |
+
long_mask = node_mask.long()
|
| 417 |
+
U_X = U_X.type_as(long_mask)
|
| 418 |
+
U_E = U_E.type_as(long_mask)
|
| 419 |
+
U_y = U_y.type_as(long_mask)
|
| 420 |
+
|
| 421 |
+
U_X = F.one_hot(U_X, num_classes=x_limit.shape[-1]).float()
|
| 422 |
+
U_E = F.one_hot(U_E, num_classes=e_limit.shape[-1]).float()
|
| 423 |
+
|
| 424 |
+
# Get upper triangular part of edge noise, without main diagonal
|
| 425 |
+
upper_triangular_mask = torch.zeros_like(U_E)
|
| 426 |
+
indices = torch.triu_indices(row=U_E.size(1), col=U_E.size(2), offset=1)
|
| 427 |
+
upper_triangular_mask[:, indices[0], indices[1], :] = 1
|
| 428 |
+
|
| 429 |
+
U_E = U_E * upper_triangular_mask
|
| 430 |
+
U_E = (U_E + torch.transpose(U_E, 1, 2))
|
| 431 |
+
|
| 432 |
+
assert (U_E == torch.transpose(U_E, 1, 2)).all()
|
| 433 |
+
|
| 434 |
+
# print(U_X.shape, limit_dist.cond.shape)
|
| 435 |
+
return PlaceHolder(X=U_X, E=U_E, y=U_y).mask(node_mask)
|
| 436 |
+
|
| 437 |
+
|
diffusion/distributions.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class DistributionNodes:
|
| 5 |
+
def __init__(self, histogram):
|
| 6 |
+
""" Compute the distribution of the number of nodes in the dataset, and sample from this distribution.
|
| 7 |
+
historgram: dict. The keys are num_nodes, the values are counts
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
if type(histogram) == dict:
|
| 11 |
+
max_n_nodes = max(histogram.keys())
|
| 12 |
+
prob = torch.zeros(max_n_nodes + 1)
|
| 13 |
+
for num_nodes, count in histogram.items():
|
| 14 |
+
prob[num_nodes] = count
|
| 15 |
+
else:
|
| 16 |
+
prob = histogram
|
| 17 |
+
|
| 18 |
+
self.prob = prob / prob.sum()
|
| 19 |
+
self.m = torch.distributions.Categorical(prob)
|
| 20 |
+
|
| 21 |
+
def sample_n(self, n_samples, device):
|
| 22 |
+
idx = self.m.sample((n_samples,))
|
| 23 |
+
return idx.to(device)
|
| 24 |
+
|
| 25 |
+
def log_prob(self, batch_n_nodes):
|
| 26 |
+
assert len(batch_n_nodes.size()) == 1
|
| 27 |
+
p = self.prob.to(batch_n_nodes.device)
|
| 28 |
+
|
| 29 |
+
probas = p[batch_n_nodes]
|
| 30 |
+
log_p = torch.log(probas + 1e-30)
|
| 31 |
+
return log_p
|
| 32 |
+
|
diffusion/extra_features.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from src import utils
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class DummyExtraFeatures:
|
| 6 |
+
def __init__(self):
|
| 7 |
+
""" This class does not compute anything, just returns empty tensors."""
|
| 8 |
+
|
| 9 |
+
def __call__(self, noisy_data):
|
| 10 |
+
X = noisy_data['X_t']
|
| 11 |
+
E = noisy_data['E_t']
|
| 12 |
+
y = noisy_data['y_t']
|
| 13 |
+
empty_x = X.new_zeros((*X.shape[:-1], 0))
|
| 14 |
+
empty_e = E.new_zeros((*E.shape[:-1], 0))
|
| 15 |
+
empty_y = y.new_zeros((y.shape[0], 0))
|
| 16 |
+
return utils.PlaceHolder(X=empty_x, E=empty_e, y=empty_y)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class ExtraFeatures:
|
| 20 |
+
def __init__(self, extra_features_type, dataset_info):
|
| 21 |
+
self.max_n_nodes = dataset_info.max_n_nodes
|
| 22 |
+
self.ncycles = NodeCycleFeatures()
|
| 23 |
+
self.features_type = extra_features_type
|
| 24 |
+
if extra_features_type in ['eigenvalues', 'all']:
|
| 25 |
+
self.eigenfeatures = EigenFeatures(mode=extra_features_type)
|
| 26 |
+
|
| 27 |
+
def __call__(self, noisy_data):
|
| 28 |
+
n = noisy_data['node_mask'].sum(dim=1).unsqueeze(1) / self.max_n_nodes
|
| 29 |
+
x_cycles, y_cycles = self.ncycles(noisy_data) # (bs, n_cycles)
|
| 30 |
+
|
| 31 |
+
if self.features_type == 'cycles':
|
| 32 |
+
E = noisy_data['E_t']
|
| 33 |
+
extra_edge_attr = torch.zeros((*E.shape[:-1], 0)).type_as(E)
|
| 34 |
+
return utils.PlaceHolder(X=x_cycles, E=extra_edge_attr, y=torch.hstack((n, y_cycles)))
|
| 35 |
+
|
| 36 |
+
elif self.features_type == 'eigenvalues':
|
| 37 |
+
eigenfeatures = self.eigenfeatures(noisy_data)
|
| 38 |
+
E = noisy_data['E_t']
|
| 39 |
+
extra_edge_attr = torch.zeros((*E.shape[:-1], 0)).type_as(E)
|
| 40 |
+
n_components, batched_eigenvalues = eigenfeatures # (bs, 1), (bs, 10)
|
| 41 |
+
return utils.PlaceHolder(X=x_cycles, E=extra_edge_attr, y=torch.hstack((n, y_cycles, n_components,
|
| 42 |
+
batched_eigenvalues)))
|
| 43 |
+
elif self.features_type == 'all':
|
| 44 |
+
eigenfeatures = self.eigenfeatures(noisy_data)
|
| 45 |
+
E = noisy_data['E_t']
|
| 46 |
+
extra_edge_attr = torch.zeros((*E.shape[:-1], 0)).type_as(E)
|
| 47 |
+
n_components, batched_eigenvalues, nonlcc_indicator, k_lowest_eigvec = eigenfeatures # (bs, 1), (bs, 10),
|
| 48 |
+
# (bs, n, 1), (bs, n, 2)
|
| 49 |
+
|
| 50 |
+
return utils.PlaceHolder(X=torch.cat((x_cycles, nonlcc_indicator, k_lowest_eigvec), dim=-1),
|
| 51 |
+
E=extra_edge_attr,
|
| 52 |
+
y=torch.hstack((n, y_cycles, n_components, batched_eigenvalues)))
|
| 53 |
+
else:
|
| 54 |
+
raise ValueError(f"Features type {self.features_type} not implemented")
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
class NodeCycleFeatures:
|
| 58 |
+
def __init__(self):
|
| 59 |
+
self.kcycles = KNodeCycles()
|
| 60 |
+
|
| 61 |
+
def __call__(self, noisy_data):
|
| 62 |
+
adj_matrix = noisy_data['E_t'][..., 1:].sum(dim=-1).float()
|
| 63 |
+
|
| 64 |
+
x_cycles, y_cycles = self.kcycles.k_cycles(adj_matrix=adj_matrix) # (bs, n_cycles)
|
| 65 |
+
x_cycles = x_cycles.type_as(adj_matrix) * noisy_data['node_mask'].unsqueeze(-1)
|
| 66 |
+
# Avoid large values when the graph is dense
|
| 67 |
+
x_cycles = x_cycles / 10
|
| 68 |
+
y_cycles = y_cycles / 10
|
| 69 |
+
x_cycles[x_cycles > 1] = 1
|
| 70 |
+
y_cycles[y_cycles > 1] = 1
|
| 71 |
+
return x_cycles, y_cycles
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
class EigenFeatures:
|
| 75 |
+
"""
|
| 76 |
+
Code taken from : https://github.com/Saro00/DGN/blob/master/models/pytorch/eigen_agg.py
|
| 77 |
+
"""
|
| 78 |
+
def __init__(self, mode):
|
| 79 |
+
""" mode: 'eigenvalues' or 'all' """
|
| 80 |
+
self.mode = mode
|
| 81 |
+
|
| 82 |
+
def __call__(self, noisy_data):
|
| 83 |
+
E_t = noisy_data['E_t']
|
| 84 |
+
mask = noisy_data['node_mask']
|
| 85 |
+
A = E_t[..., 1:].sum(dim=-1).float() * mask.unsqueeze(1) * mask.unsqueeze(2)
|
| 86 |
+
L = compute_laplacian(A, normalize=False)
|
| 87 |
+
mask_diag = 2 * L.shape[-1] * torch.eye(A.shape[-1]).type_as(L).unsqueeze(0)
|
| 88 |
+
mask_diag = mask_diag * (~mask.unsqueeze(1)) * (~mask.unsqueeze(2))
|
| 89 |
+
L = L * mask.unsqueeze(1) * mask.unsqueeze(2) + mask_diag
|
| 90 |
+
|
| 91 |
+
if self.mode == 'eigenvalues':
|
| 92 |
+
eigvals = torch.linalg.eigvalsh(L) # bs, n
|
| 93 |
+
eigvals = eigvals.type_as(A) / torch.sum(mask, dim=1, keepdim=True)
|
| 94 |
+
|
| 95 |
+
n_connected_comp, batch_eigenvalues = get_eigenvalues_features(eigenvalues=eigvals)
|
| 96 |
+
return n_connected_comp.type_as(A), batch_eigenvalues.type_as(A)
|
| 97 |
+
|
| 98 |
+
elif self.mode == 'all':
|
| 99 |
+
eigvals, eigvectors = torch.linalg.eigh(L)
|
| 100 |
+
eigvals = eigvals.type_as(A) / torch.sum(mask, dim=1, keepdim=True)
|
| 101 |
+
eigvectors = eigvectors * mask.unsqueeze(2) * mask.unsqueeze(1)
|
| 102 |
+
# Retrieve eigenvalues features
|
| 103 |
+
n_connected_comp, batch_eigenvalues = get_eigenvalues_features(eigenvalues=eigvals)
|
| 104 |
+
|
| 105 |
+
# Retrieve eigenvectors features
|
| 106 |
+
nonlcc_indicator, k_lowest_eigenvector = get_eigenvectors_features(vectors=eigvectors,
|
| 107 |
+
node_mask=noisy_data['node_mask'],
|
| 108 |
+
n_connected=n_connected_comp)
|
| 109 |
+
return n_connected_comp, batch_eigenvalues, nonlcc_indicator, k_lowest_eigenvector
|
| 110 |
+
else:
|
| 111 |
+
raise NotImplementedError(f"Mode {self.mode} is not implemented")
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def compute_laplacian(adjacency, normalize: bool):
|
| 115 |
+
"""
|
| 116 |
+
adjacency : batched adjacency matrix (bs, n, n)
|
| 117 |
+
normalize: can be None, 'sym' or 'rw' for the combinatorial, symmetric normalized or random walk Laplacians
|
| 118 |
+
Return:
|
| 119 |
+
L (n x n ndarray): combinatorial or symmetric normalized Laplacian.
|
| 120 |
+
"""
|
| 121 |
+
diag = torch.sum(adjacency, dim=-1) # (bs, n)
|
| 122 |
+
n = diag.shape[-1]
|
| 123 |
+
D = torch.diag_embed(diag) # Degree matrix # (bs, n, n)
|
| 124 |
+
combinatorial = D - adjacency # (bs, n, n)
|
| 125 |
+
|
| 126 |
+
if not normalize:
|
| 127 |
+
return (combinatorial + combinatorial.transpose(1, 2)) / 2
|
| 128 |
+
|
| 129 |
+
diag0 = diag.clone()
|
| 130 |
+
diag[diag == 0] = 1e-12
|
| 131 |
+
|
| 132 |
+
diag_norm = 1 / torch.sqrt(diag) # (bs, n)
|
| 133 |
+
D_norm = torch.diag_embed(diag_norm) # (bs, n, n)
|
| 134 |
+
L = torch.eye(n).unsqueeze(0) - D_norm @ adjacency @ D_norm
|
| 135 |
+
L[diag0 == 0] = 0
|
| 136 |
+
return (L + L.transpose(1, 2)) / 2
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def get_eigenvalues_features(eigenvalues, k=5):
|
| 140 |
+
"""
|
| 141 |
+
values : eigenvalues -- (bs, n)
|
| 142 |
+
node_mask: (bs, n)
|
| 143 |
+
k: num of non zero eigenvalues to keep
|
| 144 |
+
"""
|
| 145 |
+
ev = eigenvalues
|
| 146 |
+
bs, n = ev.shape
|
| 147 |
+
n_connected_components = (ev < 1e-5).sum(dim=-1)
|
| 148 |
+
assert (n_connected_components > 0).all(), (n_connected_components, ev)
|
| 149 |
+
|
| 150 |
+
to_extend = max(n_connected_components) + k - n
|
| 151 |
+
if to_extend > 0:
|
| 152 |
+
eigenvalues = torch.hstack((eigenvalues, 2 * torch.ones(bs, to_extend).type_as(eigenvalues)))
|
| 153 |
+
indices = torch.arange(k).type_as(eigenvalues).long().unsqueeze(0) + n_connected_components.unsqueeze(1)
|
| 154 |
+
first_k_ev = torch.gather(eigenvalues, dim=1, index=indices)
|
| 155 |
+
return n_connected_components.unsqueeze(-1), first_k_ev
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def get_eigenvectors_features(vectors, node_mask, n_connected, k=2):
|
| 159 |
+
"""
|
| 160 |
+
vectors (bs, n, n) : eigenvectors of Laplacian IN COLUMNS
|
| 161 |
+
returns:
|
| 162 |
+
not_lcc_indicator : indicator vectors of largest connected component (lcc) for each graph -- (bs, n, 1)
|
| 163 |
+
k_lowest_eigvec : k first eigenvectors for the largest connected component -- (bs, n, k)
|
| 164 |
+
"""
|
| 165 |
+
bs, n = vectors.size(0), vectors.size(1)
|
| 166 |
+
|
| 167 |
+
# Create an indicator for the nodes outside the largest connected components
|
| 168 |
+
first_ev = torch.round(vectors[:, :, 0], decimals=3) * node_mask # bs, n
|
| 169 |
+
# Add random value to the mask to prevent 0 from becoming the mode
|
| 170 |
+
random = torch.randn(bs, n, device=node_mask.device) * (~node_mask) # bs, n
|
| 171 |
+
first_ev = first_ev + random
|
| 172 |
+
most_common = torch.mode(first_ev, dim=1).values # values: bs -- indices: bs
|
| 173 |
+
mask = ~ (first_ev == most_common.unsqueeze(1))
|
| 174 |
+
not_lcc_indicator = (mask * node_mask).unsqueeze(-1).float()
|
| 175 |
+
|
| 176 |
+
# Get the eigenvectors corresponding to the first nonzero eigenvalues
|
| 177 |
+
to_extend = max(n_connected) + k - n
|
| 178 |
+
if to_extend > 0:
|
| 179 |
+
vectors = torch.cat((vectors, torch.zeros(bs, n, to_extend).type_as(vectors)), dim=2) # bs, n , n + to_extend
|
| 180 |
+
indices = torch.arange(k).type_as(vectors).long().unsqueeze(0).unsqueeze(0) + n_connected.unsqueeze(2) # bs, 1, k
|
| 181 |
+
indices = indices.expand(-1, n, -1) # bs, n, k
|
| 182 |
+
first_k_ev = torch.gather(vectors, dim=2, index=indices) # bs, n, k
|
| 183 |
+
first_k_ev = first_k_ev * node_mask.unsqueeze(2)
|
| 184 |
+
|
| 185 |
+
return not_lcc_indicator, first_k_ev
|
| 186 |
+
|
| 187 |
+
def batch_trace(X):
|
| 188 |
+
"""
|
| 189 |
+
Expect a matrix of shape B N N, returns the trace in shape B
|
| 190 |
+
:param X:
|
| 191 |
+
:return:
|
| 192 |
+
"""
|
| 193 |
+
diag = torch.diagonal(X, dim1=-2, dim2=-1)
|
| 194 |
+
trace = diag.sum(dim=-1)
|
| 195 |
+
return trace
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def batch_diagonal(X):
|
| 199 |
+
"""
|
| 200 |
+
Extracts the diagonal from the last two dims of a tensor
|
| 201 |
+
:param X:
|
| 202 |
+
:return:
|
| 203 |
+
"""
|
| 204 |
+
return torch.diagonal(X, dim1=-2, dim2=-1)
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
class KNodeCycles:
|
| 208 |
+
""" Builds cycle counts for each node in a graph.
|
| 209 |
+
"""
|
| 210 |
+
|
| 211 |
+
def __init__(self):
|
| 212 |
+
super().__init__()
|
| 213 |
+
|
| 214 |
+
def calculate_kpowers(self):
|
| 215 |
+
self.k1_matrix = self.adj_matrix.float()
|
| 216 |
+
self.d = self.adj_matrix.sum(dim=-1)
|
| 217 |
+
self.k2_matrix = self.k1_matrix @ self.adj_matrix.float()
|
| 218 |
+
self.k3_matrix = self.k2_matrix @ self.adj_matrix.float()
|
| 219 |
+
self.k4_matrix = self.k3_matrix @ self.adj_matrix.float()
|
| 220 |
+
self.k5_matrix = self.k4_matrix @ self.adj_matrix.float()
|
| 221 |
+
self.k6_matrix = self.k5_matrix @ self.adj_matrix.float()
|
| 222 |
+
|
| 223 |
+
def k3_cycle(self):
|
| 224 |
+
""" tr(A ** 3). """
|
| 225 |
+
c3 = batch_diagonal(self.k3_matrix)
|
| 226 |
+
return (c3 / 2).unsqueeze(-1).float(), (torch.sum(c3, dim=-1) / 6).unsqueeze(-1).float()
|
| 227 |
+
|
| 228 |
+
def k4_cycle(self):
|
| 229 |
+
diag_a4 = batch_diagonal(self.k4_matrix)
|
| 230 |
+
c4 = diag_a4 - self.d * (self.d - 1) - (self.adj_matrix @ self.d.unsqueeze(-1)).sum(dim=-1)
|
| 231 |
+
return (c4 / 2).unsqueeze(-1).float(), (torch.sum(c4, dim=-1) / 8).unsqueeze(-1).float()
|
| 232 |
+
|
| 233 |
+
def k5_cycle(self):
|
| 234 |
+
diag_a5 = batch_diagonal(self.k5_matrix)
|
| 235 |
+
triangles = batch_diagonal(self.k3_matrix)
|
| 236 |
+
c5 = diag_a5 - 2 * triangles * self.d - (self.adj_matrix @ triangles.unsqueeze(-1)).sum(dim=-1) + triangles
|
| 237 |
+
return (c5 / 2).unsqueeze(-1).float(), (c5.sum(dim=-1) / 10).unsqueeze(-1).float()
|
| 238 |
+
|
| 239 |
+
def k6_cycle(self):
|
| 240 |
+
term_1_t = batch_trace(self.k6_matrix)
|
| 241 |
+
term_2_t = batch_trace(self.k3_matrix ** 2)
|
| 242 |
+
term3_t = torch.sum(self.adj_matrix * self.k2_matrix.pow(2), dim=[-2, -1])
|
| 243 |
+
d_t4 = batch_diagonal(self.k2_matrix)
|
| 244 |
+
a_4_t = batch_diagonal(self.k4_matrix)
|
| 245 |
+
term_4_t = (d_t4 * a_4_t).sum(dim=-1)
|
| 246 |
+
term_5_t = batch_trace(self.k4_matrix)
|
| 247 |
+
term_6_t = batch_trace(self.k3_matrix)
|
| 248 |
+
term_7_t = batch_diagonal(self.k2_matrix).pow(3).sum(-1)
|
| 249 |
+
term8_t = torch.sum(self.k3_matrix, dim=[-2, -1])
|
| 250 |
+
term9_t = batch_diagonal(self.k2_matrix).pow(2).sum(-1)
|
| 251 |
+
term10_t = batch_trace(self.k2_matrix)
|
| 252 |
+
|
| 253 |
+
c6_t = (term_1_t - 3 * term_2_t + 9 * term3_t - 6 * term_4_t + 6 * term_5_t - 4 * term_6_t + 4 * term_7_t +
|
| 254 |
+
3 * term8_t - 12 * term9_t + 4 * term10_t)
|
| 255 |
+
return None, (c6_t / 12).unsqueeze(-1).float()
|
| 256 |
+
|
| 257 |
+
def k_cycles(self, adj_matrix, verbose=False):
|
| 258 |
+
self.adj_matrix = adj_matrix
|
| 259 |
+
self.calculate_kpowers()
|
| 260 |
+
|
| 261 |
+
k3x, k3y = self.k3_cycle()
|
| 262 |
+
assert (k3x >= -0.1).all()
|
| 263 |
+
|
| 264 |
+
k4x, k4y = self.k4_cycle()
|
| 265 |
+
assert (k4x >= -0.1).all()
|
| 266 |
+
|
| 267 |
+
k5x, k5y = self.k5_cycle()
|
| 268 |
+
assert (k5x >= -0.1).all(), k5x
|
| 269 |
+
|
| 270 |
+
_, k6y = self.k6_cycle()
|
| 271 |
+
assert (k6y >= -0.1).all()
|
| 272 |
+
|
| 273 |
+
kcyclesx = torch.cat([k3x, k4x, k5x], dim=-1)
|
| 274 |
+
kcyclesy = torch.cat([k3y, k4y, k5y, k6y], dim=-1)
|
| 275 |
+
return kcyclesx, kcyclesy
|
diffusion/extra_features_molecular.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from src import utils
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class ExtraMolecularFeatures:
|
| 6 |
+
def __init__(self, dataset_infos):
|
| 7 |
+
self.charge = ChargeFeature(remove_h=dataset_infos.remove_h, valencies=dataset_infos.valencies)
|
| 8 |
+
self.valency = ValencyFeature()
|
| 9 |
+
self.weight = WeightFeature(max_weight=dataset_infos.max_weight, atom_weights=dataset_infos.atom_weights)
|
| 10 |
+
|
| 11 |
+
def __call__(self, noisy_data):
|
| 12 |
+
charge = self.charge(noisy_data).unsqueeze(-1) # (bs, n, 1)
|
| 13 |
+
valency = self.valency(noisy_data).unsqueeze(-1) # (bs, n, 1)
|
| 14 |
+
weight = self.weight(noisy_data) # (bs, 1)
|
| 15 |
+
|
| 16 |
+
extra_edge_attr = torch.zeros((*noisy_data['E_t'].shape[:-1], 0)).type_as(noisy_data['E_t'])
|
| 17 |
+
|
| 18 |
+
return utils.PlaceHolder(X=torch.cat((charge, valency), dim=-1), E=extra_edge_attr, y=weight)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class ChargeFeature:
|
| 22 |
+
def __init__(self, remove_h, valencies):
|
| 23 |
+
self.remove_h = remove_h
|
| 24 |
+
self.valencies = valencies
|
| 25 |
+
|
| 26 |
+
def __call__(self, noisy_data):
|
| 27 |
+
bond_orders = torch.tensor([0, 1, 2, 3, 1.5], device=noisy_data['E_t'].device).reshape(1, 1, 1, -1)
|
| 28 |
+
weighted_E = noisy_data['E_t'] * bond_orders # (bs, n, n, de)
|
| 29 |
+
current_valencies = weighted_E.argmax(dim=-1).sum(dim=-1) # (bs, n)
|
| 30 |
+
|
| 31 |
+
valencies = torch.tensor(self.valencies, device=noisy_data['X_t'].device).reshape(1, 1, -1)
|
| 32 |
+
X = noisy_data['X_t'] * valencies # (bs, n, dx)
|
| 33 |
+
normal_valencies = torch.argmax(X, dim=-1) # (bs, n)
|
| 34 |
+
|
| 35 |
+
return (normal_valencies - current_valencies).type_as(noisy_data['X_t'])
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
class ValencyFeature:
|
| 39 |
+
def __init__(self):
|
| 40 |
+
pass
|
| 41 |
+
|
| 42 |
+
def __call__(self, noisy_data):
|
| 43 |
+
orders = torch.tensor([0, 1, 2, 3, 1.5], device=noisy_data['E_t'].device).reshape(1, 1, 1, -1)
|
| 44 |
+
E = noisy_data['E_t'] * orders # (bs, n, n, de)
|
| 45 |
+
valencies = E.argmax(dim=-1).sum(dim=-1) # (bs, n)
|
| 46 |
+
return valencies.type_as(noisy_data['X_t'])
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class WeightFeature:
|
| 50 |
+
def __init__(self, max_weight, atom_weights):
|
| 51 |
+
self.max_weight = max_weight
|
| 52 |
+
self.atom_weight_list = torch.tensor(list(atom_weights.values()))
|
| 53 |
+
|
| 54 |
+
def __call__(self, noisy_data):
|
| 55 |
+
X = torch.argmax(noisy_data['X_t'], dim=-1) # (bs, n)
|
| 56 |
+
X_weights = self.atom_weight_list.to(X.device)[X] # (bs, n)
|
| 57 |
+
return X_weights.sum(dim=-1).unsqueeze(-1).type_as(noisy_data['X_t']) / self.max_weight # (bs, 1)
|
diffusion/layers.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import torch
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class SinusoidalPosEmb(torch.nn.Module):
|
| 6 |
+
def __init__(self, dim):
|
| 7 |
+
super().__init__()
|
| 8 |
+
self.dim = dim
|
| 9 |
+
|
| 10 |
+
def forward(self, x):
|
| 11 |
+
x = x.squeeze() * 1000
|
| 12 |
+
assert len(x.shape) == 1
|
| 13 |
+
half_dim = self.dim // 2
|
| 14 |
+
emb = math.log(10000) / (half_dim - 1)
|
| 15 |
+
emb = torch.exp(torch.arange(half_dim) * -emb)
|
| 16 |
+
emb = emb.type_as(x)
|
| 17 |
+
emb = x[:, None] * emb[None, :]
|
| 18 |
+
emb = torch.cat((emb.sin(), emb.cos()), dim=-1)
|
| 19 |
+
return emb
|
diffusion/noise_schedule.py
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import torch
|
| 3 |
+
import utils
|
| 4 |
+
from diffusion import diffusion_utils
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class PredefinedNoiseSchedule(torch.nn.Module):
|
| 8 |
+
"""
|
| 9 |
+
Predefined noise schedule. Essentially creates a lookup array for predefined (non-learned) noise schedules.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
def __init__(self, noise_schedule, timesteps):
|
| 13 |
+
super(PredefinedNoiseSchedule, self).__init__()
|
| 14 |
+
self.timesteps = timesteps
|
| 15 |
+
|
| 16 |
+
if noise_schedule == 'cosine':
|
| 17 |
+
alphas2 = diffusion_utils.cosine_beta_schedule(timesteps)
|
| 18 |
+
elif noise_schedule == 'custom':
|
| 19 |
+
raise NotImplementedError()
|
| 20 |
+
else:
|
| 21 |
+
raise ValueError(noise_schedule)
|
| 22 |
+
|
| 23 |
+
# print('alphas2', alphas2)
|
| 24 |
+
|
| 25 |
+
sigmas2 = 1 - alphas2
|
| 26 |
+
|
| 27 |
+
log_alphas2 = np.log(alphas2)
|
| 28 |
+
log_sigmas2 = np.log(sigmas2)
|
| 29 |
+
|
| 30 |
+
log_alphas2_to_sigmas2 = log_alphas2 - log_sigmas2 # (timesteps + 1, )
|
| 31 |
+
|
| 32 |
+
# print('gamma', -log_alphas2_to_sigmas2)
|
| 33 |
+
|
| 34 |
+
self.gamma = torch.nn.Parameter(
|
| 35 |
+
torch.from_numpy(-log_alphas2_to_sigmas2).float(),
|
| 36 |
+
requires_grad=False)
|
| 37 |
+
|
| 38 |
+
def forward(self, t):
|
| 39 |
+
t_int = torch.round(t * self.timesteps).long()
|
| 40 |
+
return self.gamma[t_int]
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class PredefinedNoiseScheduleDiscrete(torch.nn.Module):
|
| 45 |
+
"""
|
| 46 |
+
Predefined noise schedule. Essentially creates a lookup array for predefined (non-learned) noise schedules.
|
| 47 |
+
"""
|
| 48 |
+
|
| 49 |
+
def __init__(self, noise_schedule, timesteps):
|
| 50 |
+
super(PredefinedNoiseScheduleDiscrete, self).__init__()
|
| 51 |
+
self.timesteps = timesteps
|
| 52 |
+
|
| 53 |
+
if noise_schedule == 'cosine':
|
| 54 |
+
betas = diffusion_utils.cosine_beta_schedule_discrete(timesteps)
|
| 55 |
+
elif noise_schedule == 'custom':
|
| 56 |
+
betas = diffusion_utils.custom_beta_schedule_discrete(timesteps)
|
| 57 |
+
else:
|
| 58 |
+
raise NotImplementedError(noise_schedule)
|
| 59 |
+
|
| 60 |
+
self.register_buffer('betas', torch.from_numpy(betas).float())
|
| 61 |
+
|
| 62 |
+
self.alphas = 1 - torch.clamp(self.betas, min=0, max=0.9999)
|
| 63 |
+
|
| 64 |
+
log_alpha = torch.log(self.alphas)
|
| 65 |
+
log_alpha_bar = torch.cumsum(log_alpha, dim=0)
|
| 66 |
+
self.alphas_bar = torch.exp(log_alpha_bar)
|
| 67 |
+
# print(f"[Noise schedule: {noise_schedule}] alpha_bar:", self.alphas_bar)
|
| 68 |
+
|
| 69 |
+
def forward(self, t_normalized=None, t_int=None):
|
| 70 |
+
assert int(t_normalized is None) + int(t_int is None) == 1
|
| 71 |
+
if t_int is None:
|
| 72 |
+
t_int = torch.round(t_normalized * self.timesteps)
|
| 73 |
+
|
| 74 |
+
return self.betas[t_int.long()]
|
| 75 |
+
|
| 76 |
+
def get_alpha_bar(self, t_normalized=None, t_int=None):
|
| 77 |
+
assert int(t_normalized is None) + int(t_int is None) == 1
|
| 78 |
+
if t_int is None:
|
| 79 |
+
t_int = torch.round(t_normalized * self.timesteps)
|
| 80 |
+
return self.alphas_bar.to(t_int.device)[t_int.long()]
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
class DiscreteUniformTransition:
|
| 84 |
+
def __init__(self, x_classes: int, e_classes: int, y_classes: int):
|
| 85 |
+
self.X_classes = x_classes
|
| 86 |
+
self.E_classes = e_classes
|
| 87 |
+
self.y_classes = y_classes
|
| 88 |
+
self.u_x = torch.ones(1, self.X_classes, self.X_classes)
|
| 89 |
+
if self.X_classes > 0:
|
| 90 |
+
self.u_x = self.u_x / self.X_classes
|
| 91 |
+
|
| 92 |
+
self.u_e = torch.ones(1, self.E_classes, self.E_classes)
|
| 93 |
+
if self.E_classes > 0:
|
| 94 |
+
self.u_e = self.u_e / self.E_classes
|
| 95 |
+
|
| 96 |
+
self.u_y = torch.ones(1, self.y_classes, self.y_classes)
|
| 97 |
+
if self.y_classes > 0:
|
| 98 |
+
self.u_y = self.u_y / self.y_classes
|
| 99 |
+
|
| 100 |
+
def get_Qt(self, beta_t, device):
|
| 101 |
+
""" Returns one-step transition matrices for X and E, from step t - 1 to step t.
|
| 102 |
+
Qt = (1 - beta_t) * I + beta_t / K
|
| 103 |
+
|
| 104 |
+
beta_t: (bs) noise level between 0 and 1
|
| 105 |
+
returns: qx (bs, dx, dx), qe (bs, de, de), qy (bs, dy, dy).
|
| 106 |
+
"""
|
| 107 |
+
beta_t = beta_t.unsqueeze(1)
|
| 108 |
+
beta_t = beta_t.to(device)
|
| 109 |
+
self.u_x = self.u_x.to(device)
|
| 110 |
+
self.u_e = self.u_e.to(device)
|
| 111 |
+
self.u_y = self.u_y.to(device)
|
| 112 |
+
|
| 113 |
+
q_x = beta_t * self.u_x + (1 - beta_t) * torch.eye(self.X_classes, device=device).unsqueeze(0)
|
| 114 |
+
q_e = beta_t * self.u_e + (1 - beta_t) * torch.eye(self.E_classes, device=device).unsqueeze(0)
|
| 115 |
+
q_y = beta_t * self.u_y + (1 - beta_t) * torch.eye(self.y_classes, device=device).unsqueeze(0)
|
| 116 |
+
|
| 117 |
+
return utils.PlaceHolder(X=q_x, E=q_e, y=q_y)
|
| 118 |
+
|
| 119 |
+
def get_Qt_bar(self, alpha_bar_t, device):
|
| 120 |
+
""" Returns t-step transition matrices for X and E, from step 0 to step t.
|
| 121 |
+
Qt = prod(1 - beta_t) * I + (1 - prod(1 - beta_t)) / K
|
| 122 |
+
|
| 123 |
+
alpha_bar_t: (bs) Product of the (1 - beta_t) for each time step from 0 to t.
|
| 124 |
+
returns: qx (bs, dx, dx), qe (bs, de, de), qy (bs, dy, dy).
|
| 125 |
+
"""
|
| 126 |
+
alpha_bar_t = alpha_bar_t.unsqueeze(1)
|
| 127 |
+
|
| 128 |
+
alpha_bar_t = alpha_bar_t.to(device)
|
| 129 |
+
self.u_x = self.u_x.to(device)
|
| 130 |
+
self.u_e = self.u_e.to(device)
|
| 131 |
+
self.u_y = self.u_y.to(device)
|
| 132 |
+
|
| 133 |
+
q_x = alpha_bar_t * torch.eye(self.X_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_x
|
| 134 |
+
q_e = alpha_bar_t * torch.eye(self.E_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_e
|
| 135 |
+
q_y = alpha_bar_t * torch.eye(self.y_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_y
|
| 136 |
+
|
| 137 |
+
return utils.PlaceHolder(X=q_x, E=q_e, y=q_y)
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
class MarginalUniformTransition:
|
| 141 |
+
def __init__(self, x_marginals, e_marginals, y_classes):
|
| 142 |
+
self.X_classes = len(x_marginals)
|
| 143 |
+
self.E_classes = len(e_marginals)
|
| 144 |
+
self.y_classes = y_classes
|
| 145 |
+
self.x_marginals = x_marginals
|
| 146 |
+
self.e_marginals = e_marginals
|
| 147 |
+
|
| 148 |
+
self.u_x = x_marginals.unsqueeze(0).expand(self.X_classes, -1).unsqueeze(0)
|
| 149 |
+
self.u_e = e_marginals.unsqueeze(0).expand(self.E_classes, -1).unsqueeze(0)
|
| 150 |
+
self.u_y = torch.ones(1, self.y_classes, self.y_classes)
|
| 151 |
+
if self.y_classes > 0:
|
| 152 |
+
self.u_y = self.u_y / self.y_classes
|
| 153 |
+
|
| 154 |
+
def get_Qt(self, beta_t, device):
|
| 155 |
+
""" Returns one-step transition matrices for X and E, from step t - 1 to step t.
|
| 156 |
+
Qt = (1 - beta_t) * I + beta_t / K
|
| 157 |
+
|
| 158 |
+
beta_t: (bs) noise level between 0 and 1
|
| 159 |
+
returns: qx (bs, dx, dx), qe (bs, de, de), qy (bs, dy, dy). """
|
| 160 |
+
beta_t = beta_t.unsqueeze(1)
|
| 161 |
+
beta_t = beta_t.to(device)
|
| 162 |
+
self.u_x = self.u_x.to(device)
|
| 163 |
+
self.u_e = self.u_e.to(device)
|
| 164 |
+
self.u_y = self.u_y.to(device)
|
| 165 |
+
|
| 166 |
+
q_x = beta_t * self.u_x + (1 - beta_t) * torch.eye(self.X_classes, device=device).unsqueeze(0)
|
| 167 |
+
q_e = beta_t * self.u_e + (1 - beta_t) * torch.eye(self.E_classes, device=device).unsqueeze(0)
|
| 168 |
+
q_y = beta_t * self.u_y + (1 - beta_t) * torch.eye(self.y_classes, device=device).unsqueeze(0)
|
| 169 |
+
|
| 170 |
+
return utils.PlaceHolder(X=q_x, E=q_e, y=q_y)
|
| 171 |
+
|
| 172 |
+
def get_Qt_bar(self, alpha_bar_t, device):
|
| 173 |
+
""" Returns t-step transition matrices for X and E, from step 0 to step t.
|
| 174 |
+
Qt = prod(1 - beta_t) * I + (1 - prod(1 - beta_t)) * K
|
| 175 |
+
|
| 176 |
+
alpha_bar_t: (bs) Product of the (1 - beta_t) for each time step from 0 to t.
|
| 177 |
+
returns: qx (bs, dx, dx), qe (bs, de, de), qy (bs, dy, dy).
|
| 178 |
+
"""
|
| 179 |
+
alpha_bar_t = alpha_bar_t.unsqueeze(1)
|
| 180 |
+
alpha_bar_t = alpha_bar_t.to(device)
|
| 181 |
+
self.u_x = self.u_x.to(device)
|
| 182 |
+
self.u_e = self.u_e.to(device)
|
| 183 |
+
self.u_y = self.u_y.to(device)
|
| 184 |
+
|
| 185 |
+
q_x = alpha_bar_t * torch.eye(self.X_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_x
|
| 186 |
+
q_e = alpha_bar_t * torch.eye(self.E_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_e
|
| 187 |
+
q_y = alpha_bar_t * torch.eye(self.y_classes, device=device).unsqueeze(0) + (1 - alpha_bar_t) * self.u_y
|
| 188 |
+
|
| 189 |
+
return utils.PlaceHolder(X=q_x, E=q_e, y=q_y)
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
class AbsorbingStateTransition:
|
| 193 |
+
def __init__(self, abs_state: int, x_classes: int, e_classes: int, y_classes: int):
|
| 194 |
+
self.X_classes = x_classes
|
| 195 |
+
self.E_classes = e_classes
|
| 196 |
+
self.y_classes = y_classes
|
| 197 |
+
|
| 198 |
+
self.u_x = torch.zeros(1, self.X_classes, self.X_classes)
|
| 199 |
+
self.u_x[:, :, abs_state] = 1
|
| 200 |
+
|
| 201 |
+
self.u_e = torch.zeros(1, self.E_classes, self.E_classes)
|
| 202 |
+
self.u_e[:, :, abs_state] = 1
|
| 203 |
+
|
| 204 |
+
self.u_y = torch.zeros(1, self.y_classes, self.y_classes)
|
| 205 |
+
self.u_e[:, :, abs_state] = 1
|
| 206 |
+
|
| 207 |
+
def get_Qt(self, beta_t):
|
| 208 |
+
""" Returns two transition matrix for X and E"""
|
| 209 |
+
beta_t = beta_t.unsqueeze(1)
|
| 210 |
+
q_x = beta_t * self.u_x + (1 - beta_t) * torch.eye(self.X_classes).unsqueeze(0)
|
| 211 |
+
q_e = beta_t * self.u_e + (1 - beta_t) * torch.eye(self.E_classes).unsqueeze(0)
|
| 212 |
+
q_y = beta_t * self.u_y + (1 - beta_t) * torch.eye(self.y_classes).unsqueeze(0)
|
| 213 |
+
return q_x, q_e, q_y
|
| 214 |
+
|
| 215 |
+
def get_Qt_bar(self, alpha_bar_t):
|
| 216 |
+
""" beta_t: (bs)
|
| 217 |
+
Returns transition matrices for X and E"""
|
| 218 |
+
|
| 219 |
+
alpha_bar_t = alpha_bar_t.unsqueeze(1)
|
| 220 |
+
|
| 221 |
+
q_x = alpha_bar_t * torch.eye(self.X_classes).unsqueeze(0) + (1 - alpha_bar_t) * self.u_x
|
| 222 |
+
q_e = alpha_bar_t * torch.eye(self.E_classes).unsqueeze(0) + (1 - alpha_bar_t) * self.u_e
|
| 223 |
+
q_y = alpha_bar_t * torch.eye(self.y_classes).unsqueeze(0) + (1 - alpha_bar_t) * self.u_y
|
| 224 |
+
|
| 225 |
+
return q_x, q_e, q_y
|
diffusion/utils.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch_geometric.utils
|
| 3 |
+
from omegaconf import OmegaConf, open_dict
|
| 4 |
+
from torch_geometric.utils import to_dense_adj, to_dense_batch
|
| 5 |
+
import torch
|
| 6 |
+
import omegaconf
|
| 7 |
+
import wandb
|
| 8 |
+
|
| 9 |
+
def create_folders(args):
|
| 10 |
+
try:
|
| 11 |
+
# os.makedirs('checkpoints')
|
| 12 |
+
os.makedirs('graphs')
|
| 13 |
+
os.makedirs('chains')
|
| 14 |
+
except OSError:
|
| 15 |
+
pass
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
# os.makedirs('checkpoints/' + args.general.name)
|
| 19 |
+
os.makedirs('graphs/' + args.general.name)
|
| 20 |
+
os.makedirs('chains/' + args.general.name)
|
| 21 |
+
except OSError:
|
| 22 |
+
pass
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def normalize(X, E, y, norm_values, norm_biases, node_mask):
|
| 26 |
+
X = (X - norm_biases[0]) / norm_values[0]
|
| 27 |
+
E = (E - norm_biases[1]) / norm_values[1]
|
| 28 |
+
y = (y - norm_biases[2]) / norm_values[2]
|
| 29 |
+
|
| 30 |
+
diag = torch.eye(E.shape[1], dtype=torch.bool).unsqueeze(0).expand(E.shape[0], -1, -1)
|
| 31 |
+
E[diag] = 0
|
| 32 |
+
|
| 33 |
+
return PlaceHolder(X=X, E=E, y=y).mask(node_mask)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def unnormalize(X, E, y, norm_values, norm_biases, node_mask, collapse=False):
|
| 37 |
+
"""
|
| 38 |
+
X : node features
|
| 39 |
+
E : edge features
|
| 40 |
+
y : global features`
|
| 41 |
+
norm_values : [norm value X, norm value E, norm value y]
|
| 42 |
+
norm_biases : same order
|
| 43 |
+
node_mask
|
| 44 |
+
"""
|
| 45 |
+
X = (X * norm_values[0] + norm_biases[0])
|
| 46 |
+
E = (E * norm_values[1] + norm_biases[1])
|
| 47 |
+
y = y * norm_values[2] + norm_biases[2]
|
| 48 |
+
|
| 49 |
+
return PlaceHolder(X=X, E=E, y=y).mask(node_mask, collapse)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def to_dense(x, edge_index, edge_attr, batch):
|
| 53 |
+
X, node_mask = to_dense_batch(x=x, batch=batch)
|
| 54 |
+
# node_mask = node_mask.float()
|
| 55 |
+
edge_index, edge_attr = torch_geometric.utils.remove_self_loops(edge_index, edge_attr)
|
| 56 |
+
# TODO: carefully check if setting node_mask as a bool breaks the continuous case
|
| 57 |
+
max_num_nodes = X.size(1)
|
| 58 |
+
E = to_dense_adj(edge_index=edge_index, batch=batch, edge_attr=edge_attr, max_num_nodes=max_num_nodes)
|
| 59 |
+
E = encode_no_edge(E)
|
| 60 |
+
|
| 61 |
+
return PlaceHolder(X=X, E=E, y=None), node_mask
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def encode_no_edge(E):
|
| 65 |
+
assert len(E.shape) == 4
|
| 66 |
+
if E.shape[-1] == 0:
|
| 67 |
+
return E
|
| 68 |
+
no_edge = torch.sum(E, dim=3) == 0
|
| 69 |
+
first_elt = E[:, :, :, 0]
|
| 70 |
+
first_elt[no_edge] = 1
|
| 71 |
+
E[:, :, :, 0] = first_elt
|
| 72 |
+
diag = torch.eye(E.shape[1], dtype=torch.bool).unsqueeze(0).expand(E.shape[0], -1, -1)
|
| 73 |
+
E[diag] = 0
|
| 74 |
+
return E
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def update_config_with_new_keys(cfg, saved_cfg):
|
| 78 |
+
saved_general = saved_cfg.general
|
| 79 |
+
saved_train = saved_cfg.train
|
| 80 |
+
saved_model = saved_cfg.model
|
| 81 |
+
|
| 82 |
+
for key, val in saved_general.items():
|
| 83 |
+
OmegaConf.set_struct(cfg.general, True)
|
| 84 |
+
with open_dict(cfg.general):
|
| 85 |
+
if key not in cfg.general.keys():
|
| 86 |
+
setattr(cfg.general, key, val)
|
| 87 |
+
|
| 88 |
+
OmegaConf.set_struct(cfg.train, True)
|
| 89 |
+
with open_dict(cfg.train):
|
| 90 |
+
for key, val in saved_train.items():
|
| 91 |
+
if key not in cfg.train.keys():
|
| 92 |
+
setattr(cfg.train, key, val)
|
| 93 |
+
|
| 94 |
+
OmegaConf.set_struct(cfg.model, True)
|
| 95 |
+
with open_dict(cfg.model):
|
| 96 |
+
for key, val in saved_model.items():
|
| 97 |
+
if key not in cfg.model.keys():
|
| 98 |
+
setattr(cfg.model, key, val)
|
| 99 |
+
return cfg
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class PlaceHolder:
|
| 103 |
+
def __init__(self, X, E, y):
|
| 104 |
+
self.X = X
|
| 105 |
+
self.E = E
|
| 106 |
+
self.y = y
|
| 107 |
+
|
| 108 |
+
def type_as(self, x: torch.Tensor):
|
| 109 |
+
""" Changes the device and dtype of X, E, y. """
|
| 110 |
+
self.X = self.X.type_as(x)
|
| 111 |
+
self.E = self.E.type_as(x)
|
| 112 |
+
self.y = self.y.type_as(x)
|
| 113 |
+
return self
|
| 114 |
+
|
| 115 |
+
def mask(self, node_mask, collapse=False):
|
| 116 |
+
x_mask = node_mask.unsqueeze(-1) # bs, n, 1
|
| 117 |
+
e_mask1 = x_mask.unsqueeze(2) # bs, n, 1, 1
|
| 118 |
+
e_mask2 = x_mask.unsqueeze(1) # bs, 1, n, 1
|
| 119 |
+
|
| 120 |
+
if collapse:
|
| 121 |
+
self.X = torch.argmax(self.X, dim=-1)
|
| 122 |
+
self.E = torch.argmax(self.E, dim=-1)
|
| 123 |
+
|
| 124 |
+
self.X[node_mask == 0] = - 1
|
| 125 |
+
self.E[(e_mask1 * e_mask2).squeeze(-1) == 0] = - 1
|
| 126 |
+
else:
|
| 127 |
+
self.X = self.X * x_mask
|
| 128 |
+
self.E = self.E * e_mask1 * e_mask2
|
| 129 |
+
assert torch.allclose(self.E, torch.transpose(self.E, 1, 2))
|
| 130 |
+
return self
|
| 131 |
+
|
| 132 |
+
def setup_wandb(cfg):
|
| 133 |
+
config_dict = omegaconf.OmegaConf.to_container(cfg, resolve=True, throw_on_missing=True)
|
| 134 |
+
kwargs = {'name': cfg.general.name, 'project': f'graph_ddm_{cfg.dataset.name}', 'config': config_dict,
|
| 135 |
+
'settings': wandb.Settings(_disable_stats=True), 'reinit': True, 'mode': cfg.general.wandb}
|
| 136 |
+
wandb.init(**kwargs)
|
| 137 |
+
wandb.save('*.txt')
|
distributions.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class DistributionNodes:
|
| 5 |
+
def __init__(self, histogram):
|
| 6 |
+
""" Compute the distribution of the number of nodes in the dataset, and sample from this distribution.
|
| 7 |
+
historgram: dict. The keys are num_nodes, the values are counts
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
if type(histogram) == dict:
|
| 11 |
+
max_n_nodes = max(histogram.keys())
|
| 12 |
+
prob = torch.zeros(max_n_nodes + 1)
|
| 13 |
+
for num_nodes, count in histogram.items():
|
| 14 |
+
prob[num_nodes] = count
|
| 15 |
+
else:
|
| 16 |
+
prob = histogram
|
| 17 |
+
|
| 18 |
+
self.prob = prob / prob.sum()
|
| 19 |
+
self.m = torch.distributions.Categorical(prob)
|
| 20 |
+
|
| 21 |
+
def sample_n(self, n_samples, device):
|
| 22 |
+
idx = self.m.sample((n_samples,))
|
| 23 |
+
return idx.to(device)
|
| 24 |
+
|
| 25 |
+
def log_prob(self, batch_n_nodes):
|
| 26 |
+
assert len(batch_n_nodes.size()) == 1
|
| 27 |
+
p = self.prob.to(batch_n_nodes.device)
|
| 28 |
+
|
| 29 |
+
mask = batch_n_nodes >= p.shape[0]
|
| 30 |
+
batch_n_nodes[mask] = p.shape[0] - 1
|
| 31 |
+
|
| 32 |
+
probas = p[batch_n_nodes]
|
| 33 |
+
|
| 34 |
+
probas[mask] = 0
|
| 35 |
+
log_p = torch.log(probas + 1e-30)
|
| 36 |
+
|
| 37 |
+
return log_p
|
extra_features.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import utils
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class DummyExtraFeatures:
|
| 6 |
+
def __init__(self):
|
| 7 |
+
""" This class does not compute anything, just returns empty tensors."""
|
| 8 |
+
|
| 9 |
+
def __call__(self, noisy_data):
|
| 10 |
+
X = noisy_data['X_t']
|
| 11 |
+
E = noisy_data['E_t']
|
| 12 |
+
y = noisy_data['y_t']
|
| 13 |
+
empty_x = X.new_zeros((*X.shape[:-1], 0))
|
| 14 |
+
empty_e = E.new_zeros((*E.shape[:-1], 0))
|
| 15 |
+
empty_y = y.new_zeros((y.shape[0], 0))
|
| 16 |
+
return utils.PlaceHolder(X=empty_x, E=empty_e, y=empty_y)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class ExtraFeatures:
|
| 20 |
+
def __init__(self, extra_features_type, max_n_nodes):
|
| 21 |
+
self.max_n_nodes = max_n_nodes
|
| 22 |
+
self.ncycles = NodeCycleFeatures()
|
| 23 |
+
self.features_type = extra_features_type
|
| 24 |
+
if extra_features_type in ['eigenvalues', 'all']:
|
| 25 |
+
self.eigenfeatures = EigenFeatures(mode=extra_features_type)
|
| 26 |
+
|
| 27 |
+
def __call__(self, noisy_data):
|
| 28 |
+
n = noisy_data['node_mask'].sum(dim=1).unsqueeze(1) / self.max_n_nodes
|
| 29 |
+
x_cycles, y_cycles = self.ncycles(noisy_data) # (bs, n_cycles)
|
| 30 |
+
|
| 31 |
+
if self.features_type == 'cycles':
|
| 32 |
+
E = noisy_data['E_t']
|
| 33 |
+
extra_edge_attr = torch.zeros((*E.shape[:-1], 0)).type_as(E)
|
| 34 |
+
return utils.PlaceHolder(X=x_cycles, E=extra_edge_attr, y=torch.hstack((n, y_cycles)))
|
| 35 |
+
|
| 36 |
+
elif self.features_type == 'eigenvalues':
|
| 37 |
+
eigenfeatures = self.eigenfeatures(noisy_data)
|
| 38 |
+
E = noisy_data['E_t']
|
| 39 |
+
extra_edge_attr = torch.zeros((*E.shape[:-1], 0)).type_as(E)
|
| 40 |
+
n_components, batched_eigenvalues = eigenfeatures # (bs, 1), (bs, 10)
|
| 41 |
+
return utils.PlaceHolder(X=x_cycles, E=extra_edge_attr, y=torch.hstack((n, y_cycles, n_components,
|
| 42 |
+
batched_eigenvalues)))
|
| 43 |
+
elif self.features_type == 'all':
|
| 44 |
+
eigenfeatures = self.eigenfeatures(noisy_data)
|
| 45 |
+
E = noisy_data['E_t']
|
| 46 |
+
extra_edge_attr = torch.zeros((*E.shape[:-1], 0)).type_as(E)
|
| 47 |
+
n_components, batched_eigenvalues, nonlcc_indicator, k_lowest_eigvec = eigenfeatures # (bs, 1), (bs, 10),
|
| 48 |
+
# (bs, n, 1), (bs, n, 2)
|
| 49 |
+
|
| 50 |
+
return utils.PlaceHolder(X=torch.cat((x_cycles, nonlcc_indicator, k_lowest_eigvec), dim=-1),
|
| 51 |
+
E=extra_edge_attr,
|
| 52 |
+
y=torch.hstack((n, y_cycles, n_components, batched_eigenvalues)))
|
| 53 |
+
else:
|
| 54 |
+
raise ValueError(f"Features type {self.features_type} not implemented")
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
class NodeCycleFeatures:
|
| 58 |
+
def __init__(self):
|
| 59 |
+
self.kcycles = KNodeCycles()
|
| 60 |
+
|
| 61 |
+
def __call__(self, noisy_data):
|
| 62 |
+
adj_matrix = noisy_data['E_t'][..., 1:].sum(dim=-1).float()
|
| 63 |
+
|
| 64 |
+
x_cycles, y_cycles = self.kcycles.k_cycles(adj_matrix=adj_matrix) # (bs, n_cycles)
|
| 65 |
+
x_cycles = x_cycles.type_as(adj_matrix) * noisy_data['node_mask'].unsqueeze(-1)
|
| 66 |
+
# Avoid large values when the graph is dense
|
| 67 |
+
x_cycles = x_cycles / 10
|
| 68 |
+
y_cycles = y_cycles / 10
|
| 69 |
+
x_cycles[x_cycles > 1] = 1
|
| 70 |
+
y_cycles[y_cycles > 1] = 1
|
| 71 |
+
return x_cycles, y_cycles
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
class EigenFeatures:
|
| 75 |
+
"""
|
| 76 |
+
Code taken from : https://github.com/Saro00/DGN/blob/master/models/pytorch/eigen_agg.py
|
| 77 |
+
"""
|
| 78 |
+
def __init__(self, mode):
|
| 79 |
+
""" mode: 'eigenvalues' or 'all' """
|
| 80 |
+
self.mode = mode
|
| 81 |
+
|
| 82 |
+
def __call__(self, noisy_data):
|
| 83 |
+
E_t = noisy_data['E_t']
|
| 84 |
+
mask = noisy_data['node_mask']
|
| 85 |
+
A = E_t[..., 1:].sum(dim=-1).float() * mask.unsqueeze(1) * mask.unsqueeze(2)
|
| 86 |
+
L = compute_laplacian(A, normalize=False)
|
| 87 |
+
mask_diag = 2 * L.shape[-1] * torch.eye(A.shape[-1]).type_as(L).unsqueeze(0)
|
| 88 |
+
mask_diag = mask_diag * (~mask.unsqueeze(1)) * (~mask.unsqueeze(2))
|
| 89 |
+
L = L * mask.unsqueeze(1) * mask.unsqueeze(2) + mask_diag
|
| 90 |
+
|
| 91 |
+
if self.mode == 'eigenvalues':
|
| 92 |
+
eigvals = torch.linalg.eigvalsh(L) # bs, n
|
| 93 |
+
eigvals = eigvals.type_as(A) / torch.sum(mask, dim=1, keepdim=True)
|
| 94 |
+
|
| 95 |
+
n_connected_comp, batch_eigenvalues = get_eigenvalues_features(eigenvalues=eigvals)
|
| 96 |
+
return n_connected_comp.type_as(A), batch_eigenvalues.type_as(A)
|
| 97 |
+
|
| 98 |
+
elif self.mode == 'all':
|
| 99 |
+
eigvals, eigvectors = torch.linalg.eigh(L)
|
| 100 |
+
eigvals = eigvals.type_as(A) / torch.sum(mask, dim=1, keepdim=True)
|
| 101 |
+
eigvectors = eigvectors * mask.unsqueeze(2) * mask.unsqueeze(1)
|
| 102 |
+
# Retrieve eigenvalues features
|
| 103 |
+
n_connected_comp, batch_eigenvalues = get_eigenvalues_features(eigenvalues=eigvals)
|
| 104 |
+
|
| 105 |
+
# Retrieve eigenvectors features
|
| 106 |
+
nonlcc_indicator, k_lowest_eigenvector = get_eigenvectors_features(vectors=eigvectors,
|
| 107 |
+
node_mask=noisy_data['node_mask'],
|
| 108 |
+
n_connected=n_connected_comp)
|
| 109 |
+
return n_connected_comp, batch_eigenvalues, nonlcc_indicator, k_lowest_eigenvector
|
| 110 |
+
else:
|
| 111 |
+
raise NotImplementedError(f"Mode {self.mode} is not implemented")
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def compute_laplacian(adjacency, normalize: bool):
|
| 115 |
+
"""
|
| 116 |
+
adjacency : batched adjacency matrix (bs, n, n)
|
| 117 |
+
normalize: can be None, 'sym' or 'rw' for the combinatorial, symmetric normalized or random walk Laplacians
|
| 118 |
+
Return:
|
| 119 |
+
L (n x n ndarray): combinatorial or symmetric normalized Laplacian.
|
| 120 |
+
"""
|
| 121 |
+
diag = torch.sum(adjacency, dim=-1) # (bs, n)
|
| 122 |
+
n = diag.shape[-1]
|
| 123 |
+
D = torch.diag_embed(diag) # Degree matrix # (bs, n, n)
|
| 124 |
+
combinatorial = D - adjacency # (bs, n, n)
|
| 125 |
+
|
| 126 |
+
if not normalize:
|
| 127 |
+
return (combinatorial + combinatorial.transpose(1, 2)) / 2
|
| 128 |
+
|
| 129 |
+
diag0 = diag.clone()
|
| 130 |
+
diag[diag == 0] = 1e-12
|
| 131 |
+
|
| 132 |
+
diag_norm = 1 / torch.sqrt(diag) # (bs, n)
|
| 133 |
+
D_norm = torch.diag_embed(diag_norm) # (bs, n, n)
|
| 134 |
+
L = torch.eye(n).unsqueeze(0) - D_norm @ adjacency @ D_norm
|
| 135 |
+
L[diag0 == 0] = 0
|
| 136 |
+
return (L + L.transpose(1, 2)) / 2
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def get_eigenvalues_features(eigenvalues, k=5):
|
| 140 |
+
"""
|
| 141 |
+
values : eigenvalues -- (bs, n)
|
| 142 |
+
node_mask: (bs, n)
|
| 143 |
+
k: num of non zero eigenvalues to keep
|
| 144 |
+
"""
|
| 145 |
+
ev = eigenvalues
|
| 146 |
+
bs, n = ev.shape
|
| 147 |
+
n_connected_components = (ev < 1e-5).sum(dim=-1)
|
| 148 |
+
# assert (n_connected_components > 0).all(), (n_connected_components, ev)
|
| 149 |
+
|
| 150 |
+
to_extend = max(n_connected_components) + k - n
|
| 151 |
+
if to_extend > 0:
|
| 152 |
+
eigenvalues = torch.hstack((eigenvalues, 2 * torch.ones(bs, to_extend).type_as(eigenvalues)))
|
| 153 |
+
indices = torch.arange(k).type_as(eigenvalues).long().unsqueeze(0) + n_connected_components.unsqueeze(1)
|
| 154 |
+
first_k_ev = torch.gather(eigenvalues, dim=1, index=indices)
|
| 155 |
+
return n_connected_components.unsqueeze(-1), first_k_ev
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def get_eigenvectors_features(vectors, node_mask, n_connected, k=2):
|
| 159 |
+
"""
|
| 160 |
+
vectors (bs, n, n) : eigenvectors of Laplacian IN COLUMNS
|
| 161 |
+
returns:
|
| 162 |
+
not_lcc_indicator : indicator vectors of largest connected component (lcc) for each graph -- (bs, n, 1)
|
| 163 |
+
k_lowest_eigvec : k first eigenvectors for the largest connected component -- (bs, n, k)
|
| 164 |
+
"""
|
| 165 |
+
bs, n = vectors.size(0), vectors.size(1)
|
| 166 |
+
|
| 167 |
+
# Create an indicator for the nodes outside the largest connected components
|
| 168 |
+
first_ev = torch.round(vectors[:, :, 0], decimals=3) * node_mask # bs, n
|
| 169 |
+
# Add random value to the mask to prevent 0 from becoming the mode
|
| 170 |
+
random = torch.randn(bs, n, device=node_mask.device) * (~node_mask) # bs, n
|
| 171 |
+
first_ev = first_ev + random
|
| 172 |
+
most_common = torch.mode(first_ev, dim=1).values # values: bs -- indices: bs
|
| 173 |
+
mask = ~ (first_ev == most_common.unsqueeze(1))
|
| 174 |
+
not_lcc_indicator = (mask * node_mask).unsqueeze(-1).float()
|
| 175 |
+
|
| 176 |
+
# Get the eigenvectors corresponding to the first nonzero eigenvalues
|
| 177 |
+
to_extend = max(n_connected) + k - n
|
| 178 |
+
if to_extend > 0:
|
| 179 |
+
vectors = torch.cat((vectors, torch.zeros(bs, n, to_extend).type_as(vectors)), dim=2) # bs, n , n + to_extend
|
| 180 |
+
indices = torch.arange(k).type_as(vectors).long().unsqueeze(0).unsqueeze(0) + n_connected.unsqueeze(2) # bs, 1, k
|
| 181 |
+
indices = indices.expand(-1, n, -1) # bs, n, k
|
| 182 |
+
first_k_ev = torch.gather(vectors, dim=2, index=indices) # bs, n, k
|
| 183 |
+
first_k_ev = first_k_ev * node_mask.unsqueeze(2)
|
| 184 |
+
|
| 185 |
+
return not_lcc_indicator, first_k_ev
|
| 186 |
+
|
| 187 |
+
def batch_trace(X):
|
| 188 |
+
"""
|
| 189 |
+
Expect a matrix of shape B N N, returns the trace in shape B
|
| 190 |
+
:param X:
|
| 191 |
+
:return:
|
| 192 |
+
"""
|
| 193 |
+
diag = torch.diagonal(X, dim1=-2, dim2=-1)
|
| 194 |
+
trace = diag.sum(dim=-1)
|
| 195 |
+
return trace
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def batch_diagonal(X):
|
| 199 |
+
"""
|
| 200 |
+
Extracts the diagonal from the last two dims of a tensor
|
| 201 |
+
:param X:
|
| 202 |
+
:return:
|
| 203 |
+
"""
|
| 204 |
+
return torch.diagonal(X, dim1=-2, dim2=-1)
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
class KNodeCycles:
|
| 208 |
+
""" Builds cycle counts for each node in a graph.
|
| 209 |
+
"""
|
| 210 |
+
|
| 211 |
+
def __init__(self):
|
| 212 |
+
super().__init__()
|
| 213 |
+
|
| 214 |
+
def calculate_kpowers(self):
|
| 215 |
+
self.k1_matrix = self.adj_matrix.float()
|
| 216 |
+
self.d = self.adj_matrix.sum(dim=-1)
|
| 217 |
+
self.k2_matrix = self.k1_matrix @ self.adj_matrix.float()
|
| 218 |
+
self.k3_matrix = self.k2_matrix @ self.adj_matrix.float()
|
| 219 |
+
self.k4_matrix = self.k3_matrix @ self.adj_matrix.float()
|
| 220 |
+
self.k5_matrix = self.k4_matrix @ self.adj_matrix.float()
|
| 221 |
+
self.k6_matrix = self.k5_matrix @ self.adj_matrix.float()
|
| 222 |
+
|
| 223 |
+
def k3_cycle(self):
|
| 224 |
+
""" tr(A ** 3). """
|
| 225 |
+
c3 = batch_diagonal(self.k3_matrix)
|
| 226 |
+
return (c3 / 2).unsqueeze(-1).float(), (torch.sum(c3, dim=-1) / 6).unsqueeze(-1).float()
|
| 227 |
+
|
| 228 |
+
def k4_cycle(self):
|
| 229 |
+
diag_a4 = batch_diagonal(self.k4_matrix)
|
| 230 |
+
c4 = diag_a4 - self.d * (self.d - 1) - (self.adj_matrix @ self.d.unsqueeze(-1)).sum(dim=-1)
|
| 231 |
+
return (c4 / 2).unsqueeze(-1).float(), (torch.sum(c4, dim=-1) / 8).unsqueeze(-1).float()
|
| 232 |
+
|
| 233 |
+
def k5_cycle(self):
|
| 234 |
+
diag_a5 = batch_diagonal(self.k5_matrix)
|
| 235 |
+
triangles = batch_diagonal(self.k3_matrix)
|
| 236 |
+
c5 = diag_a5 - 2 * triangles * self.d - (self.adj_matrix @ triangles.unsqueeze(-1)).sum(dim=-1) + triangles
|
| 237 |
+
return (c5 / 2).unsqueeze(-1).float(), (c5.sum(dim=-1) / 10).unsqueeze(-1).float()
|
| 238 |
+
|
| 239 |
+
def k6_cycle(self):
|
| 240 |
+
term_1_t = batch_trace(self.k6_matrix)
|
| 241 |
+
term_2_t = batch_trace(self.k3_matrix ** 2)
|
| 242 |
+
term3_t = torch.sum(self.adj_matrix * self.k2_matrix.pow(2), dim=[-2, -1])
|
| 243 |
+
d_t4 = batch_diagonal(self.k2_matrix)
|
| 244 |
+
a_4_t = batch_diagonal(self.k4_matrix)
|
| 245 |
+
term_4_t = (d_t4 * a_4_t).sum(dim=-1)
|
| 246 |
+
term_5_t = batch_trace(self.k4_matrix)
|
| 247 |
+
term_6_t = batch_trace(self.k3_matrix)
|
| 248 |
+
term_7_t = batch_diagonal(self.k2_matrix).pow(3).sum(-1)
|
| 249 |
+
term8_t = torch.sum(self.k3_matrix, dim=[-2, -1])
|
| 250 |
+
term9_t = batch_diagonal(self.k2_matrix).pow(2).sum(-1)
|
| 251 |
+
term10_t = batch_trace(self.k2_matrix)
|
| 252 |
+
|
| 253 |
+
c6_t = (term_1_t - 3 * term_2_t + 9 * term3_t - 6 * term_4_t + 6 * term_5_t - 4 * term_6_t + 4 * term_7_t +
|
| 254 |
+
3 * term8_t - 12 * term9_t + 4 * term10_t)
|
| 255 |
+
return None, (c6_t / 12).unsqueeze(-1).float()
|
| 256 |
+
|
| 257 |
+
def k_cycles(self, adj_matrix, verbose=False):
|
| 258 |
+
self.adj_matrix = adj_matrix
|
| 259 |
+
self.calculate_kpowers()
|
| 260 |
+
|
| 261 |
+
k3x, k3y = self.k3_cycle()
|
| 262 |
+
assert (k3x >= -0.1).all()
|
| 263 |
+
|
| 264 |
+
k4x, k4y = self.k4_cycle()
|
| 265 |
+
assert (k4x >= -0.1).all()
|
| 266 |
+
|
| 267 |
+
k5x, k5y = self.k5_cycle()
|
| 268 |
+
assert (k5x >= -0.1).all(), k5x
|
| 269 |
+
|
| 270 |
+
_, k6y = self.k6_cycle()
|
| 271 |
+
assert (k6y >= -0.1).all()
|
| 272 |
+
|
| 273 |
+
kcyclesx = torch.cat([k3x, k4x, k5x], dim=-1)
|
| 274 |
+
kcyclesy = torch.cat([k3y, k4y, k5y, k6y], dim=-1)
|
| 275 |
+
return kcyclesx, kcyclesy
|
models/__init__.py
ADDED
|
File without changes
|
models/__pycache__/__init__.cpython-39.pyc
ADDED
|
Binary file (163 Bytes). View file
|
|
|
models/__pycache__/layers.cpython-39.pyc
ADDED
|
Binary file (1.91 kB). View file
|
|
|
models/__pycache__/transformer_model.cpython-39.pyc
ADDED
|
Binary file (7.99 kB). View file
|
|
|
models/layers.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import torch.nn as nn
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class Xtoy(nn.Module):
|
| 6 |
+
def __init__(self, dx, dy):
|
| 7 |
+
""" Map node features to global features """
|
| 8 |
+
super().__init__()
|
| 9 |
+
self.lin = nn.Linear(4 * dx, dy)
|
| 10 |
+
|
| 11 |
+
def forward(self, X):
|
| 12 |
+
""" X: bs, n, dx. """
|
| 13 |
+
m = X.mean(dim=1)
|
| 14 |
+
mi = X.min(dim=1)[0]
|
| 15 |
+
ma = X.max(dim=1)[0]
|
| 16 |
+
std = X.std(dim=1)
|
| 17 |
+
z = torch.hstack((m, mi, ma, std))
|
| 18 |
+
out = self.lin(z)
|
| 19 |
+
return out
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class Etoy(nn.Module):
|
| 23 |
+
def __init__(self, d, dy):
|
| 24 |
+
""" Map edge features to global features. """
|
| 25 |
+
super().__init__()
|
| 26 |
+
self.lin = nn.Linear(4 * d, dy)
|
| 27 |
+
|
| 28 |
+
def forward(self, E):
|
| 29 |
+
""" E: bs, n, n, de
|
| 30 |
+
Features relative to the diagonal of E could potentially be added.
|
| 31 |
+
"""
|
| 32 |
+
m = E.mean(dim=(1, 2))
|
| 33 |
+
mi = E.min(dim=2)[0].min(dim=1)[0]
|
| 34 |
+
ma = E.max(dim=2)[0].max(dim=1)[0]
|
| 35 |
+
std = torch.std(E, dim=(1, 2))
|
| 36 |
+
z = torch.hstack((m, mi, ma, std))
|
| 37 |
+
out = self.lin(z)
|
| 38 |
+
return out
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def masked_softmax(x, mask, **kwargs):
|
| 42 |
+
if mask.sum() == 0:
|
| 43 |
+
return x
|
| 44 |
+
x_masked = x.clone()
|
| 45 |
+
x_masked[mask == 0] = -float("inf")
|
| 46 |
+
return torch.softmax(x_masked, **kwargs)
|
models/transformer_model.py
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
from torch.nn.modules.dropout import Dropout
|
| 6 |
+
from torch.nn.modules.linear import Linear
|
| 7 |
+
from torch.nn.modules.normalization import LayerNorm
|
| 8 |
+
from torch.nn import functional as F
|
| 9 |
+
from torch import Tensor
|
| 10 |
+
|
| 11 |
+
import utils
|
| 12 |
+
from diffusion import diffusion_utils
|
| 13 |
+
from models.layers import Xtoy, Etoy, masked_softmax
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class XEyTransformerLayer(nn.Module):
|
| 17 |
+
""" Transformer that updates node, edge and global features
|
| 18 |
+
d_x: node features
|
| 19 |
+
d_e: edge features
|
| 20 |
+
dz : global features
|
| 21 |
+
n_head: the number of heads in the multi_head_attention
|
| 22 |
+
dim_feedforward: the dimension of the feedforward network model after self-attention
|
| 23 |
+
dropout: dropout probablility. 0 to disable
|
| 24 |
+
layer_norm_eps: eps value in layer normalizations.
|
| 25 |
+
"""
|
| 26 |
+
def __init__(self, dx: int, de: int, dy: int, n_head: int, dim_ffX: int = 2048,
|
| 27 |
+
dim_ffE: int = 128, dim_ffy: int = 2048, dropout: float = 0.1,
|
| 28 |
+
layer_norm_eps: float = 1e-5, device=None, dtype=None) -> None:
|
| 29 |
+
kw = {'device': device, 'dtype': dtype}
|
| 30 |
+
super().__init__()
|
| 31 |
+
|
| 32 |
+
self.self_attn = NodeEdgeBlock(dx, de, dy, n_head, **kw)
|
| 33 |
+
|
| 34 |
+
self.linX1 = Linear(dx, dim_ffX, **kw)
|
| 35 |
+
self.linX2 = Linear(dim_ffX, dx, **kw)
|
| 36 |
+
self.normX1 = LayerNorm(dx, eps=layer_norm_eps, **kw)
|
| 37 |
+
self.normX2 = LayerNorm(dx, eps=layer_norm_eps, **kw)
|
| 38 |
+
self.dropoutX1 = Dropout(dropout)
|
| 39 |
+
self.dropoutX2 = Dropout(dropout)
|
| 40 |
+
self.dropoutX3 = Dropout(dropout)
|
| 41 |
+
|
| 42 |
+
self.linE1 = Linear(de, dim_ffE, **kw)
|
| 43 |
+
self.linE2 = Linear(dim_ffE, de, **kw)
|
| 44 |
+
self.normE1 = LayerNorm(de, eps=layer_norm_eps, **kw)
|
| 45 |
+
self.normE2 = LayerNorm(de, eps=layer_norm_eps, **kw)
|
| 46 |
+
self.dropoutE1 = Dropout(dropout)
|
| 47 |
+
self.dropoutE2 = Dropout(dropout)
|
| 48 |
+
self.dropoutE3 = Dropout(dropout)
|
| 49 |
+
|
| 50 |
+
self.lin_y1 = Linear(dy, dim_ffy, **kw)
|
| 51 |
+
self.lin_y2 = Linear(dim_ffy, dy, **kw)
|
| 52 |
+
self.norm_y1 = LayerNorm(dy, eps=layer_norm_eps, **kw)
|
| 53 |
+
self.norm_y2 = LayerNorm(dy, eps=layer_norm_eps, **kw)
|
| 54 |
+
self.dropout_y1 = Dropout(dropout)
|
| 55 |
+
self.dropout_y2 = Dropout(dropout)
|
| 56 |
+
self.dropout_y3 = Dropout(dropout)
|
| 57 |
+
|
| 58 |
+
self.activation = F.relu
|
| 59 |
+
|
| 60 |
+
def forward(self, X: Tensor, E: Tensor, y, node_mask: Tensor):
|
| 61 |
+
""" Pass the input through the encoder layer.
|
| 62 |
+
X: (bs, n, d)
|
| 63 |
+
E: (bs, n, n, d)
|
| 64 |
+
y: (bs, dy)
|
| 65 |
+
node_mask: (bs, n) Mask for the src keys per batch (optional)
|
| 66 |
+
Output: newX, newE, new_y with the same shape.
|
| 67 |
+
"""
|
| 68 |
+
|
| 69 |
+
newX, newE, new_y = self.self_attn(X, E, y, node_mask=node_mask)
|
| 70 |
+
|
| 71 |
+
newX_d = self.dropoutX1(newX)
|
| 72 |
+
X = self.normX1(X + newX_d)
|
| 73 |
+
|
| 74 |
+
newE_d = self.dropoutE1(newE)
|
| 75 |
+
E = self.normE1(E + newE_d)
|
| 76 |
+
|
| 77 |
+
new_y_d = self.dropout_y1(new_y)
|
| 78 |
+
y = self.norm_y1(y + new_y_d)
|
| 79 |
+
|
| 80 |
+
ff_outputX = self.linX2(self.dropoutX2(self.activation(self.linX1(X))))
|
| 81 |
+
ff_outputX = self.dropoutX3(ff_outputX)
|
| 82 |
+
X = self.normX2(X + ff_outputX)
|
| 83 |
+
|
| 84 |
+
ff_outputE = self.linE2(self.dropoutE2(self.activation(self.linE1(E))))
|
| 85 |
+
ff_outputE = self.dropoutE3(ff_outputE)
|
| 86 |
+
E = self.normE2(E + ff_outputE)
|
| 87 |
+
|
| 88 |
+
ff_output_y = self.lin_y2(self.dropout_y2(self.activation(self.lin_y1(y))))
|
| 89 |
+
ff_output_y = self.dropout_y3(ff_output_y)
|
| 90 |
+
y = self.norm_y2(y + ff_output_y)
|
| 91 |
+
|
| 92 |
+
return X, E, y
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
class NodeEdgeBlock(nn.Module):
|
| 96 |
+
""" Self attention layer that also updates the representations on the edges. """
|
| 97 |
+
def __init__(self, dx, de, dy, n_head, **kwargs):
|
| 98 |
+
super().__init__()
|
| 99 |
+
assert dx % n_head == 0, f"dx: {dx} -- nhead: {n_head}"
|
| 100 |
+
self.dx = dx
|
| 101 |
+
self.de = de
|
| 102 |
+
self.dy = dy
|
| 103 |
+
self.df = int(dx / n_head)
|
| 104 |
+
self.n_head = n_head
|
| 105 |
+
|
| 106 |
+
# Attention
|
| 107 |
+
self.q = Linear(dx, dx)
|
| 108 |
+
self.k = Linear(dx, dx)
|
| 109 |
+
self.v = Linear(dx, dx)
|
| 110 |
+
|
| 111 |
+
# FiLM E to X
|
| 112 |
+
self.e_add = Linear(de, dx)
|
| 113 |
+
self.e_mul = Linear(de, dx)
|
| 114 |
+
|
| 115 |
+
# FiLM y to E
|
| 116 |
+
self.y_e_mul = Linear(dy, dx) # Warning: here it's dx and not de
|
| 117 |
+
self.y_e_add = Linear(dy, dx)
|
| 118 |
+
|
| 119 |
+
# FiLM y to X
|
| 120 |
+
self.y_x_mul = Linear(dy, dx)
|
| 121 |
+
self.y_x_add = Linear(dy, dx)
|
| 122 |
+
|
| 123 |
+
# Process y
|
| 124 |
+
self.y_y = Linear(dy, dy)
|
| 125 |
+
self.x_y = Xtoy(dx, dy)
|
| 126 |
+
self.e_y = Etoy(de, dy)
|
| 127 |
+
|
| 128 |
+
# Output layers
|
| 129 |
+
self.x_out = Linear(dx, dx)
|
| 130 |
+
self.e_out = Linear(dx, de)
|
| 131 |
+
self.y_out = nn.Sequential(nn.Linear(dy, dy), nn.ReLU(), nn.Linear(dy, dy))
|
| 132 |
+
|
| 133 |
+
def forward(self, X, E, y, node_mask):
|
| 134 |
+
"""
|
| 135 |
+
:param X: bs, n, d node features
|
| 136 |
+
:param E: bs, n, n, d edge features
|
| 137 |
+
:param y: bs, dz global features
|
| 138 |
+
:param node_mask: bs, n
|
| 139 |
+
:return: newX, newE, new_y with the same shape.
|
| 140 |
+
"""
|
| 141 |
+
bs, n, _ = X.shape
|
| 142 |
+
x_mask = node_mask.unsqueeze(-1) # bs, n, 1
|
| 143 |
+
e_mask1 = x_mask.unsqueeze(2) # bs, n, 1, 1
|
| 144 |
+
e_mask2 = x_mask.unsqueeze(1) # bs, 1, n, 1
|
| 145 |
+
|
| 146 |
+
# 1. Map X to keys and queries
|
| 147 |
+
Q = self.q(X) * x_mask # (bs, n, dx)
|
| 148 |
+
K = self.k(X) * x_mask # (bs, n, dx)
|
| 149 |
+
diffusion_utils.assert_correctly_masked(Q, x_mask)
|
| 150 |
+
# 2. Reshape to (bs, n, n_head, df) with dx = n_head * df
|
| 151 |
+
|
| 152 |
+
Q = Q.reshape((Q.size(0), Q.size(1), self.n_head, self.df))
|
| 153 |
+
K = K.reshape((K.size(0), K.size(1), self.n_head, self.df))
|
| 154 |
+
|
| 155 |
+
Q = Q.unsqueeze(2) # (bs, 1, n, n_head, df)
|
| 156 |
+
K = K.unsqueeze(1) # (bs, n, 1, n head, df)
|
| 157 |
+
|
| 158 |
+
# Compute unnormalized attentions. Y is (bs, n, n, n_head, df)
|
| 159 |
+
Y = Q * K
|
| 160 |
+
Y = Y / math.sqrt(Y.size(-1))
|
| 161 |
+
diffusion_utils.assert_correctly_masked(Y, (e_mask1 * e_mask2).unsqueeze(-1))
|
| 162 |
+
|
| 163 |
+
E1 = self.e_mul(E) * e_mask1 * e_mask2 # bs, n, n, dx
|
| 164 |
+
E1 = E1.reshape((E.size(0), E.size(1), E.size(2), self.n_head, self.df))
|
| 165 |
+
|
| 166 |
+
E2 = self.e_add(E) * e_mask1 * e_mask2 # bs, n, n, dx
|
| 167 |
+
E2 = E2.reshape((E.size(0), E.size(1), E.size(2), self.n_head, self.df))
|
| 168 |
+
|
| 169 |
+
# Incorporate edge features to the self attention scores.
|
| 170 |
+
Y = Y * (E1 + 1) + E2 # (bs, n, n, n_head, df)
|
| 171 |
+
|
| 172 |
+
# Incorporate y to E
|
| 173 |
+
newE = Y.flatten(start_dim=3) # bs, n, n, dx
|
| 174 |
+
ye1 = self.y_e_add(y).unsqueeze(1).unsqueeze(1) # bs, 1, 1, de
|
| 175 |
+
ye2 = self.y_e_mul(y).unsqueeze(1).unsqueeze(1)
|
| 176 |
+
newE = ye1 + (ye2 + 1) * newE
|
| 177 |
+
|
| 178 |
+
# Output E
|
| 179 |
+
newE = self.e_out(newE) * e_mask1 * e_mask2 # bs, n, n, de
|
| 180 |
+
diffusion_utils.assert_correctly_masked(newE, e_mask1 * e_mask2)
|
| 181 |
+
|
| 182 |
+
# Compute attentions. attn is still (bs, n, n, n_head, df)
|
| 183 |
+
softmax_mask = e_mask2.expand(-1, n, -1, self.n_head) # bs, 1, n, 1
|
| 184 |
+
attn = masked_softmax(Y, softmax_mask, dim=2) # bs, n, n, n_head
|
| 185 |
+
|
| 186 |
+
V = self.v(X) * x_mask # bs, n, dx
|
| 187 |
+
V = V.reshape((V.size(0), V.size(1), self.n_head, self.df))
|
| 188 |
+
V = V.unsqueeze(1) # (bs, 1, n, n_head, df)
|
| 189 |
+
|
| 190 |
+
# Compute weighted values
|
| 191 |
+
weighted_V = attn * V
|
| 192 |
+
weighted_V = weighted_V.sum(dim=2)
|
| 193 |
+
|
| 194 |
+
# Send output to input dim
|
| 195 |
+
weighted_V = weighted_V.flatten(start_dim=2) # bs, n, dx
|
| 196 |
+
|
| 197 |
+
# Incorporate y to X
|
| 198 |
+
yx1 = self.y_x_add(y).unsqueeze(1)
|
| 199 |
+
yx2 = self.y_x_mul(y).unsqueeze(1)
|
| 200 |
+
newX = yx1 + (yx2 + 1) * weighted_V
|
| 201 |
+
|
| 202 |
+
# Output X
|
| 203 |
+
newX = self.x_out(newX) * x_mask
|
| 204 |
+
diffusion_utils.assert_correctly_masked(newX, x_mask)
|
| 205 |
+
|
| 206 |
+
# Process y based on X axnd E
|
| 207 |
+
y = self.y_y(y)
|
| 208 |
+
e_y = self.e_y(E)
|
| 209 |
+
x_y = self.x_y(X)
|
| 210 |
+
new_y = y + x_y + e_y
|
| 211 |
+
new_y = self.y_out(new_y) # bs, dy
|
| 212 |
+
|
| 213 |
+
return newX, newE, new_y
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
class GraphTransformer(nn.Module):
|
| 217 |
+
"""
|
| 218 |
+
n_layers : int -- number of layers
|
| 219 |
+
dims : dict -- contains dimensions for each feature type
|
| 220 |
+
"""
|
| 221 |
+
def __init__(self, n_layers: int, input_dims: dict, cond_dims: int, hidden_mlp_dims: dict, hidden_dims: dict,
|
| 222 |
+
output_dims: dict, act_fn_in: nn.ReLU(), act_fn_out: nn.ReLU()):
|
| 223 |
+
super().__init__()
|
| 224 |
+
self.n_layers = n_layers
|
| 225 |
+
self.out_dim_X = output_dims['X']
|
| 226 |
+
self.out_dim_E = output_dims['E']
|
| 227 |
+
self.out_dim_y = output_dims['y']
|
| 228 |
+
|
| 229 |
+
self.mlp_in_X = nn.Sequential(nn.Linear(input_dims['X'] + cond_dims, hidden_mlp_dims['X']), act_fn_in,
|
| 230 |
+
nn.Linear(hidden_mlp_dims['X'], hidden_dims['dx']), act_fn_in)
|
| 231 |
+
|
| 232 |
+
self.mlp_in_E = nn.Sequential(nn.Linear(input_dims['E'] + cond_dims, hidden_mlp_dims['E']), act_fn_in,
|
| 233 |
+
nn.Linear(hidden_mlp_dims['E'], hidden_dims['de']), act_fn_in)
|
| 234 |
+
|
| 235 |
+
self.mlp_in_y = nn.Sequential(nn.Linear(input_dims['y'], hidden_mlp_dims['y']), act_fn_in,
|
| 236 |
+
nn.Linear(hidden_mlp_dims['y'], hidden_dims['dy']), act_fn_in)
|
| 237 |
+
|
| 238 |
+
self.tf_layers = nn.ModuleList([XEyTransformerLayer(dx=hidden_dims['dx'],
|
| 239 |
+
de=hidden_dims['de'],
|
| 240 |
+
dy=hidden_dims['dy'],
|
| 241 |
+
n_head=hidden_dims['n_head'],
|
| 242 |
+
dim_ffX=hidden_dims['dim_ffX'],
|
| 243 |
+
dim_ffE=hidden_dims['dim_ffE'])
|
| 244 |
+
for i in range(n_layers)])
|
| 245 |
+
|
| 246 |
+
self.mlp_out_X = nn.Sequential(nn.Linear(hidden_dims['dx'], hidden_mlp_dims['X']), act_fn_out,
|
| 247 |
+
nn.Linear(hidden_mlp_dims['X'], output_dims['X']))
|
| 248 |
+
|
| 249 |
+
self.mlp_out_E = nn.Sequential(nn.Linear(hidden_dims['de'], hidden_mlp_dims['E']), act_fn_out,
|
| 250 |
+
nn.Linear(hidden_mlp_dims['E'], output_dims['E']))
|
| 251 |
+
|
| 252 |
+
self.mlp_out_y = nn.Sequential(nn.Linear(hidden_dims['dy'], hidden_mlp_dims['y']), act_fn_out,
|
| 253 |
+
nn.Linear(hidden_mlp_dims['y'], output_dims['y']))
|
| 254 |
+
|
| 255 |
+
def forward(self, X, E, y, node_mask):
|
| 256 |
+
bs, n = X.shape[0], X.shape[1]
|
| 257 |
+
|
| 258 |
+
diag_mask = torch.eye(n)
|
| 259 |
+
diag_mask = ~diag_mask.type_as(E).bool()
|
| 260 |
+
diag_mask = diag_mask.unsqueeze(0).unsqueeze(-1).expand(bs, -1, -1, -1)
|
| 261 |
+
|
| 262 |
+
X_to_out = X[..., :self.out_dim_X]
|
| 263 |
+
E_to_out = E[..., :self.out_dim_E]
|
| 264 |
+
y_to_out = y[..., :self.out_dim_y]
|
| 265 |
+
|
| 266 |
+
new_E = self.mlp_in_E(E)
|
| 267 |
+
new_E = (new_E + new_E.transpose(1, 2)) / 2
|
| 268 |
+
|
| 269 |
+
after_in = utils.PlaceHolder(X=self.mlp_in_X(X), E=new_E, y=self.mlp_in_y(y)).mask(node_mask)
|
| 270 |
+
X, E, y = after_in.X, after_in.E, after_in.y
|
| 271 |
+
|
| 272 |
+
for layer in self.tf_layers:
|
| 273 |
+
X, E, y = layer(X, E, y, node_mask)
|
| 274 |
+
|
| 275 |
+
X = self.mlp_out_X(X)
|
| 276 |
+
E = self.mlp_out_E(E)
|
| 277 |
+
y = self.mlp_out_y(y)
|
| 278 |
+
|
| 279 |
+
X = (X + X_to_out)
|
| 280 |
+
E = (E + E_to_out) * diag_mask
|
| 281 |
+
y = y + y_to_out
|
| 282 |
+
|
| 283 |
+
E = 1/2 * (E + torch.transpose(E, 1, 2))
|
| 284 |
+
|
| 285 |
+
return utils.PlaceHolder(X=X, E=E, y=y).mask(node_mask)
|
requirements.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
networkx==2.8.7
|
| 2 |
+
numpy==1.23
|
| 3 |
+
omegaconf==2.3.0
|
| 4 |
+
pytorch_lightning==2.0.4
|
| 5 |
+
torch_geometric==2.3.1
|
| 6 |
+
torchmetrics==0.11.4
|
| 7 |
+
tqdm==4.65.0
|
| 8 |
+
torch==2.3.0
|
| 9 |
+
torchvision==0.18.0
|
| 10 |
+
torchaudio==2.3.0
|
| 11 |
+
gradio==4.32.0
|
| 12 |
+
wandb==0.15.4
|
| 13 |
+
sentence-transformers==2.6.1
|
| 14 |
+
PyGSP==0.5.1
|
| 15 |
+
pyemd==1.0.0
|
utils.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch_geometric.utils
|
| 3 |
+
from omegaconf import OmegaConf, open_dict
|
| 4 |
+
from torch_geometric.utils import to_dense_adj, to_dense_batch
|
| 5 |
+
import torch
|
| 6 |
+
import omegaconf
|
| 7 |
+
import wandb
|
| 8 |
+
|
| 9 |
+
def create_folders(args):
|
| 10 |
+
try:
|
| 11 |
+
# os.makedirs('checkpoints')
|
| 12 |
+
os.makedirs('graphs')
|
| 13 |
+
os.makedirs('chains')
|
| 14 |
+
except OSError:
|
| 15 |
+
pass
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
# os.makedirs('checkpoints/' + args.general.name)
|
| 19 |
+
os.makedirs('graphs/' + args.general.name)
|
| 20 |
+
os.makedirs('chains/' + args.general.name)
|
| 21 |
+
except OSError:
|
| 22 |
+
pass
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def normalize(X, E, y, norm_values, norm_biases, node_mask):
|
| 26 |
+
X = (X - norm_biases[0]) / norm_values[0]
|
| 27 |
+
E = (E - norm_biases[1]) / norm_values[1]
|
| 28 |
+
y = (y - norm_biases[2]) / norm_values[2]
|
| 29 |
+
|
| 30 |
+
diag = torch.eye(E.shape[1], dtype=torch.bool).unsqueeze(0).expand(E.shape[0], -1, -1)
|
| 31 |
+
E[diag] = 0
|
| 32 |
+
|
| 33 |
+
return PlaceHolder(X=X, E=E, y=y).mask(node_mask)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def unnormalize(X, E, y, norm_values, norm_biases, node_mask, collapse=False):
|
| 37 |
+
"""
|
| 38 |
+
X : node features
|
| 39 |
+
E : edge features
|
| 40 |
+
y : global features`
|
| 41 |
+
norm_values : [norm value X, norm value E, norm value y]
|
| 42 |
+
norm_biases : same order
|
| 43 |
+
node_mask
|
| 44 |
+
"""
|
| 45 |
+
X = (X * norm_values[0] + norm_biases[0])
|
| 46 |
+
E = (E * norm_values[1] + norm_biases[1])
|
| 47 |
+
y = y * norm_values[2] + norm_biases[2]
|
| 48 |
+
|
| 49 |
+
return PlaceHolder(X=X, E=E, y=y).mask(node_mask, collapse)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def to_dense(x, edge_index, edge_attr, batch):
|
| 53 |
+
X, node_mask = to_dense_batch(x=x, batch=batch)
|
| 54 |
+
# node_mask = node_mask.float()
|
| 55 |
+
edge_index, edge_attr = torch_geometric.utils.remove_self_loops(edge_index, edge_attr)
|
| 56 |
+
# TODO: carefully check if setting node_mask as a bool breaks the continuous case
|
| 57 |
+
max_num_nodes = X.size(1)
|
| 58 |
+
E = to_dense_adj(edge_index=edge_index, batch=batch, edge_attr=edge_attr, max_num_nodes=max_num_nodes)
|
| 59 |
+
E = encode_no_edge(E)
|
| 60 |
+
|
| 61 |
+
return PlaceHolder(X=X, E=E, y=None), node_mask
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def encode_no_edge(E):
|
| 65 |
+
assert len(E.shape) == 4
|
| 66 |
+
if E.shape[-1] == 0:
|
| 67 |
+
return E
|
| 68 |
+
no_edge = torch.sum(E, dim=3) == 0
|
| 69 |
+
first_elt = E[:, :, :, 0]
|
| 70 |
+
first_elt[no_edge] = 1
|
| 71 |
+
E[:, :, :, 0] = first_elt
|
| 72 |
+
diag = torch.eye(E.shape[1], dtype=torch.bool).unsqueeze(0).expand(E.shape[0], -1, -1)
|
| 73 |
+
E[diag] = 0
|
| 74 |
+
return E
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def update_config_with_new_keys(cfg, saved_cfg):
|
| 78 |
+
saved_general = saved_cfg.general
|
| 79 |
+
saved_train = saved_cfg.train
|
| 80 |
+
saved_model = saved_cfg.model
|
| 81 |
+
|
| 82 |
+
for key, val in saved_general.items():
|
| 83 |
+
OmegaConf.set_struct(cfg.general, True)
|
| 84 |
+
with open_dict(cfg.general):
|
| 85 |
+
if key not in cfg.general.keys():
|
| 86 |
+
setattr(cfg.general, key, val)
|
| 87 |
+
|
| 88 |
+
OmegaConf.set_struct(cfg.train, True)
|
| 89 |
+
with open_dict(cfg.train):
|
| 90 |
+
for key, val in saved_train.items():
|
| 91 |
+
if key not in cfg.train.keys():
|
| 92 |
+
setattr(cfg.train, key, val)
|
| 93 |
+
|
| 94 |
+
OmegaConf.set_struct(cfg.model, True)
|
| 95 |
+
with open_dict(cfg.model):
|
| 96 |
+
for key, val in saved_model.items():
|
| 97 |
+
if key not in cfg.model.keys():
|
| 98 |
+
setattr(cfg.model, key, val)
|
| 99 |
+
return cfg
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class PlaceHolder:
|
| 103 |
+
def __init__(self, X, E, y):
|
| 104 |
+
self.X = X
|
| 105 |
+
self.E = E
|
| 106 |
+
self.y = y
|
| 107 |
+
|
| 108 |
+
def type_as(self, x: torch.Tensor):
|
| 109 |
+
""" Changes the device and dtype of X, E, y. """
|
| 110 |
+
self.X = self.X.type_as(x)
|
| 111 |
+
self.E = self.E.type_as(x)
|
| 112 |
+
self.y = self.y.type_as(x)
|
| 113 |
+
return self
|
| 114 |
+
|
| 115 |
+
def mask(self, node_mask, collapse=False):
|
| 116 |
+
x_mask = node_mask.unsqueeze(-1) # bs, n, 1
|
| 117 |
+
e_mask1 = x_mask.unsqueeze(2) # bs, n, 1, 1
|
| 118 |
+
e_mask2 = x_mask.unsqueeze(1) # bs, 1, n, 1
|
| 119 |
+
|
| 120 |
+
if collapse:
|
| 121 |
+
self.X = torch.argmax(self.X, dim=-1)
|
| 122 |
+
self.E = torch.argmax(self.E, dim=-1)
|
| 123 |
+
|
| 124 |
+
self.X[node_mask == 0] = - 1
|
| 125 |
+
self.E[(e_mask1 * e_mask2).squeeze(-1) == 0] = - 1
|
| 126 |
+
else:
|
| 127 |
+
self.X = self.X * x_mask
|
| 128 |
+
self.E = self.E * e_mask1 * e_mask2
|
| 129 |
+
assert torch.allclose(self.E, torch.transpose(self.E, 1, 2))
|
| 130 |
+
return self
|
| 131 |
+
|
| 132 |
+
def setup_wandb(cfg):
|
| 133 |
+
config_dict = omegaconf.OmegaConf.to_container(cfg, resolve=True, throw_on_missing=True)
|
| 134 |
+
kwargs = {'name': cfg.general.name, 'project': f'graph_ddm_{cfg.dataset.name}', 'config': config_dict,
|
| 135 |
+
'settings': wandb.Settings(_disable_stats=True), 'reinit': True, 'mode': cfg.general.wandb}
|
| 136 |
+
wandb.init(**kwargs)
|
| 137 |
+
wandb.save('*.txt')
|