Skip to content

Commit

Permalink
Fix random hypergraph (#597)
Browse files Browse the repository at this point in the history
* Add ability to generate ER hypergraphs without multiedges

* update

* Remove bad characters

* Fix #361

* Revert "Fix #361"

This reverts commit 28cbbf3.

* Fix #361

* Update test.yml

* fix non-multi-edge probability

* formatting

* Update random.py

* Update xgi/generators/uniform.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update using-xgi.rst

* Response to review

* Update uniform.py

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/uniform.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/uniform.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/uniform.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/uniform.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/uniform.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/uniform.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* updates

* Conditional API note (#595)

* Conditional API note

* Update api_reference.rst

* Remove bad characters

* Update random.py

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* response to review

* updates

* Update random.py

* format

* Update random.py

* update docs

* add unit tests

* Fix test

* test different version

* fix test

* updates

* last additions

* update

* fix error

* unnecessary import

* add unit tests

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

* Update xgi/generators/random.py

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>

---------

Co-authored-by: Maxime Lucas <maximelucas@users.noreply.github.com>
  • Loading branch information
nwlandry and maximelucas authored Oct 16, 2024
1 parent f2e2241 commit cce09e3
Show file tree
Hide file tree
Showing 16 changed files with 335 additions and 155 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
python-version: '3.13'
- name: Install packages
run: |
pip install --upgrade pip
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish_xgi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
python-version: '3.13'

- name: Install dependencies
run: |
Expand Down
1 change: 1 addition & 0 deletions docs/source/api/generators/xgi.generators.random.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ xgi.generators.random

.. autofunction:: chung_lu_hypergraph
.. autofunction:: dcsbm_hypergraph
.. autofunction:: fast_random_hypergraph
.. autofunction:: random_hypergraph
.. autofunction:: watts_strogatz_hypergraph
4 changes: 2 additions & 2 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[pytest]
# always run doctests
addopts = --doctest-modules
addopts = --doctest-modules --ignore=docs
# custom markers
markers =
webtest: mark test as an online test.
slow: mark test as slow.
slow: mark test as slow.
13 changes: 12 additions & 1 deletion tests/algorithms/test_simpliciality.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,18 @@ def test_edit_simpliciality(
mf = 3
assert np.allclose(es, (s - mf) / (m + s - mf))

H = xgi.Hypergraph([[1, 2, 3, 4], [3, 4, 5, 6], [2, 3, 6, 7], [1, 2], [3, 4], [2, 3], [3, 6], [3, 4]])
H = xgi.Hypergraph(
[
[1, 2, 3, 4],
[3, 4, 5, 6],
[2, 3, 6, 7],
[1, 2],
[3, 4],
[2, 3],
[3, 6],
[3, 4],
]
)
es = xgi.edit_simpliciality(H, exclude_min_size=False)
assert np.allclose(es, 0.1785714285714286)

Expand Down
1 change: 1 addition & 0 deletions tests/drawing/test_draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,7 @@ def test_draw_undirected_dyads(edgelist8):
ax, dyad_collection = xgi.draw_undirected_dyads(H, dyad_lw=-1, ax=ax)

fig, ax = plt.subplots()
np.random.seed(0)
ax, dyad_collection = xgi.draw_undirected_dyads(
H, dyad_color=np.random.random(H.num_edges), ax=ax
)
Expand Down
67 changes: 0 additions & 67 deletions tests/generators/test_nonuniform.py

This file was deleted.

131 changes: 131 additions & 0 deletions tests/generators/test_random.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import random

import numpy as np
import pytest
from scipy.special import comb

import xgi


def test_chung_lu_hypergraph():
k1 = {1: 1, 2: 2, 3: 3, 4: 4}
k2 = {1: 2, 2: 2, 3: 3, 4: 3}
H = xgi.chung_lu_hypergraph(k1, k2)
assert H.num_nodes == 4

# seed
H1 = xgi.chung_lu_hypergraph(k1, k2, seed=1)
H2 = xgi.chung_lu_hypergraph(k1, k2, seed=2)
H3 = xgi.chung_lu_hypergraph(k1, k2, seed=2)
assert H1._edge != H2._edge
assert H2._edge == H3._edge

with pytest.warns(Warning):
_ = xgi.chung_lu_hypergraph({1: 1, 2: 2}, {1: 2, 2: 2})


def test_dcsbm_hypergraph():
n = 50
k1 = {i: random.randint(1, n) for i in range(n)}
k2 = {i: sorted(k1.values())[i] for i in range(n)}
g1 = {i: random.choice([0, 1]) for i in range(n)}
g2 = {i: random.choice([0, 1]) for i in range(n)}
omega = np.array([[n // 2, 10], [10, n // 2]])

H = xgi.dcsbm_hypergraph(k1, k2, g1, g2, omega)

assert H.num_nodes == 50

# seed
H1 = xgi.dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=1)
H2 = xgi.dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=2)
H3 = xgi.dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=2)
assert H1._edge != H2._edge
assert H2._edge == H3._edge


def test_random_hypergraph():
# seed
H1 = xgi.random_hypergraph(10, [0.1, 0.01], seed=1)
H2 = xgi.random_hypergraph(10, [0.1, 0.01], seed=2)
H3 = xgi.random_hypergraph(10, [0.1, 0.01], seed=2)

assert H1._edge != H2._edge
assert H2._edge == H3._edge

assert H1.num_nodes == 10
assert xgi.unique_edge_sizes(H1) == [2, 3]

# wrong inputs
# p > 1
with pytest.raises(ValueError):
H1 = xgi.random_hypergraph(10, [1, 1.1])
# p < 0
with pytest.raises(ValueError):
H1 = xgi.random_hypergraph(10, [1, -2])
# p list and order number
with pytest.raises(ValueError):
H1 = xgi.random_hypergraph(10, [0.1, 0.1], order=3)
# different lengths
with pytest.raises(ValueError):
H1 = xgi.random_hypergraph(10, [0.1, 0.1], order=[3])

# uniform
H4 = xgi.random_hypergraph(10, 0.1, order=2, seed=1)
assert H4.num_nodes == 10
assert xgi.unique_edge_sizes(H4) == [3]

H5 = xgi.random_hypergraph(10, [0.1, 0.1], order=[1, 3], seed=1)
assert H5.num_nodes == 10
assert xgi.unique_edge_sizes(H5) == [2, 4]


def test_fast_random_hypergraph():
# seed
H1 = xgi.fast_random_hypergraph(10, [0.1, 0.01], seed=1)
H2 = xgi.fast_random_hypergraph(10, [0.1, 0.01], seed=2)
H3 = xgi.fast_random_hypergraph(10, [0.1, 0.01], seed=2)

assert H1._edge != H2._edge
assert H2._edge == H3._edge

assert H1.num_nodes == 10
assert xgi.unique_edge_sizes(H1) == [2, 3]

# wrong inputs
# p > 1
with pytest.raises(ValueError):
H1 = xgi.fast_random_hypergraph(10, [1, 1.1])
# p < 0
with pytest.raises(ValueError):
H1 = xgi.fast_random_hypergraph(10, [1, -2])
# p list and order number
with pytest.raises(ValueError):
H1 = xgi.fast_random_hypergraph(10, [0.1, 0.1], order=3)
# different lengths
with pytest.raises(ValueError):
H1 = xgi.fast_random_hypergraph(10, [0.1, 0.1], order=[3])

# uniform
H4 = xgi.fast_random_hypergraph(10, 0.1, order=2, seed=1)
assert H4.num_nodes == 10
assert xgi.unique_edge_sizes(H4) == [3]

H5 = xgi.fast_random_hypergraph(10, [0.1, 0.1], order=[1, 3], seed=1)
assert H5.num_nodes == 10
assert xgi.unique_edge_sizes(H5) == [2, 4]

H5 = xgi.fast_random_hypergraph(10, [1, 1])
assert H5.num_edges == comb(10, 2) + comb(10, 3)

with pytest.raises(ValueError):
xgi.fast_random_hypergraph(10, 0.1)

with pytest.raises(ValueError):
xgi.fast_random_hypergraph(10, 0.1, order=[1, 2])

with pytest.raises(ValueError):
xgi.fast_random_hypergraph(10, [1.1, 1])

with pytest.raises(ValueError):
xgi.fast_random_hypergraph(10, [-0.1, 1])
50 changes: 21 additions & 29 deletions tutorials/in_depth/In Depth 4 - Drawing multilayer-style.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion xgi/algorithms/connected.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def largest_connected_hypergraph(H, in_place=False):
>>> H = xgi.random_hypergraph(10, [0.1, 0.01], seed=1)
>>> H_gcc = xgi.largest_connected_hypergraph(H)
>>> print(H_gcc.num_nodes)
8
6
"""
connected_nodes = max(connected_components(H), key=len)
Expand Down
12 changes: 6 additions & 6 deletions xgi/algorithms/simpliciality.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


def edit_simpliciality(H, min_size=2, exclude_min_size=True):
"""Computes the edit simpliciality.
r"""Computes the edit simpliciality.
The fraction of sub-edges contained when compared to a simplicial complex.
Expand Down Expand Up @@ -78,7 +78,7 @@ def edit_simpliciality(H, min_size=2, exclude_min_size=True):


def simplicial_edit_distance(H, min_size=2, exclude_min_size=True, normalize=True):
"""Computes the simplicial edit distance.
r"""Computes the simplicial edit distance.
The number (or fraction) of sub-edges needed to be added
to a hypergraph to make it a simplicial complex.
Expand Down Expand Up @@ -150,7 +150,7 @@ def simplicial_edit_distance(H, min_size=2, exclude_min_size=True, normalize=Tru
)
if not maxH.edges:
return np.nan

id_to_num = dict(zip(maxH.edges, range(maxH.num_edges)))

ms = 0
Expand Down Expand Up @@ -184,7 +184,7 @@ def simplicial_edit_distance(H, min_size=2, exclude_min_size=True, normalize=Tru


def face_edit_simpliciality(H, min_size=2, exclude_min_size=True):
"""Computes the face edit simpliciality.
r"""Computes the face edit simpliciality.
The average fraction of sub-edges contained in a hyperedge
relative to a simplex.
Expand Down Expand Up @@ -247,7 +247,7 @@ def face_edit_simpliciality(H, min_size=2, exclude_min_size=True):


def mean_face_edit_distance(H, min_size=2, exclude_min_size=True, normalize=True):
"""Computes the mean face edit distance
r"""Computes the mean face edit distance
The average number (or fraction) of sub-edges needed to be added to make
a hyperedge a simplex.
Expand Down Expand Up @@ -324,7 +324,7 @@ def mean_face_edit_distance(H, min_size=2, exclude_min_size=True, normalize=True


def simplicial_fraction(H, min_size=2, exclude_min_size=True):
"""Computing the simplicial fraction for a hypergraph.
r"""Computing the simplicial fraction for a hypergraph.
What fraction of the hyperedges are simplices?
Expand Down
2 changes: 1 addition & 1 deletion xgi/core/dihypergraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ def add_edges_from(self, ebunch_to_add, **attr):
i.e. you cannot mix different formats. The iterables containing edge
members cannot be strings.
attr : \*\*kwargs, optional
**attr : kwargs, optional
Additional attributes to be assigned to all edges. Attribues specified via
`ebunch_to_add` take precedence over `attr`.
Expand Down
2 changes: 1 addition & 1 deletion xgi/core/hypergraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ def add_edges_from(self, ebunch_to_add, **attr):
the same length, i.e. you cannot mix different formats. The iterables
containing edge members cannot be strings.
attr : \*\*kwargs:, optional
**attr : kwargs, optional
Additional attributes to be assigned to all edges. Attribues specified via
`ebunch_to_add` take precedence over `attr`.
Expand Down
2 changes: 1 addition & 1 deletion xgi/core/simplicialcomplex.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ def add_simplices_from(self, ebunch_to_add, max_order=None, **attr):
Maximal dimension of simplices to add. If None (default), adds all
simplices. If int, and `ebunch_to_add` contains simplices of order >
`max_order`, creates and adds all its subfaces up to `max_order`.
attr : \*\*kwargs, optional
**attr : kwargs, optional
Additional attributes to be assigned to all simplices. Attribues specified
via `ebunch_to_add` take precedence over `attr`.
Expand Down
Loading

0 comments on commit cce09e3

Please sign in to comment.