From 96722c7f331acaeab292d714a9d999493d843b5d Mon Sep 17 00:00:00 2001 From: Nicholas Landry Date: Mon, 11 Mar 2024 13:35:14 -0400 Subject: [PATCH] Reorganizing stat tests (#525) * initial rearranging of stat tests * update tests --- tests/stats/test_core_stats_functions.py | 956 +++++++++++++++++++++++ tests/stats/test_diedgestats.py | 127 +-- tests/stats/test_dinodestats.py | 214 +---- tests/stats/test_edgestats.py | 149 +--- tests/stats/test_nodestats.py | 573 +------------- xgi/stats/edgestats.py | 3 +- 6 files changed, 1004 insertions(+), 1018 deletions(-) create mode 100644 tests/stats/test_core_stats_functions.py diff --git a/tests/stats/test_core_stats_functions.py b/tests/stats/test_core_stats_functions.py new file mode 100644 index 000000000..e007c8a6e --- /dev/null +++ b/tests/stats/test_core_stats_functions.py @@ -0,0 +1,956 @@ +# This module tests the following: + +# Numerical node and edge statistics: The degree and edge size +# are the stats on which to test all of the stat functionality. +# Tests include +# * Functions for casting to different types (tohist, tonumpy, etc.) +# * Statistics of stats (max, min, etc.) +# * Filterby + +# Node and edge attributes: T onversion functions (tohist, tonumpy, etc.), stats of stats (max, min, etc.), and filterby + +# Tests specific to different metrics are implemented in the other files. + +### General functionality + +import numpy as np +import pandas as pd +import pytest + +import xgi + + +def test_hypergraph_filterby_wrong_stat(): + H = xgi.Hypergraph() + with pytest.raises(AttributeError): + H.nodes.filterby("__I_DO_NOT_EXIST__", None) + + with pytest.raises(AttributeError): + H.edges.filterby("__I_DO_NOT_EXIST__", None) + + +def test_sc_filterby_wrong_stat(): + H = xgi.SimplicialComplex() + with pytest.raises(AttributeError): + H.nodes.filterby("__I_DO_NOT_EXIST__", None) + + with pytest.raises(AttributeError): + H.edges.filterby("__I_DO_NOT_EXIST__", None) + + +def test_dihypergraph_filterby_wrong_stat(): + H = xgi.DiHypergraph() + with pytest.raises(AttributeError): + H.nodes.filterby("__I_DO_NOT_EXIST__", None) + + with pytest.raises(AttributeError): + H.edges.filterby("__I_DO_NOT_EXIST__", None) + + +def test_hypergraph_stats_items(edgelist1): + H = xgi.Hypergraph(edgelist1) + + deg = {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} + for n, d in H.nodes.degree.items(): + assert deg[n] == d + + o = {0: 2, 1: 0, 2: 1, 3: 2} + for e, s in H.edges.order.items(): + assert o[e] == s + + +def test_dihypergraph_stats_items(diedgelist2): + d = {0: 2, 1: 2, 2: 3} + H = xgi.DiHypergraph(diedgelist2) + for e, s in H.edges.order.items(): + assert d[e] == s + + +def test_hypergraph_view_val(edgelist1, edgelist2): + H = xgi.Hypergraph(edgelist1) + assert H.nodes.degree._val == {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} + assert H.nodes([1, 2, 3]).degree._val == {1: 1, 2: 1, 3: 1} + assert H.edges.order._val == {0: 2, 1: 0, 2: 1, 3: 2} + assert H.edges([1, 2]).order._val == {1: 0, 2: 1} + + H = xgi.Hypergraph(edgelist2) + assert H.nodes.degree._val == {1: 1, 2: 1, 3: 1, 4: 2, 5: 1, 6: 1} + assert H.nodes([4, 5, 6]).degree._val == {4: 2, 5: 1, 6: 1} + assert H.edges.order._val == {0: 1, 1: 1, 2: 2} + assert H.edges([1, 2]).order._val == {1: 1, 2: 2} + + +def test_dihypergraph_view_val(diedgelist1, diedgelist2): + H = xgi.DiHypergraph(diedgelist1) + assert H.edges.order._val == {0: 3, 1: 3} + assert H.edges([1]).order._val == {1: 3} + + H = xgi.DiHypergraph(diedgelist2) + assert H.nodes.degree._val == {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} + assert H.nodes([1, 2]).degree._val == {1: 2, 2: 3} + + assert H.edges.order._val == {0: 2, 1: 2, 2: 3} + assert H.edges([1, 2]).order._val == {1: 2, 2: 3} + + +def test_hypergraph_stats_are_views(edgelist1): + H = xgi.Hypergraph(edgelist1) + ns = H.nodes.degree + assert ns.asdict() == {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} + H.add_node(10) + assert ns.asdict() == {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1, 10: 0} + H.add_edge([1, 2, 10, 20]) + assert ns.asdict() == {1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1, 10: 1, 20: 1} + + H = xgi.Hypergraph(edgelist1) + es = H.edges.order + assert es.asdict() == {0: 2, 1: 0, 2: 1, 3: 2} + H.add_edge([3, 4, 5]) + assert es.asdict() == {0: 2, 1: 0, 2: 1, 3: 2, 4: 2} + + +def test_dihypergraph_stats_are_views(diedgelist2): + H = xgi.DiHypergraph(diedgelist2) + es = H.edges.order + assert es.asdict() == {0: 2, 1: 2, 2: 3} + H.add_edge(([3, 4, 5], [6])) + assert es.asdict() == {0: 2, 1: 2, 2: 3, 3: 3} + + H = xgi.DiHypergraph(diedgelist2) + ns = H.nodes.degree + assert ns.asdict() == {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} + H.add_node(10) + assert ns.asdict() == {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1, 10: 0} + + +def test_hypergraph_user_defined(edgelist1): + + # Hypergraphs + H = xgi.Hypergraph(edgelist1) + + with pytest.raises(AttributeError): + H.user_degree + with pytest.raises(AttributeError): + H.nodes.user_degree + + @xgi.nodestat_func + def user_degree(net, bunch): + return {n: 10 * net.degree(n) for n in bunch} + + vals = {n: 10 * H.degree(n) for n in H} + assert H.user_degree() == vals + assert H.nodes.user_degree.asdict() == vals + assert H.nodes.user_degree.aslist() == [vals[n] for n in H] + assert ( + list(H.nodes.filterby("user_degree", 20)) + == list(H.nodes.filterby("degree", 2)) + == [6] + ) + assert H.nodes.filterby("degree", 2).user_degree.asdict() == {6: 20} + + with pytest.raises(AttributeError): + H.user_order + with pytest.raises(AttributeError): + H.edges.user_order + + @xgi.edgestat_func + def user_order(net, bunch): + return {e: 10 * net.order(e) for e in bunch} + + vals = {e: 10 * H.order(e) for e in H.edges} + assert H.user_order() == vals + assert H.edges.user_order.asdict() == vals + assert H.edges.user_order.aslist() == [vals[n] for n in H.edges] + assert ( + list(H.edges.filterby("user_order", 20)) + == list(H.edges.filterby("order", 2)) + == [0, 3] + ) + assert H.edges.filterby("order", 2).user_order.asdict() == {0: 20, 3: 20} + + +def test_dihypergraph_user_defined(diedgelist2): + # DiHypergraphs + H = xgi.DiHypergraph(diedgelist2) + + with pytest.raises(AttributeError): + H.user_didegree + with pytest.raises(AttributeError): + H.nodes.user_didegree + + @xgi.dinodestat_func + def user_didegree(net, bunch): + return {n: 10 * net.degree(n) for n in bunch} + + vals = {n: 10 * H.degree(n) for n in H.nodes} + assert H.user_didegree() == vals + assert H.nodes.user_didegree.asdict() == vals + assert H.nodes.user_didegree.aslist() == [vals[n] for n in H.nodes] + assert H.nodes.filterby("degree", 2).user_didegree.asdict() == {1: 20, 4: 20} + + with pytest.raises(AttributeError): + H.user_diorder + with pytest.raises(AttributeError): + H.edges.user_diorder + + @xgi.diedgestat_func + def user_diorder(net, bunch): + return {e: 10 * net.order(e) for e in bunch} + + vals = {e: 10 * H.order(e) for e in H.edges} + assert H.user_diorder() == vals + assert H.edges.user_diorder.asdict() == vals + assert H.edges.user_diorder.aslist() == [vals[n] for n in H.edges] + assert H.edges.filterby("order", 2).user_diorder.asdict() == {0: 20, 1: 20} + + +def test_hypergraph_different_views(edgelist1): + H = xgi.Hypergraph(edgelist1) + with pytest.raises(KeyError): + H.nodes.multi([H.nodes.degree, H.nodes([1, 2]).degree]).asdict() + with pytest.raises(KeyError): + H.nodes.multi([H.nodes.attrs("color"), H.nodes([1, 2]).attrs("color")]).asdict() + + with pytest.raises(KeyError): + H.edges.multi(["order", H.edges([1, 2]).size]).asdict() + with pytest.raises(KeyError): + H.edges.multi(["order", H.edges([1, 2]).attrs("color")]).asdict() + + +def test_dihypergraph_different_views(diedgelist1): + H = xgi.DiHypergraph(diedgelist1) + with pytest.raises(KeyError): + H.nodes.multi([H.nodes.degree, H.nodes([1, 2]).degree]).asdict() + with pytest.raises(KeyError): + H.nodes.multi([H.nodes.attrs("color"), H.nodes([1, 2]).attrs("color")]).asdict() + + with pytest.raises(KeyError): + H.edges.multi(["order", H.edges([1, 2]).size]).asdict() + with pytest.raises(KeyError): + H.edges.multi(["order", H.edges([1, 2]).attrs("color")]).asdict() + + +def test_hypergraph_stats_items(edgelist1): + d = {0: 2, 1: 0, 2: 1, 3: 2} + H = xgi.Hypergraph(edgelist1) + for e, s in H.edges.order.items(): + assert d[e] == s + + +def test_dihypergraph_stats_items(diedgelist2): + deg = {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} + H = xgi.DiHypergraph(diedgelist2) + for n, d in H.nodes.degree.items(): + assert deg[n] == d + + +### Numerical statistics + + +def test_hypergraph_filterby(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + assert H.nodes.filterby("degree", 2).average_neighbor_degree.asdict() == {6: 1.0} + assert H.nodes.filterby("average_neighbor_degree", 1.0).degree.asdict() == { + 1: 1, + 2: 1, + 3: 1, + 6: 2, + } + assert H.edges.filterby("order", 2).size.asdict() == {0: 3, 3: 3} + assert H.edges.filterby("size", 2).order.asdict() == {2: 1} + + H = xgi.Hypergraph(edgelist8) + assert H.nodes.filterby("degree", 3).average_neighbor_degree.asdict() == {4: 4.2} + assert H.nodes.filterby("average_neighbor_degree", 4.2).degree.asdict() == {4: 3} + assert H.edges.filterby("order", 2).size.asdict() == {1: 3, 2: 3, 4: 3, 5: 3, 6: 3} + assert H.edges.filterby("size", 2).order.asdict() == {0: 1, 8: 1, 7: 1} + + +def test_dihypergraph_filterby(diedgelist1, diedgelist2): + H = xgi.DiHypergraph(diedgelist2) + assert H.nodes.filterby("degree", 2).in_degree.asdict() == {1: 2, 4: 1} + assert H.nodes.filterby("degree", 2).out_degree.asdict() == {1: 0, 4: 2} + assert H.nodes.filterby("in_degree", 1).degree.asdict() == {0: 1, 3: 1, 4: 2} + assert H.nodes.filterby("out_degree", 1).degree.asdict() == {2: 3, 5: 1} + + assert H.edges.filterby("order", 2).size.asdict() == {0: 3, 1: 3} + assert H.edges.filterby("size", 4).order.asdict() == {2: 3} + + H = xgi.DiHypergraph(diedgelist1) + assert H.nodes.filterby("degree", 1).in_degree.asdict() == { + 1: 1, + 2: 1, + 3: 1, + 4: 0, + 5: 1, + 6: 1, + 7: 0, + 8: 0, + } + assert H.nodes.filterby("degree", 1).out_degree.asdict() == { + 1: 0, + 2: 0, + 3: 0, + 4: 1, + 5: 0, + 6: 1, + 7: 1, + 8: 1, + } + assert H.nodes.filterby("in_degree", 1).degree.asdict() == { + 1: 1, + 2: 1, + 3: 1, + 5: 1, + 6: 1, + } + assert H.nodes.filterby("out_degree", 1).degree.asdict() == {8: 1, 4: 1, 6: 1, 7: 1} + + +def test_filterby_modes(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + assert list(H.nodes.filterby("degree", 2)) == [6] + assert list(H.nodes.filterby("degree", 2, "eq")) == [6] + assert list(H.nodes.filterby("degree", 1, "neq")) == [6] + assert list(H.nodes.filterby("degree", 2, "geq")) == [6] + assert list(H.nodes.filterby("degree", 2, "gt")) == [] + assert list(H.nodes.filterby("degree", 0, "leq")) == [] + assert list(H.nodes.filterby("degree", 1, "lt")) == [] + assert set(H.nodes.filterby("degree", (1, 3), "between")) == set(H.nodes) + + H = xgi.Hypergraph(edgelist8) + assert set(H.nodes.filterby("degree", 2)) == {5, 6} + assert set(H.nodes.filterby("degree", 2, "eq")) == {5, 6} + assert set(H.nodes.filterby("degree", 2, "neq")) == {0, 1, 2, 3, 4} + assert set(H.nodes.filterby("degree", 5, "geq")) == {0, 1} + assert set(H.nodes.filterby("degree", 5, "gt")) == {0} + assert set(H.nodes.filterby("degree", 2, "leq")) == {5, 6} + assert set(H.nodes.filterby("degree", 2, "lt")) == set() + assert set(H.nodes.filterby("degree", (2, 3), "between")) == {4, 5, 6} + + +def test_dihypergraph_filterby_modes(diedgelist2): + H = xgi.DiHypergraph(diedgelist2) + assert list(H.nodes.filterby("degree", 2)) == [1, 4] + assert list(H.nodes.filterby("degree", 2, "eq")) == [1, 4] + assert list(H.nodes.filterby("degree", 1, "neq")) == [1, 2, 4] + assert list(H.nodes.filterby("degree", 3, "geq")) == [2] + assert list(H.nodes.filterby("degree", 3, "gt")) == [] + assert list(H.nodes.filterby("degree", 0, "leq")) == [] + assert list(H.nodes.filterby("degree", 1, "lt")) == [] + assert set(H.nodes.filterby("degree", (1, 3), "between")) == set(H.nodes) + + +def test_hypergraph_call_filterby(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + + filtered = H.nodes([5, 6, 7, 8]).filterby("average_neighbor_degree", 2.0).degree + assert filtered.asdict() == {5: 1} + + filtered = H.nodes([5, 6, 7, 8]).filterby("degree", 2).average_neighbor_degree + assert filtered.asdict() == {6: 1.0} + + filtered = H.edges([1, 2, 3]).filterby("order", 2).size + assert filtered.asdict() == {3: 3} + + H = xgi.Hypergraph(edgelist8) + assert set(H.nodes([1, 2, 3]).filterby("degree", 4)) == {2, 3} + + filtered = H.nodes([1, 2, 3]).filterby("average_neighbor_degree", 4.0).degree + assert filtered.asdict() == {2: 4, 3: 4} + + filtered = H.nodes([1, 2, 3]).filterby("degree", 5).average_neighbor_degree + assert filtered.asdict() == {1: 3.5} + + filtered = H.edges([5, 6]).filterby("order", 2).size + assert filtered.asdict() == {5: 3, 6: 3} + + +def test_dihypergraph_call_filterby(diedgelist1, diedgelist2): + H = xgi.DiHypergraph(diedgelist1) + + filtered = H.nodes([4, 5, 6]).filterby("in_degree", 1).degree + assert filtered.asdict() == {5: 1, 6: 1} + + H = xgi.DiHypergraph(diedgelist2) + assert set(H.nodes([1, 2, 3]).filterby("degree", 2)) == {1} + assert H.edges([1, 2]).filterby("order", 2).size.asdict() == {1: 3} + + +def test_hypergraph_after_call_with_args(edgelist1): + H = xgi.Hypergraph(edgelist1) + degs = {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} + assert H.nodes.degree.asdict() == degs + + # check when calling without arguments AFTER calling WITH arguments + H.nodes.degree(order=2).asdict() + assert H.nodes.degree.asdict() == degs + + +def test_dihypergraph_after_call_with_args(diedgelist2): + H = xgi.DiHypergraph(diedgelist2) + degs = {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} + assert H.nodes.degree.asdict() == degs + + # check when calling without arguments AFTER calling WITH arguments + H.nodes.degree(order=2).asdict() + assert H.nodes.degree.asdict() == degs + + +def test_hypergraph_filterby_with_nodestat(edgelist4, edgelist8): + H = xgi.Hypergraph(edgelist4) + assert list(H.nodes.filterby(H.nodes.degree(order=2), 2)) == [3] + + H = xgi.Hypergraph(edgelist8) + assert list(H.nodes.filterby(H.nodes.degree(order=2), 2)) == [1, 4, 5] + + +def test_dihypergraph_filterby_with_nodestat(diedgelist1, diedgelist2): + H = xgi.DiHypergraph(diedgelist1) + assert list(H.edges.filterby(H.edges.order(degree=1), 3)) == [0, 1] + + H = xgi.DiHypergraph(diedgelist2) + assert list(H.edges.filterby(H.edges.order(degree=2), 1)) == [1] + assert list(H.nodes.filterby(H.nodes.degree(order=2), 1)) == [0, 4] + + +def test_filterby_edgestat_with_nodestat(edgelist4, edgelist8): + H = xgi.Hypergraph(edgelist4) + assert list(H.edges.filterby(H.edges.order(degree=2), 2)) == [1] + + H = xgi.Hypergraph(edgelist8) + assert list(H.edges.filterby(H.edges.order(degree=4), 1)) == [2, 3] + + +def test_hypergraph_aggregates(edgelist1, edgelist2, edgelist8): + H = xgi.Hypergraph(edgelist1) + assert H.nodes.degree.max() == 2 + assert H.nodes.degree.min() == 1 + assert H.nodes.degree.argmax() == 6 + assert H.nodes.degree.argmin() == 1 + assert H.nodes.degree.argsort() == list(H.nodes.filterby("degree", 1)) + list( + H.nodes.filterby("degree", 2) + ) + assert H.nodes.degree.argsort(reverse=True) == list( + H.nodes.filterby("degree", 2) + ) + list(H.nodes.filterby("degree", 1)) + assert H.nodes.degree.sum() == 9 + assert round(H.nodes.degree.mean(), 3) == 1.125 + assert round(H.nodes.degree.std(), 3) == 0.331 + assert round(H.nodes.degree.var(), 3) == 0.109 + + assert H.edges.order.max() == 2 + assert H.edges.order.min() == 0 + assert H.edges.order.sum() == 5 + assert round(H.edges.order.mean(), 3) == 1.25 + assert round(H.edges.order.std(), 3) == 0.829 + assert round(H.edges.order.var(), 3) == 0.688 + + H = xgi.Hypergraph(edgelist2) + assert H.nodes.degree.max() == 2 + assert H.nodes.degree.min() == 1 + assert H.nodes.degree.argmax() == 4 + assert H.nodes.degree.argmin() == 1 + assert H.nodes.degree.argsort() == list(H.nodes.filterby("degree", 1)) + list( + H.nodes.filterby("degree", 2) + ) + assert H.nodes.degree.sum() == 7 + assert round(H.nodes.degree.mean(), 3) == 1.167 + assert round(H.nodes.degree.std(), 3) == 0.373 + assert round(H.nodes.degree.var(), 3) == 0.139 + + assert H.edges.order.max() == 2 + assert H.edges.order.min() == 1 + assert H.edges.order.sum() == 4 + assert round(H.edges.order.mean(), 3) == 1.333 + assert round(H.edges.order.std(), 3) == 0.471 + assert round(H.edges.order.var(), 3) == 0.222 + + H = xgi.Hypergraph(edgelist8) + assert H.nodes.degree.max() == 6 + assert H.nodes.degree.min() == 2 + assert H.nodes.degree.argmax() == 0 + assert H.nodes.degree.argmin() == 5 + assert H.nodes.degree.argsort() == list(H.nodes.filterby("degree", 2)) + list( + H.nodes.filterby("degree", 3) + ) + list(H.nodes.filterby("degree", 4)) + list( + H.nodes.filterby("degree", 5) + ) + list( + H.nodes.filterby("degree", 6) + ) + assert H.nodes.degree.sum() == 26 + assert round(H.nodes.degree.mean(), 3) == 3.714 + assert round(H.nodes.degree.std(), 3) == 1.385 + assert round(H.nodes.degree.var(), 3) == 1.918 + + assert H.edges.order.max() == 4 + assert H.edges.order.min() == 1 + assert H.edges.order.sum() == 17 + assert round(H.edges.order.mean(), 3) == 1.889 + assert round(H.edges.order.std(), 3) == 0.875 + assert round(H.edges.order.var(), 3) == 0.765 + + +def test_dihypergraph_aggregates(diedgelist1, diedgelist2): + H = xgi.DiHypergraph(diedgelist1) + assert H.edges.order.max() == 3 + assert H.edges.order.min() == 3 + assert H.edges.order.sum() == 6 + assert round(H.edges.order.mean(), 3) == 3 + assert round(H.edges.order.std(), 3) == 0 + assert round(H.edges.order.var(), 3) == 0 + + H = xgi.DiHypergraph(diedgelist2) + assert H.nodes.degree.max() == 3 + assert H.nodes.degree.min() == 1 + assert H.nodes.degree.sum() == 10 + assert round(H.nodes.degree.mean(), 3) == 1.667 + assert round(H.nodes.degree.std(), 3) == 0.745 + assert round(H.nodes.degree.var(), 3) == 0.556 + + assert H.edges.order.max() == 3 + assert H.edges.order.min() == 2 + assert H.edges.order.sum() == 7 + assert round(H.edges.order.mean(), 3) == 2.333 + assert round(H.edges.order.std(), 3) == 0.471 + assert round(H.edges.order.var(), 3) == 0.222 + + +def test_hypergraph_moment(edgelist1, edgelist6): + H = xgi.Hypergraph(edgelist1) + deg = H.nodes.degree + assert round(deg.moment(), 3) == 1.375 + assert round(deg.moment(2, center=False), 3) == 1.375 + assert round(deg.moment(2, center=True), 3) == 0.109 + assert round(deg.moment(3, center=False), 3) == 1.875 + assert round(deg.moment(3, center=True), 3) == 0.082 + + H = xgi.Hypergraph(edgelist6) + deg = H.edges.size + assert round(deg.moment(), 3) == 9.0 + assert round(deg.moment(2, center=False), 3) == 9.0 + assert round(deg.moment(2, center=True), 3) == 0.0 + assert round(deg.moment(3, center=False), 3) == 27.0 + assert round(deg.moment(3, center=True), 3) == 0.0 + + +def test_dihypergraph_moment(diedgelist2): + H = xgi.DiHypergraph(diedgelist2) + deg = H.nodes.degree + assert round(deg.moment(), 3) == 3.333 + assert round(deg.moment(2, center=False), 3) == 3.333 + assert round(deg.moment(2, center=True), 3) == 0.556 + assert round(deg.moment(3, center=False), 3) == 7.667 + assert round(deg.moment(3, center=True), 3) == 0.259 + + +def test_hypergraph_single_id(edgelist1): + H = xgi.Hypergraph(edgelist1) + assert H.degree()[1] == 1 + assert H.nodes.degree[1] == 1 + with pytest.raises(KeyError): + H.degree()[-1] + with pytest.raises(KeyError): + H.nodes.degree[-1] + + assert H.order()[1] == 0 + assert H.edges.order[1] == 0 + with pytest.raises(KeyError): + H.order()[-1] + with pytest.raises(KeyError): + H.edges.order[-1] + + +def test_dihypergraph_single_id(diedgelist1): + H = xgi.DiHypergraph(diedgelist1) + assert H.degree()[1] == 1 + assert H.nodes.degree[1] == 1 + with pytest.raises(KeyError): + H.degree()[-1] + with pytest.raises(KeyError): + H.nodes.degree[-1] + + assert H.order()[1] == 3 + assert H.edges.order[1] == 3 + with pytest.raises(KeyError): + H.order()[-1] + with pytest.raises(KeyError): + H.edges.order[-1] + + +def test_issue_468(): + H = xgi.sunflower(3, 1, 20) + df = pd.DataFrame([[20.0, 3]], columns=["bin_center", "value"]) + assert H.edges.size.ashist().equals(df) + + +### Attribute statistics + + +def test_hypergraph_attrs(hyperwithattrs, attr1, attr2, attr3, attr4, attr5): + H = hyperwithattrs + attrs = { + 1: attr1, + 2: attr2, + 3: attr3, + 4: attr4, + 5: attr5, + } + assert H.nodes.attrs.asdict() == attrs + assert H.nodes.attrs.aslist() == list(attrs.values()) + assert H.nodes.attrs("color").asdict() == {n: H._node_attr[n]["color"] for n in H} + + filtered = H.nodes.filterby_attr("color", "blue").attrs + assert filtered.asdict() == {2: attr2, 5: attr5} + + filtered = H.nodes([1, 2, 3]).filterby_attr("color", "blue").attrs + assert filtered.asdict() == {2: attr2} + + filtered = H.nodes([1, 2, 3]).filterby("degree", 3).attrs + assert filtered.asdict() == {3: attr3} + + with pytest.raises(ValueError): + H.nodes.attrs(-1).asdict() + + +# test pre-defined functions +def test_dihypergraph_attrs(dihyperwithattrs): + c = dihyperwithattrs.nodes.attrs("color") + assert c.asdict() == { + 0: "brown", + 1: "red", + 2: "blue", + 3: "yellow", + 4: "red", + 5: "blue", + } + c = dihyperwithattrs.nodes.attrs("age", missing=100) + assert c.asdict() == {0: 100, 1: 100, 2: 100, 3: 100, 4: 20, 5: 2} + c = dihyperwithattrs.nodes.attrs() + assert c.asdict() == { + 0: {"color": "brown", "name": "camel"}, + 1: {"color": "red", "name": "horse"}, + 2: {"color": "blue", "name": "pony"}, + 3: {"color": "yellow", "name": "zebra"}, + 4: {"color": "red", "name": "orangutan", "age": 20}, + 5: {"color": "blue", "name": "fish", "age": 2}, + } + with pytest.raises(ValueError): + dihyperwithattrs.nodes.attrs(attr=100).asdict() + + +def test_filterby_attr(hyperwithattrs): + H = hyperwithattrs + + filtered = H.nodes.filterby_attr("age", 20, "eq") + assert set(filtered) == {4} + + filtered = H.nodes.filterby_attr("age", 2, "neq") + assert set(filtered) == {4} + + filtered = H.nodes.filterby_attr("age", 20, "lt") + assert set(filtered) == {5} + + filtered = H.nodes.filterby_attr("age", 2, "gt") + assert set(filtered) == {4} + + filtered = H.nodes.filterby_attr("age", 20, "leq") + assert set(filtered) == {4, 5} + + filtered = H.nodes.filterby_attr("age", 2, "geq") + assert set(filtered) == {4, 5} + + filtered = H.nodes.filterby_attr("age", [1, 3], "between") + assert set(filtered) == {5} + + filtered = H.nodes.filterby_attr("age", [2, 20], "between") + assert set(filtered) == {4, 5} + + filtered = H.nodes.filterby_attr("age", 2, "leq", 1) + assert set(filtered) == {1, 2, 3, 5} + + filtered = H.nodes.filterby_attr("age", 2, "leq", 10) + assert set(filtered) == {5} + + +def test_missing_attrs(hyperwithattrs): + H = hyperwithattrs + H.add_node(10) + assert H.nodes.attrs("color").asdict() == { + 1: "red", + 2: "blue", + 3: "yellow", + 4: "red", + 5: "blue", + 10: None, + } + assert H.nodes.attrs("color", missing="missingval").asdict() == { + 1: "red", + 2: "blue", + 3: "yellow", + 4: "red", + 5: "blue", + 10: "missingval", + } + + +### Test multiple stats + + +def test_multi_stats_order(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + assert H.nodes.multi(["degree", "average_neighbor_degree"]).asdict() == { + 1: {"degree": 1, "average_neighbor_degree": 1.0}, + 2: {"degree": 1, "average_neighbor_degree": 1.0}, + 3: {"degree": 1, "average_neighbor_degree": 1.0}, + 4: {"degree": 1, "average_neighbor_degree": 0}, + 5: {"degree": 1, "average_neighbor_degree": 2.0}, + 6: {"degree": 2, "average_neighbor_degree": 1.0}, + 7: {"degree": 1, "average_neighbor_degree": 1.5}, + 8: {"degree": 1, "average_neighbor_degree": 1.5}, + } + assert H.nodes.multi(["average_neighbor_degree", "degree"]).asdict() == { + 1: {"average_neighbor_degree": 1.0, "degree": 1}, + 2: {"average_neighbor_degree": 1.0, "degree": 1}, + 3: {"average_neighbor_degree": 1.0, "degree": 1}, + 4: {"average_neighbor_degree": 0, "degree": 1}, + 5: {"average_neighbor_degree": 2.0, "degree": 1}, + 6: {"average_neighbor_degree": 1.0, "degree": 2}, + 7: {"average_neighbor_degree": 1.5, "degree": 1}, + 8: {"average_neighbor_degree": 1.5, "degree": 1}, + } + + H = xgi.Hypergraph(edgelist8) + assert H.nodes.multi(["degree", "average_neighbor_degree"]).asdict() == { + 0: {"degree": 6, "average_neighbor_degree": 3.6}, + 1: {"degree": 5, "average_neighbor_degree": 3.5}, + 2: {"degree": 4, "average_neighbor_degree": 4.0}, + 3: {"degree": 4, "average_neighbor_degree": 4.0}, + 4: {"degree": 3, "average_neighbor_degree": 4.2}, + 5: {"degree": 2, "average_neighbor_degree": 4.0}, + 6: {"degree": 2, "average_neighbor_degree": 5.5}, + } + assert H.nodes.multi(["average_neighbor_degree", "degree"]).asdict() == { + 0: {"average_neighbor_degree": 3.6, "degree": 6}, + 1: {"average_neighbor_degree": 3.5, "degree": 5}, + 2: {"average_neighbor_degree": 4.0, "degree": 4}, + 3: {"average_neighbor_degree": 4.0, "degree": 4}, + 4: {"average_neighbor_degree": 4.2, "degree": 3}, + 5: {"average_neighbor_degree": 4.0, "degree": 2}, + 6: {"average_neighbor_degree": 5.5, "degree": 2}, + } + + +def test_multi_stats_with_parameters(edgelist1): + H = xgi.Hypergraph(edgelist1) + multi = H.nodes.multi(["degree", H.nodes.degree(order=2)]) + assert multi.asdict() == { + 1: {"degree": 1, "degree(order=2)": 1}, + 2: {"degree": 1, "degree(order=2)": 1}, + 3: {"degree": 1, "degree(order=2)": 1}, + 4: {"degree": 1, "degree(order=2)": 0}, + 5: {"degree": 1, "degree(order=2)": 0}, + 6: {"degree": 2, "degree(order=2)": 1}, + 7: {"degree": 1, "degree(order=2)": 1}, + 8: {"degree": 1, "degree(order=2)": 1}, + } + + +def test_multi_stats_dict_transpose(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + multi = H.nodes.multi( + ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] + ) + assert multi.asdict() == { + 1: {"average_neighbor_degree": 1.0, "degree": 1, "degree(order=2)": 1}, + 2: {"average_neighbor_degree": 1.0, "degree": 1, "degree(order=2)": 1}, + 3: {"average_neighbor_degree": 1.0, "degree": 1, "degree(order=2)": 1}, + 4: {"average_neighbor_degree": 0, "degree": 1, "degree(order=2)": 0}, + 5: {"average_neighbor_degree": 2.0, "degree": 1, "degree(order=2)": 0}, + 6: {"average_neighbor_degree": 1.0, "degree": 2, "degree(order=2)": 1}, + 7: {"average_neighbor_degree": 1.5, "degree": 1, "degree(order=2)": 1}, + 8: {"average_neighbor_degree": 1.5, "degree": 1, "degree(order=2)": 1}, + } + assert multi.asdict(transpose=True) == { + "average_neighbor_degree": { + 1: 1.0, + 2: 1.0, + 3: 1.0, + 4: 0, + 5: 2.0, + 6: 1.0, + 7: 1.5, + 8: 1.5, + }, + "degree": {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1}, + "degree(order=2)": {1: 1, 2: 1, 3: 1, 4: 0, 5: 0, 6: 1, 7: 1, 8: 1}, + } + + H = xgi.Hypergraph(edgelist8) + multi = H.nodes.multi( + ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] + ) + assert multi.asdict() == { + 0: {"average_neighbor_degree": 3.6, "degree": 6, "degree(order=2)": 3}, + 1: {"average_neighbor_degree": 3.5, "degree": 5, "degree(order=2)": 2}, + 2: {"average_neighbor_degree": 4.0, "degree": 4, "degree(order=2)": 3}, + 3: {"average_neighbor_degree": 4.0, "degree": 4, "degree(order=2)": 3}, + 4: {"average_neighbor_degree": 4.2, "degree": 3, "degree(order=2)": 2}, + 5: {"average_neighbor_degree": 4.0, "degree": 2, "degree(order=2)": 2}, + 6: {"average_neighbor_degree": 5.5, "degree": 2, "degree(order=2)": 0}, + } + assert multi.asdict(transpose=True) == { + "average_neighbor_degree": { + 0: 3.6, + 1: 3.5, + 2: 4.0, + 3: 4.0, + 4: 4.2, + 5: 4.0, + 6: 5.5, + }, + "degree": {0: 6, 1: 5, 2: 4, 3: 4, 4: 3, 5: 2, 6: 2}, + "degree(order=2)": {0: 3, 1: 2, 2: 3, 3: 3, 4: 2, 5: 2, 6: 0}, + } + + +def test_multi_stats_dict_list(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + multi = H.nodes.multi(["average_neighbor_degree", "degree"]) + assert multi.asdict(list) == { + 1: [1.0, 1], + 2: [1.0, 1], + 3: [1.0, 1], + 4: [0, 1], + 5: [2.0, 1], + 6: [1.0, 2], + 7: [1.5, 1], + 8: [1.5, 1], + } + + H = xgi.Hypergraph(edgelist8) + multi = H.nodes.multi(["average_neighbor_degree", "degree"]) + assert multi.asdict(list) == { + 0: [3.6, 6], + 1: [3.5, 5], + 2: [4.0, 4], + 3: [4.0, 4], + 4: [4.2, 3], + 5: [4.0, 2], + 6: [5.5, 2], + } + + +def test_multi_stats_list_dict(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + multi = H.nodes.multi(["average_neighbor_degree", "degree"]) + assert multi.aslist(dict) == [ + {"average_neighbor_degree": 1.0, "degree": 1}, + {"average_neighbor_degree": 1.0, "degree": 1}, + {"average_neighbor_degree": 1.0, "degree": 1}, + {"average_neighbor_degree": 0, "degree": 1}, + {"average_neighbor_degree": 2.0, "degree": 1}, + {"average_neighbor_degree": 1.0, "degree": 2}, + {"average_neighbor_degree": 1.5, "degree": 1}, + {"average_neighbor_degree": 1.5, "degree": 1}, + ] + + H = xgi.Hypergraph(edgelist8) + multi = H.nodes.multi(["average_neighbor_degree", "degree"]) + assert multi.aslist(dict) == [ + {"average_neighbor_degree": 3.6, "degree": 6}, + {"average_neighbor_degree": 3.5, "degree": 5}, + {"average_neighbor_degree": 4.0, "degree": 4}, + {"average_neighbor_degree": 4.0, "degree": 4}, + {"average_neighbor_degree": 4.2, "degree": 3}, + {"average_neighbor_degree": 4.0, "degree": 2}, + {"average_neighbor_degree": 5.5, "degree": 2}, + ] + + +def test_multi_stats_list_transpose(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + multi = H.nodes.multi( + ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] + ) + assert multi.aslist() == [ + [1.0, 1, 1], + [1.0, 1, 1], + [1.0, 1, 1], + [0, 1, 0], + [2.0, 1, 0], + [1.0, 2, 1], + [1.5, 1, 1], + [1.5, 1, 1], + ] + assert multi.aslist(transpose=True) == [ + [1.0, 1.0, 1.0, 0, 2.0, 1.0, 1.5, 1.5], + [1, 1, 1, 1, 1, 2, 1, 1], + [1, 1, 1, 0, 0, 1, 1, 1], + ] + + H = xgi.Hypergraph(edgelist8) + multi = H.nodes.multi( + ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] + ) + assert multi.aslist() == [ + [3.6, 6, 3], + [3.5, 5, 2], + [4.0, 4, 3], + [4.0, 4, 3], + [4.2, 3, 2], + [4.0, 2, 2], + [5.5, 2, 0], + ] + assert multi.aslist(transpose=True) == [ + [3.6, 3.5, 4.0, 4.0, 4.2, 4.0, 5.5], + [6, 5, 4, 4, 3, 2, 2], + [3, 2, 3, 3, 2, 2, 0], + ] + + +def test_multi_stats_aspandas(edgelist1, edgelist8): + H = xgi.Hypergraph(edgelist1) + multi = H.nodes.multi( + ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] + ) + df = pd.DataFrame(multi.asdict(transpose=True)) + pd.testing.assert_frame_equal(df, multi.aspandas(), check_like=True) + + H = xgi.Hypergraph(edgelist8) + multi = H.nodes.multi( + ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] + ) + df = pd.DataFrame(multi.asdict(transpose=True)) + pd.testing.assert_frame_equal(df, multi.aspandas()) + + +def test_multi_with_attrs(hyperwithattrs): + H = hyperwithattrs + multi = H.nodes.multi([H.nodes.attrs("color")]) + assert multi.asdict() == { + 1: {"attrs(color)": "red"}, + 2: {"attrs(color)": "blue"}, + 3: {"attrs(color)": "yellow"}, + 4: {"attrs(color)": "red"}, + 5: {"attrs(color)": "blue"}, + } + assert multi.asdict(transpose=True) == { + "attrs(color)": {1: "red", 2: "blue", 3: "yellow", 4: "red", 5: "blue"} + } + + multi = H.nodes.multi([H.nodes.degree, H.nodes.attrs("color")]) + assert multi.asdict() == { + 1: {"degree": 1, "attrs(color)": "red"}, + 2: {"degree": 2, "attrs(color)": "blue"}, + 3: {"degree": 3, "attrs(color)": "yellow"}, + 4: {"degree": 2, "attrs(color)": "red"}, + 5: {"degree": 2, "attrs(color)": "blue"}, + } + assert multi.asdict(list) == { + 1: [1, "red"], + 2: [2, "blue"], + 3: [3, "yellow"], + 4: [2, "red"], + 5: [2, "blue"], + } diff --git a/tests/stats/test_diedgestats.py b/tests/stats/test_diedgestats.py index 65397e3d8..9ea380daf 100644 --- a/tests/stats/test_diedgestats.py +++ b/tests/stats/test_diedgestats.py @@ -2,139 +2,18 @@ import xgi - -def test_filterby_wrong_stat(): - H = xgi.DiHypergraph() - with pytest.raises(AttributeError): - H.edges.filterby("__I_DO_NOT_EXIST__", None) - - -def test_filterby(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - assert H.edges.filterby("order", 2).size.asdict() == {0: 3, 1: 3} - assert H.edges.filterby("size", 4).order.asdict() == {2: 3} - - -def test_call_filterby(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - assert H.edges([1, 2]).filterby("order", 2).size.asdict() == {1: 3} - - -def test_filterby_with_nodestat(diedgelist1, diedgelist2): - H = xgi.DiHypergraph(diedgelist1) - assert list(H.edges.filterby(H.edges.order(degree=1), 3)) == [0, 1] - - H = xgi.DiHypergraph(diedgelist2) - assert list(H.edges.filterby(H.edges.order(degree=2), 1)) == [1] - - -def test_single_node(diedgelist1): - H = xgi.DiHypergraph(diedgelist1) - assert H.order()[1] == 3 - assert H.edges.order[1] == 3 - with pytest.raises(KeyError): - H.order()[-1] - with pytest.raises(KeyError): - H.edges.order[-1] - - -def test_aggregates(diedgelist1, diedgelist2): - H = xgi.DiHypergraph(diedgelist1) - assert H.edges.order.max() == 3 - assert H.edges.order.min() == 3 - assert H.edges.order.sum() == 6 - assert round(H.edges.order.mean(), 3) == 3 - assert round(H.edges.order.std(), 3) == 0 - assert round(H.edges.order.var(), 3) == 0 - - H = xgi.DiHypergraph(diedgelist2) - assert H.edges.order.max() == 3 - assert H.edges.order.min() == 2 - assert H.edges.order.sum() == 7 - assert round(H.edges.order.mean(), 3) == 2.333 - assert round(H.edges.order.std(), 3) == 0.471 - assert round(H.edges.order.var(), 3) == 0.222 - - -def test_stats_items(diedgelist2): - d = {0: 2, 1: 2, 2: 3} - H = xgi.DiHypergraph(diedgelist2) - for e, s in H.edges.order.items(): - assert d[e] == s - - -def test_stats_are_views(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - es = H.edges.order - assert es.asdict() == {0: 2, 1: 2, 2: 3} - H.add_edge(([3, 4, 5], [6])) - assert es.asdict() == {0: 2, 1: 2, 2: 3, 3: 3} - - -def test_different_views(diedgelist1): - H = xgi.DiHypergraph(diedgelist1) - with pytest.raises(KeyError): - H.edges.multi(["order", H.edges([1, 2]).size]).asdict() - with pytest.raises(KeyError): - H.edges.multi(["order", H.edges([1, 2]).attrs("color")]).asdict() - - -def test_user_defined(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - - with pytest.raises(AttributeError): - H.user_order - with pytest.raises(AttributeError): - H.edges.user_order - - @xgi.diedgestat_func - def user_order(net, bunch): - return {n: 10 * net.order(n) for n in bunch} - - vals = {n: 10 * H.order(n) for n in H.edges} - assert H.user_order() == vals - assert H.edges.user_order.asdict() == vals - assert H.edges.user_order.aslist() == [vals[n] for n in H.edges] - assert H.edges.filterby("order", 2).user_order.asdict() == {0: 20, 1: 20} - - -def test_view_val(diedgelist1, diedgelist2): - H = xgi.DiHypergraph(diedgelist1) - assert H.edges.order._val == {0: 3, 1: 3} - assert H.edges([1]).order._val == {1: 3} - - H = xgi.DiHypergraph(diedgelist2) - assert H.edges.order._val == {0: 2, 1: 2, 2: 3} - assert H.edges([1, 2]).order._val == {1: 2, 2: 3} - - -# test the pre-defined edgestat methods -def test_attrs(dihyperwithattrs): - c = dihyperwithattrs.edges.attrs("color") - assert c.asdict() == {0: "yellow", 1: "red", 2: "blue"} - c = dihyperwithattrs.edges.attrs("age", missing=100) - assert c.asdict() == {0: 100, 1: 20, 2: 2} - c = dihyperwithattrs.edges.attrs() - assert c.asdict() == { - 0: {"color": "yellow", "name": "zebra"}, - 1: {"color": "red", "name": "orangutan", "age": 20}, - 2: {"color": "blue", "name": "fish", "age": 2}, - } - with pytest.raises(ValueError): - dihyperwithattrs.edges.attrs(attr=100).asdict() +### di-edge stat specific tests def test_order(diedgelist2): H = xgi.DiHypergraph(diedgelist2) assert H.edges.order.asdict() == {0: 2, 1: 2, 2: 3} - assert H.edges.order(degree=1).asdict() == {0: 0, 1: -1, 2: 1} def test_size(diedgelist2): H = xgi.DiHypergraph(diedgelist2) assert H.edges.size.asdict() == {0: 3, 1: 3, 2: 4} - assert H.edges.size(degree=1).asdict() == {0: 1, 1: 0, 2: 2} @@ -144,7 +23,6 @@ def test_tail_order(diedgelist1, diedgelist2): H = xgi.DiHypergraph(diedgelist2) assert H.edges.tail_order.asdict() == {0: 1, 1: 1, 2: 2} - assert H.edges.tail_order(degree=1).asdict() == {0: 0, 1: -1, 2: 0} @@ -154,7 +32,6 @@ def test_tail_size(diedgelist1, diedgelist2): H = xgi.DiHypergraph(diedgelist2) assert H.edges.tail_size.asdict() == {0: 2, 1: 2, 2: 3} - assert H.edges.tail_size(degree=1).asdict() == {0: 1, 1: 0, 2: 1} @@ -164,7 +41,6 @@ def test_head_order(diedgelist1, diedgelist2): H = xgi.DiHypergraph(diedgelist2) assert H.edges.head_order.asdict() == {0: 0, 1: 0, 2: 1} - assert H.edges.head_order(degree=1).asdict() == {0: -1, 1: -1, 2: 0} @@ -174,5 +50,4 @@ def test_head_size(diedgelist1, diedgelist2): H = xgi.DiHypergraph(diedgelist2) assert H.edges.head_size.asdict() == {0: 1, 1: 1, 2: 2} - assert H.edges.head_size(degree=1).asdict() == {0: 0, 1: 0, 2: 1} diff --git a/tests/stats/test_dinodestats.py b/tests/stats/test_dinodestats.py index 4d231196d..4a650ea9a 100644 --- a/tests/stats/test_dinodestats.py +++ b/tests/stats/test_dinodestats.py @@ -4,93 +4,7 @@ import xgi - -def test_filterby_wrong_stat(): - H = xgi.DiHypergraph() - with pytest.raises(AttributeError): - H.nodes.filterby("__I_DO_NOT_EXIST__", None) - - -def test_filterby(diedgelist1, diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - assert H.nodes.filterby("degree", 2).in_degree.asdict() == {1: 2, 4: 1} - assert H.nodes.filterby("degree", 2).out_degree.asdict() == {1: 0, 4: 2} - assert H.nodes.filterby("in_degree", 1).degree.asdict() == {0: 1, 3: 1, 4: 2} - assert H.nodes.filterby("out_degree", 1).degree.asdict() == {2: 3, 5: 1} - - H = xgi.DiHypergraph(diedgelist1) - assert H.nodes.filterby("degree", 1).in_degree.asdict() == { - 1: 1, - 2: 1, - 3: 1, - 4: 0, - 5: 1, - 6: 1, - 7: 0, - 8: 0, - } - assert H.nodes.filterby("degree", 1).out_degree.asdict() == { - 1: 0, - 2: 0, - 3: 0, - 4: 1, - 5: 0, - 6: 1, - 7: 1, - 8: 1, - } - assert H.nodes.filterby("in_degree", 1).degree.asdict() == { - 1: 1, - 2: 1, - 3: 1, - 5: 1, - 6: 1, - } - assert H.nodes.filterby("out_degree", 1).degree.asdict() == {8: 1, 4: 1, 6: 1, 7: 1} - - -def test_filterby_with_nodestat(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - assert list(H.nodes.filterby(H.nodes.degree(order=2), 1)) == [0, 4] - - -def test_filterby_modes(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - assert list(H.nodes.filterby("degree", 2)) == [1, 4] - assert list(H.nodes.filterby("degree", 2, "eq")) == [1, 4] - assert list(H.nodes.filterby("degree", 1, "neq")) == [1, 2, 4] - assert list(H.nodes.filterby("degree", 3, "geq")) == [2] - assert list(H.nodes.filterby("degree", 3, "gt")) == [] - assert list(H.nodes.filterby("degree", 0, "leq")) == [] - assert list(H.nodes.filterby("degree", 1, "lt")) == [] - assert set(H.nodes.filterby("degree", (1, 3), "between")) == set(H.nodes) - - -def test_call_filterby(diedgelist1, diedgelist2): - H = xgi.DiHypergraph(diedgelist1) - - filtered = H.nodes([4, 5, 6]).filterby("in_degree", 1).degree - assert filtered.asdict() == {5: 1, 6: 1} - - H = xgi.DiHypergraph(diedgelist2) - assert set(H.nodes([1, 2, 3]).filterby("degree", 2)) == {1} - - -def test_single_node(diedgelist1): - H = xgi.DiHypergraph(diedgelist1) - assert H.degree()[1] == 1 - assert H.nodes.degree[1] == 1 - with pytest.raises(KeyError): - H.degree()[-1] - with pytest.raises(KeyError): - H.nodes.degree[-1] - - -def test_stats_items(diedgelist2): - deg = {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} - H = xgi.DiHypergraph(diedgelist2) - for n, d in H.nodes.degree.items(): - assert deg[n] == d +## di-node stat specific tests def test_degree(diedgelist2): @@ -99,7 +13,6 @@ def test_degree(diedgelist2): assert H.degree() == degs assert H.degree(order=2) == {0: 1, 1: 2, 2: 2, 4: 1, 3: 0, 5: 0} assert H.nodes.degree.asdict() == degs - assert H.nodes.degree.aslist() == list(degs.values()) def test_in_degree(diedgelist2): @@ -108,7 +21,6 @@ def test_in_degree(diedgelist2): assert H.in_degree() == degs assert H.in_degree(order=2) == {0: 1, 1: 2, 2: 1, 4: 0, 3: 0, 5: 0} assert H.nodes.in_degree.asdict() == degs - assert H.nodes.in_degree.aslist() == list(degs.values()) def test_out_degree(diedgelist2): @@ -117,127 +29,3 @@ def test_out_degree(diedgelist2): assert H.out_degree() == degs assert H.out_degree(order=2) == {0: 0, 1: 0, 2: 1, 4: 1, 3: 0, 5: 0} assert H.nodes.out_degree.asdict() == degs - assert H.nodes.out_degree.aslist() == list(degs.values()) - - -def test_aggregates(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - assert H.nodes.degree.max() == 3 - assert H.nodes.degree.min() == 1 - assert H.nodes.degree.sum() == 10 - assert round(H.nodes.degree.mean(), 3) == 1.667 - assert round(H.nodes.degree.std(), 3) == 0.745 - assert round(H.nodes.degree.var(), 3) == 0.556 - - -def test_stats_are_views(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - ns = H.nodes.degree - assert ns.asdict() == {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} - H.add_node(10) - assert ns.asdict() == {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1, 10: 0} - - -def test_after_call_with_args(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - degs = {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} - assert H.nodes.degree.asdict() == degs - - # check when calling without arguments AFTER calling WITH arguments - H.nodes.degree(order=2).asdict() - assert H.nodes.degree.asdict() == degs - - -def test_different_views(diedgelist1): - H = xgi.DiHypergraph(diedgelist1) - with pytest.raises(KeyError): - H.nodes.multi([H.nodes.degree, H.nodes([1, 2]).degree]).asdict() - with pytest.raises(KeyError): - H.nodes.multi([H.nodes.attrs("color"), H.nodes([1, 2]).attrs("color")]).asdict() - - -def test_user_defined(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - - with pytest.raises(AttributeError): - H.user_degree - with pytest.raises(AttributeError): - H.nodes.user_degree - - @xgi.dinodestat_func - def user_degree(net, bunch): - return {n: 10 * net.degree(n) for n in bunch} - - vals = {n: 10 * H.degree(n) for n in H} - assert H.user_degree() == vals - assert H.nodes.user_degree.asdict() == vals - assert H.nodes.user_degree.aslist() == [vals[n] for n in H] - assert ( - list(H.nodes.filterby("user_degree", 20)) - == list(H.nodes.filterby("degree", 2)) - == [1, 4] - ) - assert H.nodes.filterby("degree", 2).user_degree.asdict() == {1: 20, 4: 20} - - -def test_view_val(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - assert H.nodes.degree._val == {0: 1, 1: 2, 2: 3, 4: 2, 3: 1, 5: 1} - assert H.nodes([1, 2]).degree._val == {1: 2, 2: 3} - - -def test_moment(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - deg = H.nodes.degree - assert round(deg.moment(), 3) == 3.333 - assert round(deg.moment(2, center=False), 3) == 3.333 - assert round(deg.moment(2, center=True), 3) == 0.556 - assert round(deg.moment(3, center=False), 3) == 7.667 - assert round(deg.moment(3, center=True), 3) == 0.259 - - -# test pre-defined functions -def test_attrs(dihyperwithattrs): - c = dihyperwithattrs.nodes.attrs("color") - assert c.asdict() == { - 0: "brown", - 1: "red", - 2: "blue", - 3: "yellow", - 4: "red", - 5: "blue", - } - c = dihyperwithattrs.nodes.attrs("age", missing=100) - assert c.asdict() == {0: 100, 1: 100, 2: 100, 3: 100, 4: 20, 5: 2} - c = dihyperwithattrs.nodes.attrs() - assert c.asdict() == { - 0: {"color": "brown", "name": "camel"}, - 1: {"color": "red", "name": "horse"}, - 2: {"color": "blue", "name": "pony"}, - 3: {"color": "yellow", "name": "zebra"}, - 4: {"color": "red", "name": "orangutan", "age": 20}, - 5: {"color": "blue", "name": "fish", "age": 2}, - } - with pytest.raises(ValueError): - dihyperwithattrs.nodes.attrs(attr=100).asdict() - - -def test_degree(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - - assert H.nodes.degree.asdict() == {0: 1, 1: 2, 2: 3, 3: 1, 4: 2, 5: 1} - assert H.nodes.degree(order=2).asdict() == {0: 1, 1: 2, 2: 2, 3: 0, 4: 1, 5: 0} - - -def test_in_degree(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - - assert H.nodes.in_degree.asdict() == {0: 1, 1: 2, 2: 2, 3: 1, 4: 1, 5: 0} - assert H.nodes.in_degree(order=2).asdict() == {0: 1, 1: 2, 2: 1, 3: 0, 4: 0, 5: 0} - - -def test_out_degree(diedgelist2): - H = xgi.DiHypergraph(diedgelist2) - - assert H.nodes.out_degree.asdict() == {0: 0, 1: 0, 2: 1, 3: 0, 4: 2, 5: 1} - assert H.nodes.out_degree(order=2).asdict() == {0: 0, 1: 0, 2: 1, 3: 0, 4: 1, 5: 0} diff --git a/tests/stats/test_edgestats.py b/tests/stats/test_edgestats.py index 2c7825733..27941f8e0 100644 --- a/tests/stats/test_edgestats.py +++ b/tests/stats/test_edgestats.py @@ -3,133 +3,42 @@ import xgi +### edge stat specific tests -def test_filterby_wrong_stat(): - H = xgi.Hypergraph() - with pytest.raises(AttributeError): - H.edges.filterby("__I_DO_NOT_EXIST__", None) - -def test_filterby(edgelist1, edgelist8): +def test_size(edgelist1, edgelist8): H = xgi.Hypergraph(edgelist1) - assert H.edges.filterby("order", 2).size.asdict() == {0: 3, 3: 3} - assert H.edges.filterby("size", 2).order.asdict() == {2: 1} - - H = xgi.Hypergraph(edgelist8) - assert H.edges.filterby("order", 2).size.asdict() == {1: 3, 2: 3, 4: 3, 5: 3, 6: 3} - assert H.edges.filterby("size", 2).order.asdict() == {0: 1, 8: 1, 7: 1} - - -def test_call_filterby(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - assert H.edges([1, 2, 3]).filterby("order", 2).size.asdict() == {3: 3} - - H = xgi.Hypergraph(edgelist8) - assert H.edges([5, 6]).filterby("order", 2).size.asdict() == {5: 3, 6: 3} - - -def test_filterby_with_nodestat(edgelist4, edgelist8): - H = xgi.Hypergraph(edgelist4) - assert list(H.edges.filterby(H.edges.order(degree=2), 2)) == [1] + sizes = {0: 3, 1: 1, 2: 2, 3: 3} + assert H.size() == sizes + assert H.size(degree=2) == {0: 0, 1: 0, 2: 1, 3: 1} + assert H.edges.size.asdict() == sizes H = xgi.Hypergraph(edgelist8) - assert list(H.edges.filterby(H.edges.order(degree=4), 1)) == [2, 3] + sizes = {0: 2, 1: 3, 2: 3, 3: 5, 4: 3, 5: 3, 6: 3, 7: 2, 8: 2} + assert H.size() == sizes + assert H.size(degree=2) == {0: 0, 1: 0, 2: 0, 3: 0, 4: 1, 5: 1, 6: 0, 7: 1, 8: 1} + assert H.edges.size.asdict() == sizes -def test_single_node(edgelist1): +def test_order(edgelist1, edgelist8): H = xgi.Hypergraph(edgelist1) - assert H.order()[1] == 0 - assert H.edges.order[1] == 0 - with pytest.raises(KeyError): - H.order()[-1] - with pytest.raises(KeyError): - H.edges.order[-1] - - -def test_aggregates(edgelist1, edgelist2, edgelist8): - H = xgi.Hypergraph(edgelist1) - assert H.edges.order.max() == 2 - assert H.edges.order.min() == 0 - assert H.edges.order.sum() == 5 - assert round(H.edges.order.mean(), 3) == 1.25 - assert round(H.edges.order.std(), 3) == 0.829 - assert round(H.edges.order.var(), 3) == 0.688 - - H = xgi.Hypergraph(edgelist2) - assert H.edges.order.max() == 2 - assert H.edges.order.min() == 1 - assert H.edges.order.sum() == 4 - assert round(H.edges.order.mean(), 3) == 1.333 - assert round(H.edges.order.std(), 3) == 0.471 - assert round(H.edges.order.var(), 3) == 0.222 + orders = {0: 2, 1: 0, 2: 1, 3: 2} + assert H.order() == orders + assert H.order(degree=2) == {0: -1, 1: -1, 2: 0, 3: 0} + assert H.edges.order().asdict() == orders H = xgi.Hypergraph(edgelist8) - assert H.edges.order.max() == 4 - assert H.edges.order.min() == 1 - assert H.edges.order.sum() == 17 - assert round(H.edges.order.mean(), 3) == 1.889 - assert round(H.edges.order.std(), 3) == 0.875 - assert round(H.edges.order.var(), 3) == 0.765 - - -def test_stats_items(edgelist1): - d = {0: 2, 1: 0, 2: 1, 3: 2} - H = xgi.Hypergraph(edgelist1) - for e, s in H.edges.order.items(): - assert d[e] == s - - -def test_stats_are_views(edgelist1): - H = xgi.Hypergraph(edgelist1) - es = H.edges.order - assert es.asdict() == {0: 2, 1: 0, 2: 1, 3: 2} - H.add_edge([3, 4, 5]) - assert es.asdict() == {0: 2, 1: 0, 2: 1, 3: 2, 4: 2} - - -def test_different_views(edgelist1): - H = xgi.Hypergraph(edgelist1) - with pytest.raises(KeyError): - H.edges.multi(["order", H.edges([1, 2]).size]).asdict() - with pytest.raises(KeyError): - H.edges.multi(["order", H.edges([1, 2]).attrs("color")]).asdict() - - -def test_user_defined(edgelist1): - H = xgi.Hypergraph(edgelist1) - - with pytest.raises(AttributeError): - H.user_order - with pytest.raises(AttributeError): - H.edges.user_order - - @xgi.edgestat_func - def user_order(net, bunch): - return {n: 10 * net.order(n) for n in bunch} - - vals = {n: 10 * H.order(n) for n in H.edges} - assert H.user_order() == vals - assert H.edges.user_order.asdict() == vals - assert H.edges.user_order.aslist() == [vals[n] for n in H.edges] - assert ( - list(H.edges.filterby("user_order", 20)) - == list(H.edges.filterby("order", 2)) - == [0, 3] - ) - assert H.edges.filterby("order", 2).user_order.asdict() == {0: 20, 3: 20} - - -def test_view_val(edgelist1, edgelist2): - H = xgi.Hypergraph(edgelist1) - assert H.edges.order._val == {0: 2, 1: 0, 2: 1, 3: 2} - assert H.edges([1, 2]).order._val == {1: 0, 2: 1} - - H = xgi.Hypergraph(edgelist2) - assert H.edges.order._val == {0: 1, 1: 1, 2: 2} - assert H.edges([1, 2]).order._val == {1: 1, 2: 2} - - -def test_issue_468(): - H = xgi.sunflower(3, 1, 20) - df = pd.DataFrame([[20.0, 3]], columns=["bin_center", "value"]) - assert H.edges.size.ashist().equals(df) + orders = {0: 1, 1: 2, 2: 2, 3: 4, 4: 2, 5: 2, 6: 2, 7: 1, 8: 1} + assert H.order() == orders + assert H.order(degree=2) == { + 0: -1, + 1: -1, + 2: -1, + 3: -1, + 4: 0, + 5: 0, + 6: -1, + 7: 0, + 8: 0, + } + assert H.edges.order().asdict() == orders diff --git a/tests/stats/test_nodestats.py b/tests/stats/test_nodestats.py index b90b71d76..9194df127 100644 --- a/tests/stats/test_nodestats.py +++ b/tests/stats/test_nodestats.py @@ -4,126 +4,7 @@ import xgi - -def test_filterby_wrong_stat(): - H = xgi.Hypergraph() - with pytest.raises(AttributeError): - H.nodes.filterby("__I_DO_NOT_EXIST__", None) - - -def test_filterby(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - assert H.nodes.filterby("degree", 2).average_neighbor_degree.asdict() == {6: 1.0} - assert H.nodes.filterby("average_neighbor_degree", 1.0).degree.asdict() == { - 1: 1, - 2: 1, - 3: 1, - 6: 2, - } - - H = xgi.Hypergraph(edgelist8) - assert H.nodes.filterby("degree", 3).average_neighbor_degree.asdict() == {4: 4.2} - assert H.nodes.filterby("average_neighbor_degree", 4.2).degree.asdict() == {4: 3} - - -def test_filterby_with_nodestat(edgelist4, edgelist8): - H = xgi.Hypergraph(edgelist4) - assert list(H.nodes.filterby(H.nodes.degree(order=2), 2)) == [3] - - H = xgi.Hypergraph(edgelist8) - assert list(H.nodes.filterby(H.nodes.degree(order=2), 2)) == [1, 4, 5] - - -def test_filterby_modes(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - assert list(H.nodes.filterby("degree", 2)) == [6] - assert list(H.nodes.filterby("degree", 2, "eq")) == [6] - assert list(H.nodes.filterby("degree", 1, "neq")) == [6] - assert list(H.nodes.filterby("degree", 2, "geq")) == [6] - assert list(H.nodes.filterby("degree", 2, "gt")) == [] - assert list(H.nodes.filterby("degree", 0, "leq")) == [] - assert list(H.nodes.filterby("degree", 1, "lt")) == [] - assert set(H.nodes.filterby("degree", (1, 3), "between")) == set(H.nodes) - - H = xgi.Hypergraph(edgelist8) - assert set(H.nodes.filterby("degree", 2)) == {5, 6} - assert set(H.nodes.filterby("degree", 2, "eq")) == {5, 6} - assert set(H.nodes.filterby("degree", 2, "neq")) == {0, 1, 2, 3, 4} - assert set(H.nodes.filterby("degree", 5, "geq")) == {0, 1} - assert set(H.nodes.filterby("degree", 5, "gt")) == {0} - assert set(H.nodes.filterby("degree", 2, "leq")) == {5, 6} - assert set(H.nodes.filterby("degree", 2, "lt")) == set() - assert set(H.nodes.filterby("degree", (2, 3), "between")) == {4, 5, 6} - - -def test_call_filterby(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - - filtered = H.nodes([5, 6, 7, 8]).filterby("average_neighbor_degree", 2.0).degree - assert filtered.asdict() == {5: 1} - - filtered = H.nodes([5, 6, 7, 8]).filterby("degree", 2).average_neighbor_degree - assert filtered.asdict() == {6: 1.0} - - H = xgi.Hypergraph(edgelist8) - assert set(H.nodes([1, 2, 3]).filterby("degree", 4)) == {2, 3} - - filtered = H.nodes([1, 2, 3]).filterby("average_neighbor_degree", 4.0).degree - assert filtered.asdict() == {2: 4, 3: 4} - - filtered = H.nodes([1, 2, 3]).filterby("degree", 5).average_neighbor_degree - assert filtered.asdict() == {1: 3.5} - - -def test_filterby_attr(hyperwithattrs): - H = hyperwithattrs - - filtered = H.nodes.filterby_attr("age", 20, "eq") - assert set(filtered) == {4} - - filtered = H.nodes.filterby_attr("age", 2, "neq") - assert set(filtered) == {4} - - filtered = H.nodes.filterby_attr("age", 20, "lt") - assert set(filtered) == {5} - - filtered = H.nodes.filterby_attr("age", 2, "gt") - assert set(filtered) == {4} - - filtered = H.nodes.filterby_attr("age", 20, "leq") - assert set(filtered) == {4, 5} - - filtered = H.nodes.filterby_attr("age", 2, "geq") - assert set(filtered) == {4, 5} - - filtered = H.nodes.filterby_attr("age", [1, 3], "between") - assert set(filtered) == {5} - - filtered = H.nodes.filterby_attr("age", [2, 20], "between") - assert set(filtered) == {4, 5} - - filtered = H.nodes.filterby_attr("age", 2, "leq", 1) - assert set(filtered) == {1, 2, 3, 5} - - filtered = H.nodes.filterby_attr("age", 2, "leq", 10) - assert set(filtered) == {5} - - -def test_single_node(edgelist1): - H = xgi.Hypergraph(edgelist1) - assert H.degree()[1] == 1 - assert H.nodes.degree[1] == 1 - with pytest.raises(KeyError): - H.degree()[-1] - with pytest.raises(KeyError): - H.nodes.degree[-1] - - -def test_stats_items(edgelist1): - deg = {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} - H = xgi.Hypergraph(edgelist1) - for n, d in H.nodes.degree.items(): - assert deg[n] == d +### node stat specific tests def test_degree(edgelist1, edgelist8): @@ -132,14 +13,12 @@ def test_degree(edgelist1, edgelist8): assert H.degree() == degs assert H.degree(order=2) == {1: 1, 2: 1, 3: 1, 4: 0, 5: 0, 6: 1, 7: 1, 8: 1} assert H.nodes.degree.asdict() == degs - assert H.nodes.degree.aslist() == list(degs.values()) H = xgi.Hypergraph(edgelist8) degs = {0: 6, 1: 5, 2: 4, 3: 4, 4: 3, 5: 2, 6: 2} assert H.degree() == degs assert H.degree(order=2) == {0: 3, 1: 2, 2: 3, 3: 3, 4: 2, 5: 2, 6: 0} assert H.nodes.degree.asdict() == degs - assert H.nodes.degree.aslist() == list(degs.values()) def test_average_neighbor_degree(edgelist1, edgelist8): @@ -147,13 +26,11 @@ def test_average_neighbor_degree(edgelist1, edgelist8): vals = {1: 1.0, 2: 1.0, 3: 1.0, 4: 0, 5: 2.0, 6: 1.0, 7: 1.5, 8: 1.5} assert H.average_neighbor_degree() == vals assert H.nodes.average_neighbor_degree().asdict() == vals - assert H.nodes.average_neighbor_degree().aslist() == list(vals.values()) H = xgi.Hypergraph(edgelist8) vals = {0: 3.6, 1: 3.5, 2: 4.0, 3: 4.0, 4: 4.2, 5: 4.0, 6: 5.5} assert H.average_neighbor_degree() == vals assert H.nodes.average_neighbor_degree().asdict() == vals - assert H.nodes.average_neighbor_degree().aslist() == list(vals.values()) def test_clustering_coefficient(): @@ -161,20 +38,18 @@ def test_clustering_coefficient(): H = xgi.Hypergraph() assert H.clustering_coefficient() == dict() - assert H.nodes.clustering_coefficient().aslist() == [] assert H.nodes.clustering_coefficient().asdict() == dict() # no edges H.add_nodes_from(range(3)) - assert H.nodes.clustering_coefficient().aslist() == [0, 0, 0] assert H.nodes.clustering_coefficient().asdict() == {0: 0, 1: 0, 2: 0} # edges edges = [[1, 2, 3], [2, 3, 4, 5], [3, 4, 5]] H = xgi.Hypergraph(edges) - assert np.allclose( - H.nodes.clustering_coefficient.aslist(), np.array([1, 2 / 3, 2 / 3, 1, 1]) - ) + val = H.nodes.clustering_coefficient.asdict() + true_val = {1: 1, 2: 2 / 3, 3: 2 / 3, 4: 1, 5: 1} + assert val == true_val def test_local_clustering_coefficient(): @@ -182,20 +57,18 @@ def test_local_clustering_coefficient(): H = xgi.Hypergraph() assert H.local_clustering_coefficient() == dict() - assert H.nodes.local_clustering_coefficient().aslist() == [] assert H.nodes.local_clustering_coefficient().asdict() == dict() # no edges H.add_nodes_from(range(3)) - assert H.nodes.local_clustering_coefficient().aslist() == [0, 0, 0] assert H.nodes.local_clustering_coefficient().asdict() == {0: 0, 1: 0, 2: 0} # edges edges = [[1, 2, 3], [2, 3, 4, 5], [3, 4, 5]] H = xgi.Hypergraph(edges) - assert np.allclose( - H.nodes.local_clustering_coefficient.aslist(), np.array([0, 0, 0.25, 0, 0]) - ) + val = H.nodes.local_clustering_coefficient.asdict() + true_val = {1: 0, 2: 0, 3: 0.25, 4: 0, 5: 0} + assert val == true_val def test_two_node_clustering_coefficient(): @@ -203,77 +76,24 @@ def test_two_node_clustering_coefficient(): H = xgi.Hypergraph() assert H.two_node_clustering_coefficient() == dict() - assert H.nodes.two_node_clustering_coefficient().aslist() == [] assert H.nodes.two_node_clustering_coefficient().asdict() == dict() # no edges H.add_nodes_from(range(3)) - assert H.nodes.two_node_clustering_coefficient().aslist() == [0, 0, 0] assert H.nodes.two_node_clustering_coefficient().asdict() == {0: 0, 1: 0, 2: 0} # edges edges = [[1, 2, 3], [2, 3, 4, 5], [3, 4, 5]] H = xgi.Hypergraph(edges) - assert np.allclose( - H.nodes.two_node_clustering_coefficient(kind="union").aslist(), - np.array( - [ - 0.41666666666666663, - 0.45833333333333326, - 0.5833333333333333, - 0.6666666666666666, - 0.6666666666666666, - ] - ), - ) - - -def test_aggregates(edgelist1, edgelist2, edgelist8): - H = xgi.Hypergraph(edgelist1) - assert H.nodes.degree.max() == 2 - assert H.nodes.degree.min() == 1 - assert H.nodes.degree.argmax() == 6 - assert H.nodes.degree.argmin() == 1 - assert H.nodes.degree.argsort() == list(H.nodes.filterby("degree", 1)) + list( - H.nodes.filterby("degree", 2) - ) - assert H.nodes.degree.argsort(reverse=True) == list( - H.nodes.filterby("degree", 2) - ) + list(H.nodes.filterby("degree", 1)) - assert H.nodes.degree.sum() == 9 - assert round(H.nodes.degree.mean(), 3) == 1.125 - assert round(H.nodes.degree.std(), 3) == 0.331 - assert round(H.nodes.degree.var(), 3) == 0.109 - - H = xgi.Hypergraph(edgelist2) - assert H.nodes.degree.max() == 2 - assert H.nodes.degree.min() == 1 - assert H.nodes.degree.argmax() == 4 - assert H.nodes.degree.argmin() == 1 - assert H.nodes.degree.argsort() == list(H.nodes.filterby("degree", 1)) + list( - H.nodes.filterby("degree", 2) - ) - assert H.nodes.degree.sum() == 7 - assert round(H.nodes.degree.mean(), 3) == 1.167 - assert round(H.nodes.degree.std(), 3) == 0.373 - assert round(H.nodes.degree.var(), 3) == 0.139 - - H = xgi.Hypergraph(edgelist8) - assert H.nodes.degree.max() == 6 - assert H.nodes.degree.min() == 2 - assert H.nodes.degree.argmax() == 0 - assert H.nodes.degree.argmin() == 5 - assert H.nodes.degree.argsort() == list(H.nodes.filterby("degree", 2)) + list( - H.nodes.filterby("degree", 3) - ) + list(H.nodes.filterby("degree", 4)) + list( - H.nodes.filterby("degree", 5) - ) + list( - H.nodes.filterby("degree", 6) - ) - assert H.nodes.degree.sum() == 26 - assert round(H.nodes.degree.mean(), 3) == 3.714 - assert round(H.nodes.degree.std(), 3) == 1.385 - assert round(H.nodes.degree.var(), 3) == 1.918 + val = H.nodes.two_node_clustering_coefficient(kind="union").asdict() + true_val = { + 1: 0.41666666666666663, + 2: 0.45833333333333326, + 3: 0.5833333333333333, + 4: 0.6666666666666666, + 5: 0.6666666666666666, + } + assert val == true_val def test_attrs(hyperwithattrs, attr1, attr2, attr3, attr4, attr5): @@ -286,7 +106,6 @@ def test_attrs(hyperwithattrs, attr1, attr2, attr3, attr4, attr5): 5: attr5, } assert H.nodes.attrs.asdict() == attrs - assert H.nodes.attrs.aslist() == list(attrs.values()) assert H.nodes.attrs("color").asdict() == {n: H._node_attr[n]["color"] for n in H} filtered = H.nodes.filterby_attr("color", "blue").attrs @@ -300,363 +119,3 @@ def test_attrs(hyperwithattrs, attr1, attr2, attr3, attr4, attr5): with pytest.raises(ValueError): H.nodes.attrs(-1).asdict() - - -def test_stats_are_views(edgelist1): - H = xgi.Hypergraph(edgelist1) - ns = H.nodes.degree - assert ns.asdict() == {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} - H.add_node(10) - assert ns.asdict() == {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1, 10: 0} - H.add_edge([1, 2, 10, 20]) - assert ns.asdict() == {1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1, 10: 1, 20: 1} - - -def test_after_call_with_args(edgelist1): - H = xgi.Hypergraph(edgelist1) - degs = {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} - assert H.nodes.degree.asdict() == degs - - # check when calling without arguments AFTER calling WITH arguments - H.nodes.degree(order=2).asdict() - assert H.nodes.degree.asdict() == degs - - -def test_multi_stats_order(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - assert H.nodes.multi(["degree", "average_neighbor_degree"]).asdict() == { - 1: {"degree": 1, "average_neighbor_degree": 1.0}, - 2: {"degree": 1, "average_neighbor_degree": 1.0}, - 3: {"degree": 1, "average_neighbor_degree": 1.0}, - 4: {"degree": 1, "average_neighbor_degree": 0}, - 5: {"degree": 1, "average_neighbor_degree": 2.0}, - 6: {"degree": 2, "average_neighbor_degree": 1.0}, - 7: {"degree": 1, "average_neighbor_degree": 1.5}, - 8: {"degree": 1, "average_neighbor_degree": 1.5}, - } - assert H.nodes.multi(["average_neighbor_degree", "degree"]).asdict() == { - 1: {"average_neighbor_degree": 1.0, "degree": 1}, - 2: {"average_neighbor_degree": 1.0, "degree": 1}, - 3: {"average_neighbor_degree": 1.0, "degree": 1}, - 4: {"average_neighbor_degree": 0, "degree": 1}, - 5: {"average_neighbor_degree": 2.0, "degree": 1}, - 6: {"average_neighbor_degree": 1.0, "degree": 2}, - 7: {"average_neighbor_degree": 1.5, "degree": 1}, - 8: {"average_neighbor_degree": 1.5, "degree": 1}, - } - - H = xgi.Hypergraph(edgelist8) - assert H.nodes.multi(["degree", "average_neighbor_degree"]).asdict() == { - 0: {"degree": 6, "average_neighbor_degree": 3.6}, - 1: {"degree": 5, "average_neighbor_degree": 3.5}, - 2: {"degree": 4, "average_neighbor_degree": 4.0}, - 3: {"degree": 4, "average_neighbor_degree": 4.0}, - 4: {"degree": 3, "average_neighbor_degree": 4.2}, - 5: {"degree": 2, "average_neighbor_degree": 4.0}, - 6: {"degree": 2, "average_neighbor_degree": 5.5}, - } - assert H.nodes.multi(["average_neighbor_degree", "degree"]).asdict() == { - 0: {"average_neighbor_degree": 3.6, "degree": 6}, - 1: {"average_neighbor_degree": 3.5, "degree": 5}, - 2: {"average_neighbor_degree": 4.0, "degree": 4}, - 3: {"average_neighbor_degree": 4.0, "degree": 4}, - 4: {"average_neighbor_degree": 4.2, "degree": 3}, - 5: {"average_neighbor_degree": 4.0, "degree": 2}, - 6: {"average_neighbor_degree": 5.5, "degree": 2}, - } - - -def test_multi_stats_with_parameters(edgelist1): - H = xgi.Hypergraph(edgelist1) - multi = H.nodes.multi(["degree", H.nodes.degree(order=2)]) - assert multi.asdict() == { - 1: {"degree": 1, "degree(order=2)": 1}, - 2: {"degree": 1, "degree(order=2)": 1}, - 3: {"degree": 1, "degree(order=2)": 1}, - 4: {"degree": 1, "degree(order=2)": 0}, - 5: {"degree": 1, "degree(order=2)": 0}, - 6: {"degree": 2, "degree(order=2)": 1}, - 7: {"degree": 1, "degree(order=2)": 1}, - 8: {"degree": 1, "degree(order=2)": 1}, - } - - -def test_multi_stats_dict_transpose(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - multi = H.nodes.multi( - ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] - ) - assert multi.asdict() == { - 1: {"average_neighbor_degree": 1.0, "degree": 1, "degree(order=2)": 1}, - 2: {"average_neighbor_degree": 1.0, "degree": 1, "degree(order=2)": 1}, - 3: {"average_neighbor_degree": 1.0, "degree": 1, "degree(order=2)": 1}, - 4: {"average_neighbor_degree": 0, "degree": 1, "degree(order=2)": 0}, - 5: {"average_neighbor_degree": 2.0, "degree": 1, "degree(order=2)": 0}, - 6: {"average_neighbor_degree": 1.0, "degree": 2, "degree(order=2)": 1}, - 7: {"average_neighbor_degree": 1.5, "degree": 1, "degree(order=2)": 1}, - 8: {"average_neighbor_degree": 1.5, "degree": 1, "degree(order=2)": 1}, - } - assert multi.asdict(transpose=True) == { - "average_neighbor_degree": { - 1: 1.0, - 2: 1.0, - 3: 1.0, - 4: 0, - 5: 2.0, - 6: 1.0, - 7: 1.5, - 8: 1.5, - }, - "degree": {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1}, - "degree(order=2)": {1: 1, 2: 1, 3: 1, 4: 0, 5: 0, 6: 1, 7: 1, 8: 1}, - } - - H = xgi.Hypergraph(edgelist8) - multi = H.nodes.multi( - ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] - ) - assert multi.asdict() == { - 0: {"average_neighbor_degree": 3.6, "degree": 6, "degree(order=2)": 3}, - 1: {"average_neighbor_degree": 3.5, "degree": 5, "degree(order=2)": 2}, - 2: {"average_neighbor_degree": 4.0, "degree": 4, "degree(order=2)": 3}, - 3: {"average_neighbor_degree": 4.0, "degree": 4, "degree(order=2)": 3}, - 4: {"average_neighbor_degree": 4.2, "degree": 3, "degree(order=2)": 2}, - 5: {"average_neighbor_degree": 4.0, "degree": 2, "degree(order=2)": 2}, - 6: {"average_neighbor_degree": 5.5, "degree": 2, "degree(order=2)": 0}, - } - assert multi.asdict(transpose=True) == { - "average_neighbor_degree": { - 0: 3.6, - 1: 3.5, - 2: 4.0, - 3: 4.0, - 4: 4.2, - 5: 4.0, - 6: 5.5, - }, - "degree": {0: 6, 1: 5, 2: 4, 3: 4, 4: 3, 5: 2, 6: 2}, - "degree(order=2)": {0: 3, 1: 2, 2: 3, 3: 3, 4: 2, 5: 2, 6: 0}, - } - - -def test_multi_stats_dict_list(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - multi = H.nodes.multi(["average_neighbor_degree", "degree"]) - assert multi.asdict(list) == { - 1: [1.0, 1], - 2: [1.0, 1], - 3: [1.0, 1], - 4: [0, 1], - 5: [2.0, 1], - 6: [1.0, 2], - 7: [1.5, 1], - 8: [1.5, 1], - } - - H = xgi.Hypergraph(edgelist8) - multi = H.nodes.multi(["average_neighbor_degree", "degree"]) - assert multi.asdict(list) == { - 0: [3.6, 6], - 1: [3.5, 5], - 2: [4.0, 4], - 3: [4.0, 4], - 4: [4.2, 3], - 5: [4.0, 2], - 6: [5.5, 2], - } - - -def test_multi_stats_list_dict(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - multi = H.nodes.multi(["average_neighbor_degree", "degree"]) - assert multi.aslist(dict) == [ - {"average_neighbor_degree": 1.0, "degree": 1}, - {"average_neighbor_degree": 1.0, "degree": 1}, - {"average_neighbor_degree": 1.0, "degree": 1}, - {"average_neighbor_degree": 0, "degree": 1}, - {"average_neighbor_degree": 2.0, "degree": 1}, - {"average_neighbor_degree": 1.0, "degree": 2}, - {"average_neighbor_degree": 1.5, "degree": 1}, - {"average_neighbor_degree": 1.5, "degree": 1}, - ] - - H = xgi.Hypergraph(edgelist8) - multi = H.nodes.multi(["average_neighbor_degree", "degree"]) - assert multi.aslist(dict) == [ - {"average_neighbor_degree": 3.6, "degree": 6}, - {"average_neighbor_degree": 3.5, "degree": 5}, - {"average_neighbor_degree": 4.0, "degree": 4}, - {"average_neighbor_degree": 4.0, "degree": 4}, - {"average_neighbor_degree": 4.2, "degree": 3}, - {"average_neighbor_degree": 4.0, "degree": 2}, - {"average_neighbor_degree": 5.5, "degree": 2}, - ] - - -def test_multi_stats_list_transpose(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - multi = H.nodes.multi( - ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] - ) - assert multi.aslist() == [ - [1.0, 1, 1], - [1.0, 1, 1], - [1.0, 1, 1], - [0, 1, 0], - [2.0, 1, 0], - [1.0, 2, 1], - [1.5, 1, 1], - [1.5, 1, 1], - ] - assert multi.aslist(transpose=True) == [ - [1.0, 1.0, 1.0, 0, 2.0, 1.0, 1.5, 1.5], - [1, 1, 1, 1, 1, 2, 1, 1], - [1, 1, 1, 0, 0, 1, 1, 1], - ] - - H = xgi.Hypergraph(edgelist8) - multi = H.nodes.multi( - ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] - ) - assert multi.aslist() == [ - [3.6, 6, 3], - [3.5, 5, 2], - [4.0, 4, 3], - [4.0, 4, 3], - [4.2, 3, 2], - [4.0, 2, 2], - [5.5, 2, 0], - ] - assert multi.aslist(transpose=True) == [ - [3.6, 3.5, 4.0, 4.0, 4.2, 4.0, 5.5], - [6, 5, 4, 4, 3, 2, 2], - [3, 2, 3, 3, 2, 2, 0], - ] - - -def test_multi_stats_aspandas(edgelist1, edgelist8): - H = xgi.Hypergraph(edgelist1) - multi = H.nodes.multi( - ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] - ) - df = pd.DataFrame(multi.asdict(transpose=True)) - pd.testing.assert_frame_equal(df, multi.aspandas(), check_like=True) - - H = xgi.Hypergraph(edgelist8) - multi = H.nodes.multi( - ["average_neighbor_degree", "degree", H.nodes.degree(order=2)] - ) - df = pd.DataFrame(multi.asdict(transpose=True)) - pd.testing.assert_frame_equal(df, multi.aspandas()) - - -def test_multi_with_attrs(hyperwithattrs): - H = hyperwithattrs - multi = H.nodes.multi([H.nodes.attrs("color")]) - assert multi.asdict() == { - 1: {"attrs(color)": "red"}, - 2: {"attrs(color)": "blue"}, - 3: {"attrs(color)": "yellow"}, - 4: {"attrs(color)": "red"}, - 5: {"attrs(color)": "blue"}, - } - assert multi.asdict(transpose=True) == { - "attrs(color)": {1: "red", 2: "blue", 3: "yellow", 4: "red", 5: "blue"} - } - - multi = H.nodes.multi([H.nodes.degree, H.nodes.attrs("color")]) - assert multi.asdict() == { - 1: {"degree": 1, "attrs(color)": "red"}, - 2: {"degree": 2, "attrs(color)": "blue"}, - 3: {"degree": 3, "attrs(color)": "yellow"}, - 4: {"degree": 2, "attrs(color)": "red"}, - 5: {"degree": 2, "attrs(color)": "blue"}, - } - assert multi.asdict(list) == { - 1: [1, "red"], - 2: [2, "blue"], - 3: [3, "yellow"], - 4: [2, "red"], - 5: [2, "blue"], - } - - -def test_missing_attrs(hyperwithattrs): - H = hyperwithattrs - H.add_node(10) - assert H.nodes.attrs("color").asdict() == { - 1: "red", - 2: "blue", - 3: "yellow", - 4: "red", - 5: "blue", - 10: None, - } - assert H.nodes.attrs("color", missing="missingval").asdict() == { - 1: "red", - 2: "blue", - 3: "yellow", - 4: "red", - 5: "blue", - 10: "missingval", - } - - -def test_different_views(edgelist1): - H = xgi.Hypergraph(edgelist1) - with pytest.raises(KeyError): - H.nodes.multi([H.nodes.degree, H.nodes([1, 2]).degree]).asdict() - with pytest.raises(KeyError): - H.nodes.multi([H.nodes.attrs("color"), H.nodes([1, 2]).attrs("color")]).asdict() - - -def test_user_defined(edgelist1): - H = xgi.Hypergraph(edgelist1) - - with pytest.raises(AttributeError): - H.user_degree - with pytest.raises(AttributeError): - H.nodes.user_degree - - @xgi.nodestat_func - def user_degree(net, bunch): - return {n: 10 * net.degree(n) for n in bunch} - - vals = {n: 10 * H.degree(n) for n in H} - assert H.user_degree() == vals - assert H.nodes.user_degree.asdict() == vals - assert H.nodes.user_degree.aslist() == [vals[n] for n in H] - assert ( - list(H.nodes.filterby("user_degree", 20)) - == list(H.nodes.filterby("degree", 2)) - == [6] - ) - assert H.nodes.filterby("degree", 2).user_degree.asdict() == {6: 20} - - -def test_view_val(edgelist1, edgelist2): - H = xgi.Hypergraph(edgelist1) - assert H.nodes.degree._val == {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 2, 7: 1, 8: 1} - assert H.nodes([1, 2, 3]).degree._val == {1: 1, 2: 1, 3: 1} - - H = xgi.Hypergraph(edgelist2) - assert H.nodes.degree._val == {1: 1, 2: 1, 3: 1, 4: 2, 5: 1, 6: 1} - assert H.nodes([4, 5, 6]).degree._val == {4: 2, 5: 1, 6: 1} - - -def test_moment(edgelist1, edgelist6): - H = xgi.Hypergraph(edgelist1) - deg = H.nodes.degree - assert round(deg.moment(), 3) == 1.375 - assert round(deg.moment(2, center=False), 3) == 1.375 - assert round(deg.moment(2, center=True), 3) == 0.109 - assert round(deg.moment(3, center=False), 3) == 1.875 - assert round(deg.moment(3, center=True), 3) == 0.082 - - H = xgi.Hypergraph(edgelist6) - deg = H.edges.size - assert round(deg.moment(), 3) == 9.0 - assert round(deg.moment(2, center=False), 3) == 9.0 - assert round(deg.moment(2, center=True), 3) == 0.0 - assert round(deg.moment(3, center=False), 3) == 27.0 - assert round(deg.moment(3, center=True), 3) == 0.0 diff --git a/xgi/stats/edgestats.py b/xgi/stats/edgestats.py index 9b034d63e..68e8ca392 100644 --- a/xgi/stats/edgestats.py +++ b/xgi/stats/edgestats.py @@ -177,8 +177,7 @@ def size(net, bunch, degree=None): return {e: len(net._edge[e]) for e in bunch} else: return { - e: len(n for n in net._edge[e] if len(net._node[n]) == degree) - for e in bunch + e: sum(len(net._node[n]) == degree for n in net._edge[e]) for e in bunch }