Repository: graspologic-org/graspologic

Issue:
fix test_omni_matrix_random()
```
def test_omni_matrix_random():
    expected_output = np.array(
        [
            [0.0, 1.0, 1.0, 0.0, 0.5, 0.5],
            [1.0, 0.0, 1.0, 0.5, 0.0, 1.0],
            [1.0, 1.0, 0.0, 0.5, 1.0, 0.0],
            [0.0, 0.5, 0.5, 0.0, 0.0, 0.0],
            [0.5, 0.0, 1.0, 0.0, 0.0, 1.0],
            [0.5, 1.0, 0.0, 0.0, 1.0, 0.0],
        ]
    )

    np.random.seed(4)
    graphs = [er_np(3, 0.5) for _ in range(2)]

    A = _get_omni_matrix(graphs)
    assert_allclose(A, expected_output)
```

Though the random seed is set this test is dependent on the implementation of ```er_np``` function, changing that implementation breaks this test. Should be rewritten to not use ```er_np``` unless I am missing something @j1c ?


Discussion:

Resolving patch:
diff --git a/graspy/simulations/simulations.py b/graspy/simulations/simulations.py
--- a/graspy/simulations/simulations.py
+++ b/graspy/simulations/simulations.py
@@ -70,7 +70,7 @@ def sample_edges(P, directed=False, loops=False):
         return A - np.diag(np.diag(A))
 
 
-def er_np(n, p, directed=False, loops=False, wt=1, wtargs=None):
+def er_np(n, p, directed=False, loops=False, wt=1, wtargs=None, dc=None, dc_kws={}):
     r"""
     Samples a Erdos Renyi (n, p) graph with specified edge probability.
 
@@ -80,7 +80,7 @@ def er_np(n, p, directed=False, loops=False, wt=1, wtargs=None):
     Parameters
     ----------
     n: int
-        Number of vertices
+       Number of vertices
     p: float
         Probability of an edge existing between two vertices, between 0 and 1.
     directed: boolean, optional (default=False)
@@ -96,50 +96,46 @@ def er_np(n, p, directed=False, loops=False, wt=1, wtargs=None):
     wtargs: dictionary, optional (default=None)
         Optional arguments for parameters that can be passed
         to weight function ``wt``.
+    dc: function or array-like, shape (n_vertices)
+        `dc` is used to generate a degree-corrected Erdos Renyi Model in
+        which each node in the graph has a parameter to specify its expected degree
+        relative to other nodes.
+
+        - function:
+            should generate a non-negative number to be used as a degree correction to
+            create a heterogenous degree distribution. A weight will be generated for
+            each vertex, normalized so that the sum of weights is 1.
+        - array-like of scalars, shape (n_vertices):
+            The weights should sum to 1; otherwise, they will be
+            normalized and a warning will be thrown. The scalar associated with each
+            vertex is the node's relative expected degree.
+
+    dc_kws: dictionary
+        Ignored if `dc` is none or array of scalar.
+        If `dc` is a function, `dc_kws` corresponds to its named arguments.
+        If not specified, in either case all functions will assume their default
+        parameters.
+
 
     Returns
     -------
     A : ndarray, shape (n, n)
         Sampled adjacency matrix
     """
-    if not np.issubdtype(type(p), np.floating):
-        raise TypeError("p is not of type float.")
-    elif p < 0:
-        msg = "You have passed a probability, {}, less than 0."
-        msg = msg.format(float(p))
-        raise ValueError(msg)
-    elif p > 1:
-        msg = "You have passed a probability, {}, greater than 1."
-        msg = msg.format(float(p))
-        raise ValueError(msg)
+    if isinstance(dc, (list, np.ndarray)) and all(callable(f) for f in dc):
+        raise TypeError("dc is not of type function or array-like of scalars")
     if not np.issubdtype(type(n), np.integer):
         raise TypeError("n is not of type int.")
-    elif n <= 0:
-        msg = "n must be > 0."
-        raise ValueError(msg)
-    if type(directed) is not bool:
-        raise TypeError("directed is not of type bool.")
+    if not np.issubdtype(type(p), np.floating):
+        raise TypeError("p is not of type float.")
     if type(loops) is not bool:
         raise TypeError("loops is not of type bool.")
-
-    # check weight function
-    if not np.issubdtype(type(wt), np.number):
-        if not callable(wt):
-            raise TypeError("You have not passed a function for wt.")
-
-    probs = np.ones((n, n)) * p
-    A = sample_edges(probs, directed, loops)
-
-    if not np.issubdtype(type(wt), np.number):
-        weights = wt(size=int(A.sum()), **wtargs)
-        A[A == 1] = weights
-    else:
-        A *= wt
-
-    if not directed:
-        A = symmetrize(A)
-
-    return A
+    if type(directed) is not bool:
+        raise TypeError("directed is not of type bool.")
+    n_sbm = np.array([n])
+    p_sbm = np.array([[p]])
+    g = sbm(n_sbm, p_sbm, directed, loops, wt, wtargs, dc, dc_kws)
+    return g
 
 
 def er_nm(n, m, directed=False, loops=False, wt=1, wtargs=None):
@@ -287,29 +283,29 @@ def sbm(n, p, directed=False, loops=False, wt=1, wtargs=None, dc=None, dc_kws={}
         to pass to the weight function. If Wt is an array-like, Wtargs[i, j] 
         corresponds to trailing arguments to pass to Wt[i, j].
     dc: function or array-like, shape (n_vertices) or (n_communities), optional
-        `dc` is used to generate a degree-corrected stochastic block model [1] in 
+        `dc` is used to generate a degree-corrected stochastic block model [1] in
         which each node in the graph has a parameter to specify its expected degree
         relative to other nodes within its community.
 
-        - function: 
-            should generate a non-negative number to be used as a degree correction to 
+        - function:
+            should generate a non-negative number to be used as a degree correction to
             create a heterogenous degree distribution. A weight will be generated for
-            each vertex, normalized so that the sum of weights in each block is 1. 
-        - array-like of functions, shape (n_communities): 
-            Each function will generate the degree distribution for its respective 
-            community. 
-        - array-like of scalars, shape (n_vertices): 
-            The weights in each block should sum to 1; otherwise, they will be 
+            each vertex, normalized so that the sum of weights in each block is 1.
+        - array-like of functions, shape (n_communities):
+            Each function will generate the degree distribution for its respective
+            community.
+        - array-like of scalars, shape (n_vertices):
+            The weights in each block should sum to 1; otherwise, they will be
             normalized and a warning will be thrown. The scalar associated with each
-            vertex is the node's relative expected degree within its community. 
-    
+            vertex is the node's relative expected degree within its community.
+
     dc_kws: dictionary or array-like, shape (n_communities), optional
         Ignored if `dc` is none or array of scalar.
-        If `dc` is a function, `dc_kws` corresponds to its named arguments. 
-        If `dc` is an array-like of functions, `dc_kws` should be an array-like, shape 
-        (n_communities), of dictionary. Each dictionary is the named arguments 
-        for the corresponding function for that community. 
-        If not specified, in either case all functions will assume their default 
+        If `dc` is a function, `dc_kws` corresponds to its named arguments.
+        If `dc` is an array-like of functions, `dc_kws` should be an array-like, shape
+        (n_communities), of dictionary. Each dictionary is the named arguments
+        for the corresponding function for that community.
+        If not specified, in either case all functions will assume their default
         parameters.
 
     References


Test patch:
diff --git a/tests/test_omni.py b/tests/test_omni.py
old mode 100644
new mode 100755
--- a/tests/test_omni.py
+++ b/tests/test_omni.py
@@ -1,13 +1,12 @@
-import pytest
 import numpy as np
-import networkx as nx
-from numpy import array_equal, allclose
-from numpy.testing import assert_allclose
+import pytest
+from numpy import allclose, array_equal
 from numpy.linalg import norm
+from numpy.testing import assert_allclose
 
 from graspy.embed.omni import OmnibusEmbed, _get_omni_matrix
-from graspy.simulations.simulations import er_np, er_nm
-from graspy.utils.utils import symmetrize, is_symmetric
+from graspy.simulations.simulations import er_nm, er_np
+from graspy.utils.utils import is_symmetric, symmetrize
 
 
 def generate_data(n, seed=1):
@@ -61,8 +60,11 @@ def test_omni_matrix_random():
     )
 
     np.random.seed(4)
-    graphs = [er_np(3, 0.5) for _ in range(2)]
-
+    dat_list = (
+        [[0.0, 1.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 0.0]],
+        [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [0.0, 1.0, 0.0]],
+    )
+    graphs = np.array(dat_list)
     A = _get_omni_matrix(graphs)
     assert_allclose(A, expected_output)
 
diff --git a/tests/test_sims.py b/tests/test_sims.py
--- a/tests/test_sims.py
+++ b/tests/test_sims.py
@@ -337,6 +337,10 @@ def test_bad_inputs(self):
             wt = np.random
             er_np(self.n, self.p, wt=wt)
 
+        with self.assertRaises(TypeError):
+            dc = np.array(np.random.power)
+            er_np(self.n, self.p, dc=dc)
+
 
 class Test_WSBM(unittest.TestCase):
     @classmethod