Skip to content

Commit

Permalink
add docstrings and cleanup function
Browse files Browse the repository at this point in the history
  • Loading branch information
nwlandry committed Nov 6, 2024
1 parent 9a357b6 commit 1e2dcd4
Showing 1 changed file with 115 additions and 60 deletions.
175 changes: 115 additions & 60 deletions xgi/utils/tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,99 +84,116 @@ def banerjee_coeff(size, max_size):
)


def get_gen_coef_subset_expansion(edge_values, node_value, r):
k = len(edge_values)
subset_vector = [0]
subset_lengths = [0]
for i in range(k):
for t in range(len(subset_vector)):
subset_vector.append(subset_vector[t] + edge_values[i])
subset_lengths.append(subset_lengths[t] + 1)
for i in range(len(subset_lengths)):
subset_lengths[i] = (-1) ** (k - subset_lengths[i])
# subset_lengths[i] = -1 if (k - subset_lengths[i]) % 2 == 1 else 1
total = sum(
[
(node_value + subset_vector[i]) ** r * subset_lengths[i]
for i in range(len(subset_lengths))
]
)
return total / factorial(r)

def ttsv1(nodedict, edgedict, r, a):
"""Computes the tensor times same vector in all modes but 1.
def get_gen_coef_fft(edge_without_node, a, node, l, r):
coefs = np.array([(a[node] ** i) / factorial(i) for i in range(r)])
for u in edge_without_node:
_coefs = np.array([a[u] ** i / factorial(i) for i in range(r - l + 2)])
_coefs[0] = 0
coefs = convolve(coefs, _coefs)[0:r]
gen_fun_coef = coefs[-1]
return gen_fun_coef
This method uses generating functions as described in the corresponding reference.
Parameters
----------
nodedict : dict
A dictionary with nodes as keys and hyperedges they appear in
as values.
edgedict : dict
A dictionary with edges as keys and nodes which are members as
values.
r : int
maximum hyperedge size
a : NumPy array
the vector to multiply the tensor by.
def get_gen_coef_fft_fast_array(edge_without_node, a, node, l, r):
coefs = [1]
for i in range(1, r):
coefs.append(coefs[-1] * a[node] / i)
coefs = np.array(coefs)
for u in edge_without_node:
_coefs = [1]
for i in range(1, r - l + 2):
_coefs.append(_coefs[-1] * a[u] / i)
_coefs = np.array(_coefs)
_coefs[0] = 0
coefs = convolve(coefs, _coefs)[0:r]
gen_fun_coef = coefs[-1]
return gen_fun_coef
Returns
-------
NumPy array
The tensor multiplied by the vector in all modes but 1.
See Also
--------
ttsv2
def ttsv1(E, H, r, a):
n = len(E)
References
----------
Scalable Tensor Methods for Nonuniform Hypergraphs,
Sinan Aksoy, Ilya Amburg, Stephen Young,
https://doi.org/10.1137/23M1584472
"""
n = len(nodedict)
s = np.zeros(n)
r_minus_1_factorial = factorial(r - 1)
for node, edges in E.items():
for node, edges in nodedict.items():
c = 0
for e in edges:
l = len(H[e])
l = len(edgedict[e])
alpha = banerjee_coeff(l, r)
edge_without_node = [v for v in H[e] if v != node]
edge_without_node = [v for v in edgedict[e] if v != node]
if l == r:
gen_fun_coef = prod(a[edge_without_node])
elif 2 ** (l - 1) < r * (l - 1):
gen_fun_coef = get_gen_coef_subset_expansion(
gen_fun_coef = _get_gen_coef_subset_expansion(
a[edge_without_node], a[node], r - 1
)
else:
gen_fun_coef = get_gen_coef_fft_fast_array(
gen_fun_coef = _get_gen_coef_fft_fast_array(
edge_without_node, a, node, l, r
)
c += r_minus_1_factorial * l * gen_fun_coef / alpha
s[node] = c
return s


def ttsv2(E, H, r, a, n):
def ttsv2(pairdict, edgedict, r, a, n):
"""Computes the tensor times same vector in all modes but 2.
Parameters
----------
pairdict : dict
A dictionary with node pairs as keys and hyperedges they appear in
as values.
edgedict : dict
A dictionary with edges as keys and nodes which are members as
values.
r : int
maximum hyperedge size
a : NumPy array
the vector to multiply the tensor by.
n : int
Number of nodes
Returns
-------
Scipy sparse array
A 2D array, which is the result of the tensor
multiplied by the vector in all modes but 2.
See Also
--------
ttsv1
References
----------
Scalable Tensor Methods for Nonuniform Hypergraphs,
Sinan Aksoy, Ilya Amburg, Stephen Young,
https://doi.org/10.1137/23M1584472
"""
s = {}
r_minus_2_factorial = factorial(r - 2)
for nodes, edges in E.items():
v1 = nodes[0]
v2 = nodes[1]
for (v1, v2), edges in pairdict.items():
c = 0
for e in edges:
l = len(H[e])
l = len(edgedict[e])
alpha = banerjee_coeff(l, r)
edge_without_node = [v for v in H[e] if v != v1 and v != v2]
edge_without_node = [v for v in edgedict[e] if v != v1 and v != v2]
if v1 != v2:
if 2 ** (l - 2) < (r - 2) * (l - 2):
gen_fun_coef = get_gen_coef_subset_expansion(
gen_fun_coef = _get_gen_coef_subset_expansion(
a[edge_without_node], a[v1] + a[v2], r - 2
)
else:
coefs = [1]
for i in range(1, r - 1):
coefs.append(coefs[-1] * (a[v1] + a[v2]) / i)
coefs = np.array(coefs)
for u in H[e]:
for u in edgedict[e]:
if u != v1 and u != v2:
_coefs = [1]
for i in range(1, r - l + 2):
Expand All @@ -187,15 +204,15 @@ def ttsv2(E, H, r, a, n):
gen_fun_coef = coefs[-1]
else:
if 2 ** (l - 1) < (r - 2) * (l - 1):
gen_fun_coef = get_gen_coef_subset_expansion(
gen_fun_coef = _get_gen_coef_subset_expansion(
a[edge_without_node], a[v1], r - 2
)
else:
coefs = [1]
for i in range(1, r - 1):
coefs.append(coefs[-1] * (a[v1]) / i)
coefs = np.array(coefs)
for u in H[e]:
for u in edgedict[e]:
if u != v1 and u != v2:
_coefs = [1]
for i in range(1, r - l + 1):
Expand All @@ -205,9 +222,9 @@ def ttsv2(E, H, r, a, n):
coefs = convolve(coefs, _coefs)[0 : r - 1]
gen_fun_coef = coefs[-1]
c += r_minus_2_factorial * l * gen_fun_coef / alpha
s[nodes] = c
s[(v1, v2)] = c
if v1 == v2:
s[nodes] /= 2
s[(v1, v2)] /= 2
first = np.zeros(len(s))
second = np.zeros(len(s))
value = np.zeros(len(s))
Expand All @@ -217,3 +234,41 @@ def ttsv2(E, H, r, a, n):
value[i] = s[k]
Y = coo_array((value, (first, second)), (n, n))
return Y + Y.T


## Helper functions for the tensor methods.

def _get_gen_coef_subset_expansion(edge_values, node_value, r):
k = len(edge_values)
subset_vector = [0]
subset_lengths = [0]
for i in range(k):
for t in range(len(subset_vector)):
subset_vector.append(subset_vector[t] + edge_values[i])
subset_lengths.append(subset_lengths[t] + 1)
for i in range(len(subset_lengths)):
subset_lengths[i] = (-1) ** (k - subset_lengths[i])
# subset_lengths[i] = -1 if (k - subset_lengths[i]) % 2 == 1 else 1
total = sum(
[
(node_value + subset_vector[i]) ** r * subset_lengths[i]
for i in range(len(subset_lengths))
]
)
return total / factorial(r)


def _get_gen_coef_fft_fast_array(edge_without_node, a, node, l, r):
coefs = [1]
for i in range(1, r):
coefs.append(coefs[-1] * a[node] / i)
coefs = np.array(coefs)
for u in edge_without_node:
_coefs = [1]
for i in range(1, r - l + 2):
_coefs.append(_coefs[-1] * a[u] / i)
_coefs = np.array(_coefs)
_coefs[0] = 0
coefs = convolve(coefs, _coefs)[0:r]
gen_fun_coef = coefs[-1]
return gen_fun_coef

0 comments on commit 1e2dcd4

Please sign in to comment.