Ejemplo n.º 1
0
    def euclidean_gen(A, D, m, eta, model_var):
        mseed = np.size(np.where(A.flat)) // 2

        if type(model_var) == tuple:
            mv1, mv2 = model_var
        else:
            mv1, mv2 = model_var, model_var

        if mv1 != mv2:
            raise BCTParamError('Too many hyperparameters specified')

        if mv1 in ('powerlaw', 'power_law'):
            Fd = D**eta
        elif mv1 in ('exponential', ):
            Fd = np.exp(eta**D)

        u, v = np.where(np.triu(np.ones((n, n)), 1))
        P = Fd * np.logical_not(A)

        b = np.zeros((m, ), dtype=int)
        b[:mseed] = np.squeeze(np.where(A[u, v]))
        for i in range(mseed, m):
            C = np.append(0, np.cumsum(P[u, v]))
            r = np.sum(rng.random_sample() * C[-1] >= C)
            b[i] = r
            P = Fd
            P[u[b[:i]], v[b[:i]]] = P[v[b[:i]], u[b[:i]]] = 0

            A[u[r], v[r]] = A[v[r], u[r]] = 1

        return A
Ejemplo n.º 2
0
def get_components(A, no_depend=False):
    '''
    Returns the components of an undirected graph specified by the binary and
    undirected adjacency matrix adj. Components and their constitutent nodes
    are assigned the same index and stored in the vector, comps. The vector,
    comp_sizes, contains the number of nodes beloning to each component.

    Parameters
    ----------
    A : NxN np.ndarray
        binary undirected adjacency matrix
    no_depend : Any
        Does nothing, included for backwards compatibility

    Returns
    -------
    comps : Nx1 np.ndarray
        vector of component assignments for each node
    comp_sizes : Mx1 np.ndarray
        vector of component sizes

    Notes
    -----
    Note: disconnected nodes will appear as components with a component
    size of 1

    Note: The identity of each component (i.e. its numerical value in the
    result) is not guaranteed to be identical the value returned in BCT,
    matlab code, although the component topology is.

    Many thanks to Nick Cullen for providing this implementation
    '''

    if not np.all(A == A.T):  # ensure matrix is undirected
        raise BCTParamError('get_components can only be computed for undirected'
                            ' matrices.  If your matrix is noisy, correct it with np.around')
    
    A = binarize(A, copy=True)
    n = len(A)
    np.fill_diagonal(A, 1)

    edge_map = [{u,v} for u in range(n) for v in range(n) if A[u,v] == 1]
    union_sets = []
    for item in edge_map:
        temp = []
        for s in union_sets:

            if not s.isdisjoint(item):
                item = s.union(item)
            else:
                temp.append(s)
        temp.append(item)
        union_sets = temp

    comps = np.array([i+1 for v in range(n) for i in 
        range(len(union_sets)) if v in union_sets[i]])
    comp_sizes = np.array([len(s) for s in union_sets])

    return comps, comp_sizes
Ejemplo n.º 3
0
def corr_flat_dir(a1, a2):
    '''
    Returns the correlation coefficient between two flattened adjacency
    matrices.  Similarity metric for weighted matrices.

    Parameters
    ----------
    A1 : NxN np.ndarray
        directed matrix 1
    A2 : NxN np.ndarray
        directed matrix 2

    Returns
    -------
    r : float
        Correlation coefficient describing edgewise similarity of a1 and a2
    '''
    n = len(a1)
    if len(a2) != n:
        raise BCTParamError("Cannot calculate flattened correlation on "
                            "matrices of different size")
    ix = np.logical_not(np.eye(n))
    return np.corrcoef(a1[ix].flat, a2[ix].flat)[0][1]
Ejemplo n.º 4
0
def corr_flat_und(a1, a2):
    '''
    Returns the correlation coefficient between two flattened adjacency
    matrices.  Only the upper triangular part is used to avoid double counting
    undirected matrices.  Similarity metric for weighted matrices.

    Parameters
    ----------
    A1 : NxN np.ndarray
        undirected matrix 1
    A2 : NxN np.ndarray
        undirected matrix 2

    Returns
    -------
    r : float
        Correlation coefficient describing edgewise similarity of a1 and a2
    '''
    n = len(a1)
    if len(a2) != n:
        raise BCTParamError("Cannot calculate flattened correlation on "
                            "matrices of different size")
    triu_ix = np.where(np.triu(np.ones((n, n)), 1))
    return np.corrcoef(a1[triu_ix].flat, a2[triu_ix].flat)[0][1]
Ejemplo n.º 5
0
def get_components_old(A, no_depend=False):
    '''
    Returns the components of an undirected graph specified by the binary and
    undirected adjacency matrix adj. Components and their constitutent nodes
    are assigned the same index and stored in the vector, comps. The vector,
    comp_sizes, contains the number of nodes beloning to each component.

    Parameters
    ----------
    adj : NxN np.ndarray
        binary undirected adjacency matrix
    no_depend : bool
        If true, doesn't import networkx to do the calculation. Default value
        is false.

    Returns
    -------
    comps : Nx1 np.ndarray
        vector of component assignments for each node
    comp_sizes : Mx1 np.ndarray
        vector of component sizes

    Notes
    -----
    Note: disconnected nodes will appear as components with a component
    size of 1

    Note: The identity of each component (i.e. its numerical value in the
    result) is not guaranteed to be identical the value returned in BCT,
    although the component topology is.

    Note: networkx is used to do the computation efficiently. If networkx is
    not available a breadth-first search that does not depend on networkx is
    used instead, but this is less efficient. The corresponding BCT function
    does the computation by computing the Dulmage-Mendelsohn decomposition. I
    don't know what a Dulmage-Mendelsohn decomposition is and there doesn't
    appear to be a python equivalent. If you think of a way to implement this
    better, let me know.
        '''
    # nonsquare matrices cannot be symmetric; no need to check

    if not np.all(A == A.T):  # ensure matrix is undirected
        raise BCTParamError('get_components can only be computed for undirected'
                            ' matrices.  If your matrix is noisy, correct it with np.around')

    A = binarize(A, copy=True)
    n = len(A)
    np.fill_diagonal(A, 1)

    try:
        if no_depend:
            raise ImportError()
        else:
            import networkx as nx
        net = nx.from_numpy_matrix(A)
        cpts = list(nx.connected_components(net))

        cptvec = np.zeros((n,))
        cptsizes = np.zeros(len(cpts))
        for i, cpt in enumerate(cpts):
            cptsizes[i] = len(cpt)
            for node in cpt:
                cptvec[node] = i + 1

    except ImportError:
        # if networkx is not available use less efficient breadth first search
        cptvec = np.zeros((n,))
        r, _ = breadthdist(A)
        for node, reach in enumerate(r):
            if cptvec[node] > 0:
                continue
            else:
                cptvec[np.where(reach)] = np.max(cptvec) + 1

        cptsizes = np.zeros(np.max(cptvec))
        for i in np.arange(np.max(cptvec)):
            cptsizes[i] = np.size(np.where(cptvec == i + 1))

    return cptvec, cptsizes
Ejemplo n.º 6
0
Archivo: motifs.py Proyecto: YSA6/bctpy
def find_motif34(m, n=None):
    '''
    This function returns all motif isomorphs for a given motif id and
    class (3 or 4). The function also returns the motif id for a given
    motif matrix

    1. Input:       Motif_id,           e.g. 1 to 13, if class is 3
                 Motif_class,        number of nodes, 3 or 4.
    Output:      Motif_matrices,     all isomorphs for the given motif

    2. Input:       Motif_matrix        e.g. [0 1 0; 0 0 1; 1 0 0]
    Output       Motif_id            e.g. 1 to 13, if class is 3

    Parameters
    ----------
    m : int | matrix
        In use case 1, a motif_id which is an integer.
        In use case 2, the entire matrix of the motif
        (e.g. [0 1 0; 0 0 1; 1 0 0])
    n : int | None
        In use case 1, the motif class, which is the number of nodes. This is
        either 3 or 4.
        In use case 2, None.

    Returns
    -------
    M : np.ndarray | int
        In use case 1, returns all isomorphs for the given motif
        In use case 2, returns the motif_id for the specified motif matrix
    '''
    from scipy import io
    import os
    fname = os.path.join(os.path.dirname(__file__), motiflib)
    z = (0,)
    if n == 3:
        mot = io.loadmat(fname)
        m3 = mot['m3']
        id3 = mot['id3'].squeeze()
        ix, = np.where(id3 == m)
        M = np.zeros((3, 3, len(ix)))
        for i, ind in enumerate(ix):
            M[:, :, i] = np.reshape(np.concatenate(
                (z, m3[ind, 0:3], z, m3[ind, 3:6], z)), (3, 3))
    elif n == 4:
        mot = io.loadmat(fname)
        m4 = mot['m4']
        id4 = mot['id4'].squeeze()
        ix, = np.where(id4 == m)
        M = np.zeros((4, 4, len(ix)))
        for i, ind in enumerate(ix):
            M[:, :, i] = np.reshape(np.concatenate(
                (z, m4[ind, 0:4], z, m4[ind, 4:8], z, m4[ind, 8:12], z)), (4, 4))
    elif n is None:
        try:
            m = np.array(m)
        except TypeError:
            raise BCTParamError('motif matrix must be an array-like')
        if m.shape[0] == 3:
            M, = np.where(motif3struct_bin(m))
        elif m.shape[0] == 4:
            M, = np.where(motif4struct_bin(m))
        else:
            raise BCTParamError('motif matrix must be 3x3 or 4x4')
    else:
        raise BCTParamError('Invalid motif class, must be 3, 4, or None')

    return M
Ejemplo n.º 7
0
def generative_model(A,
                     D,
                     m,
                     eta,
                     gamma=None,
                     model_type='matching',
                     model_var='powerlaw',
                     epsilon=1e-6,
                     copy=True,
                     seed=None):
    '''
    Generates synthetic networks using the models described in
    Betzel et al. (2016) Neuroimage. See this paper for more details.

    Succinctly, the probability of forming a connection between nodes u and v is
    P(u,v) = E(u,v)**eta * K(u,v)**gamma
    where eta and gamma are hyperparameters, E(u,v) is the euclidean or similar
    distance measure, and K(u,v) is the algorithm that defines the model.

    This describes the power law formulation, an alternative formulation uses
    the exponential function
    P(u,v) = exp(E(u,v)*eta) * exp(K(u,v)*gamma)

    Parameters
    ----------
    A : np.ndarray
        Binary network of seed connections
    D : np.ndarray
        Matrix of euclidean distances or other distances between nodes
    m : int
        Number of connections that should be present in the final synthetic 
        network
    eta : np.ndarray
        A vector describing a range of values to estimate for eta, the 
        hyperparameter describing exponential weighting of the euclidean
        distance.
    gamma : np.ndarray
        A vector describing a range of values to estimate for theta, the
        hyperparameter describing exponential weighting of the basis
        algorithm. If model_type='euclidean' or another distance metric,
        this can be None.
    model_type : Enum(str)
        euclidean : Uses only euclidean distances to generate connection 
            probabilities
        neighbors : count of common neighbors
        matching : matching index, the normalized overlap in neighborhoods
        clu-avg : Average clustering coefficient
        clu-min : Minimum clustering coefficient
        clu-max : Maximum clustering coefficient
        clu-diff : Difference in clustering coefficient
        clu-prod : Product of clustering coefficient
        deg-avg : Average degree
        deg-min : Minimum degree
        deg-max : Maximum degree
        deg-diff : Difference in degree
        deg-prod : Product of degrees
    model_var : Enum(str)
        Default value is powerlaw. If so, uses formulation of P(u,v) as
        described above. Alternate value is exponential. If so, uses
        P(u,v) = exp(E(u,v)*eta) * exp(K(u,v)*gamma)
    epsilon : float
        A small positive value added to all P(u,v). The default value is 1e-6
    copy : bool
        Some algorithms add edges directly to the input matrix. Set this flag
        to make a copy of the input matrix instead. Defaults to True.
    seed : hashable, optional
        If None (default), use the np.random's global random state to generate random numbers.
        Otherwise, use a new np.random.RandomState instance seeded with the given value.
    '''
    rng = get_rng(seed)
    if copy:
        A = A.copy()

    n = len(D)

    #These parameters don't do any of the voronoi narrowing.
    #Its a list of eta values paired with gamma values.
    #To try 3 eta and 3 gamma pairs, should use 9 list values.
    if len(eta) != len(gamma):
        raise BCTParamError('Eta and gamma hyperparameters must be lists of '
                            'the same size')

    nparams = len(eta)

    B = np.zeros((n, n, nparams))

    def k_avg(K):
        return ((np.tile(K, (n, 1)) + np.transpose(np.tile(K, (n, 1)))) / 2 +
                epsilon)

    def k_diff(K):
        return np.abs(np.tile(K, (n, 1)) -
                      np.transpose(np.tile(K, (n, 1)))) + epsilon

    def k_max(K):
        return np.max(np.dstack(
            (np.tile(K, (n, 1)), np.transpose(np.tile(K, (n, 1))))),
                      axis=2) + epsilon

    def k_min(K):
        return np.min(np.dstack(
            (np.tile(K, (n, 1)), np.transpose(np.tile(K, (n, 1))))),
                      axis=2) + epsilon

    def k_prod(K):
        return np.outer(K, np.transpose(K)) + epsilon

    def s_avg(K, sc):
        return (K + sc) / 2 + epsilon

    def s_diff(K, sc):
        return np.abs(K - sc) + epsilon

    def s_min(K, sc):
        return np.where(K < sc, K + epsilon, sc + epsilon)

    def s_max(K, sc):
        #return np.max((K, sc.T), axis=0)
        return np.where(K > sc, K + epsilon, sc + epsilon)

    def s_prod(K, sc):
        return K * sc + epsilon

    def x_avg(K, ixes):
        nr_ixes = np.size(np.where(ixes))
        Ksc = np.tile(K, (nr_ixes, 1))
        Kix = np.transpose(np.tile(K[ixes], (n, 1)))
        return s_avg(Ksc, Kix)

    def x_diff(K, ixes):
        nr_ixes = np.size(np.where(ixes))
        Ksc = np.tile(K, (nr_ixes, 1))
        Kix = np.transpose(np.tile(K[ixes], (n, 1)))
        return s_diff(Ksc, Kix)

    def x_max(K, ixes):
        nr_ixes = np.size(np.where(ixes))
        Ksc = np.tile(K, (nr_ixes, 1))
        Kix = np.transpose(np.tile(K[ixes], (n, 1)))
        return s_max(Ksc, Kix)

    def x_min(K, ixes):
        nr_ixes = np.size(np.where(ixes))
        Ksc = np.tile(K, (nr_ixes, 1))
        Kix = np.transpose(np.tile(K[ixes], (n, 1)))
        return s_min(Ksc, Kix)

    def x_prod(K, ixes):
        nr_ixes = np.size(np.where(ixes))
        Ka = np.reshape(K[ixes], (nr_ixes, 1))
        Kb = np.reshape(np.transpose(K), (1, n))
        return np.outer(Ka, Kb) + epsilon

    def clu_gen(A, K, D, m, eta, gamma, model_var, x_fun):
        mseed = np.size(np.where(A.flat)) // 2

        A = A > 0

        if type(model_var) == tuple:
            mv1, mv2 = model_var
        else:
            mv1, mv2 = model_var, model_var

        if mv1 in ('powerlaw', 'power_law'):
            Fd = D**eta
        elif mv1 in ('exponential', ):
            Fd = np.exp(eta * D)

        if mv2 in ('powerlaw', 'power_law'):
            Fk = K**gamma
        elif mv2 in ('exponential', ):
            Fk = np.exp(gamma * K)

        c = clustering_coef_bu(A)
        k = np.sum(A, axis=1)

        Ff = Fd * Fk * np.logical_not(A)
        u, v = np.where(np.triu(np.ones((n, n)), 1))

        #print(mseed, m)
        for i in range(mseed + 1, m):
            C = np.append(0, np.cumsum(Ff[u, v]))
            r = np.sum(rng.random_sample() * C[-1] >= C)
            uu = u[r]
            vv = v[r]
            A[uu, vv] = A[vv, uu] = 1
            k[uu] += 1
            k[vv] += 1

            bu = A[uu, :].astype(bool)
            bv = A[vv, :].astype(bool)
            su = A[np.ix_(bu, bu)]
            sv = A[np.ix_(bu, bu)]

            bth = np.logical_and(bu, bv)
            c[bth] += 2 / (k[bth]**2 - k[bth])
            c[uu] = np.size(np.where(su.flat)) / (k[uu] * (k[uu] - 1))
            c[vv] = np.size(np.where(sv.flat)) / (k[vv] * (k[vv] - 1))
            c[k <= 1] = 0
            bth[uu] = 1
            bth[vv] = 1

            k_result = x_fun(c, bth)

            #print(np.shape(k_result))
            #print(np.shape(K))
            #print(K)
            #print(np.shape(K[bth,:]))

            K[bth, :] = k_result
            K[:, bth] = k_result.T

            if mv2 in ('powerlaw', 'power_law'):
                Ff[bth, :] = Fd[bth, :] * K[bth, :]**gamma
                Ff[:, bth] = Fd[:, bth] * K[:, bth]**gamma
            elif mv2 in ('exponential', ):
                Ff[bth, :] = Fd[bth, :] * np.exp(K[bth, :]) * gamma
                Ff[:, bth] = Fd[:, bth] * np.exp(K[:, bth]) * gamma

            Ff = Ff * np.logical_not(A)

        return A

    def deg_gen(A, K, D, m, eta, gamma, model_var, s_fun):
        mseed = np.size(np.where(A.flat)) // 2

        k = np.sum(A, axis=1)

        if type(model_var) == tuple:
            mv1, mv2 = model_var
        else:
            mv1, mv2 = model_var, model_var

        if mv1 in ('powerlaw', 'power_law'):
            Fd = D**eta
        elif mv1 in ('exponential', ):
            Fd = np.exp(eta * D)

        if mv2 in ('powerlaw', 'power_law'):
            Fk = K**gamma
        elif mv2 in ('exponential', ):
            Fk = np.exp(gamma * K)

        P = Fd * Fk * np.logical_not(A)
        u, v = np.where(np.triu(np.ones((n, n)), 1))

        b = np.zeros((m, ), dtype=int)

        #        print(mseed)
        #        print(np.shape(u),np.shape(v))
        #        print(np.shape(b))
        #        print(np.shape(A[u,v]))
        #        print(np.shape(np.where(A[u,v])), 'sqishy')
        #        print(np.shape(P), 'squnnaq')

        #b[:mseed] = np.where(A[np.ix_(u,v)])
        b[:mseed] = np.squeeze(np.where(A[u, v]))
        #print(mseed, m)
        for i in range(mseed, m):
            C = np.append(0, np.cumsum(P[u, v]))
            r = np.sum(rng.random_sample() * C[-1] >= C)
            uu = u[r]
            vv = v[r]
            k[uu] += 1
            k[vv] += 1

            if mv2 in ('powerlaw', 'power_law'):
                Fk[:, uu] = Fk[uu, :] = s_fun(k, k[uu])**gamma
                Fk[:, vv] = Fk[vv, :] = s_fun(k, k[vv])**gamma
            elif mv2 in ('exponential', ):
                Fk[:, uu] = Fk[uu, :] = np.exp(s_fun(k, k[uu]) * gamma)
                Fk[:, vv] = Fk[vv, :] = np.exp(s_fun(k, k[vv]) * gamma)

            P = Fd * Fk

            b[i] = r

            P[u[b[:i]], v[b[:i]]] = P[v[b[:i]], u[b[:i]]] = 0

            A[u[r], v[r]] = A[v[r], u[r]] = 1
            #P[b[u[:i]], b[v[:i]]] = P[b[v[:i]], b[u[:i]]] = 0

            #A[uu,vv] = A[vv,uu] = 1


#        indx = v*n + u
#        indx[b]
#
#        nH = np.zeros((n,n))
#        nH.ravel()[indx[b]]=1
#
#        nG = np.zeros((n,n))
#        nG[ u[b], v[b] ]=1
#        nG = nG + nG.T
#
#        print(np.shape(np.where(A != nG)))
#
#        import pdb
#        pdb.set_trace()

        return A

    def matching_gen(A, K, D, m, eta, gamma, model_var):
        K += epsilon

        mseed = np.size(np.where(A.flat)) // 2

        if type(model_var) == tuple:
            mv1, mv2 = model_var
        else:
            mv1, mv2 = model_var, model_var

        if mv1 in ('powerlaw', 'power_law'):
            Fd = D**eta
        elif mv1 in ('exponential', ):
            Fd = np.exp(eta * D)

        if mv2 in ('powerlaw', 'power_law'):
            Fk = K**gamma
        elif mv2 in ('exponential', ):
            Fk = np.exp(gamma * K)

        Ff = Fd * Fk * np.logical_not(A)
        u, v = np.where(np.triu(np.ones((n, n)), 1))

        for ii in range(mseed, m):
            C = np.append(0, np.cumsum(Ff[u, v]))
            r = np.sum(rng.random_sample() * C[-1] >= C)
            uu = u[r]
            vv = v[r]
            A[uu, vv] = A[vv, uu] = 1

            updateuu, = np.where(np.inner(A, A[:, uu]))
            np.delete(updateuu, np.where(updateuu == uu))
            np.delete(updateuu, np.where(updateuu == vv))

            c1 = np.append(A[:, uu], A[uu, :])
            for i in range(len(updateuu)):
                j = updateuu[i]
                c2 = np.append(A[:, j], A[j, :])

                use = np.logical_or(c1, c2)
                use[uu] = use[uu + n] = use[j] = use[j + n] = 0
                ncon = np.sum(c1[use]) + np.sum(c2[use])
                if ncon == 0:
                    K[uu, j] = K[j, uu] = epsilon
                else:
                    K[uu, j] = K[j, uu] = (
                        2 / ncon * np.sum(np.logical_and(c1[use], c2[use])) +
                        epsilon)

            updatevv, = np.where(np.inner(A, A[:, vv]))
            np.delete(updatevv, np.where(updatevv == uu))
            np.delete(updatevv, np.where(updatevv == vv))

            c1 = np.append(A[:, vv], A[vv, :])
            for i in range(len(updatevv)):
                j = updatevv[i]
                c2 = np.append(A[:, j], A[j, :])

                use = np.logical_or(c1, c2)
                use[vv] = use[vv + n] = use[j] = use[j + n] = 0
                ncon = np.sum(c1[use]) + np.sum(c2[use])
                if ncon == 0:
                    K[vv, j] = K[j, vv] = epsilon
                else:
                    K[vv, j] = K[j, vv] = (
                        2 / ncon * np.sum(np.logical_and(c1[use], c2[use])) +
                        epsilon)

            Ff = Fd * Fk * np.logical_not(A)

        return A

    def neighbors_gen(A, K, D, m, eta, gamma, model_var):
        K += epsilon

        mseed = np.size(np.where(A.flat)) // 2

        if type(model_var) == tuple:
            mv1, mv2 = model_var
        else:
            mv1, mv2 = model_var, model_var

        if mv1 in ('powerlaw', 'power_law'):
            Fd = D**eta
        elif mv1 in ('exponential', ):
            Fd = np.exp(eta * D)

        if mv2 in ('powerlaw', 'power_law'):
            Fk = K**gamma
        elif mv2 in ('exponential', ):
            Fk = np.exp(gamma * K)

        Ff = Fd * Fk * np.logical_not(A)
        u, v = np.where(np.triu(np.ones((n, n)), 1))

        for ii in range(mseed, m):
            C = np.append(0, np.cumsum(Ff[u, v]))
            r = np.sum(rng.random_sample() * C[-1] >= C)
            uu = u[r]
            vv = v[r]
            A[uu, vv] = A[vv, uu] = 1

            x = A[uu, :].astype(int)
            y = A[:, vv].astype(int)

            K[uu, y] += 1
            K[y, uu] += 1
            K[vv, x] += 1
            K[x, vv] += 1

            if mv2 in ('powerlaw', 'power_law'):
                Fk = K**gamma
            elif mv2 in ('exponential', ):
                Fk = np.exp(gamma * K)

            if mv2 in ('powerlaw', 'power_law'):
                Ff[uu, y] = Ff[y, uu] = Fd[uu, y] * (K[uu, y]**gamma)
                Ff[vv, x] = Ff[x, vv] = Fd[vv, x] * (K[vv, x]**gamma)
            elif mv2 in ('exponential', ):
                Ff[uu, y] = Ff[y, uu] = Fd[uu, y] * np.exp(gamma * K[uu, y])
                Ff[vv, x] = Ff[x, vv] = Fd[vv, x] * np.exp(gamma * K[vv, x])

            Ff[np.where(A)] = 0

        return A

    def euclidean_gen(A, D, m, eta, model_var):
        mseed = np.size(np.where(A.flat)) // 2

        if type(model_var) == tuple:
            mv1, mv2 = model_var
        else:
            mv1, mv2 = model_var, model_var

        if mv1 != mv2:
            raise BCTParamError('Too many hyperparameters specified')

        if mv1 in ('powerlaw', 'power_law'):
            Fd = D**eta
        elif mv1 in ('exponential', ):
            Fd = np.exp(eta**D)

        u, v = np.where(np.triu(np.ones((n, n)), 1))
        P = Fd * np.logical_not(A)

        b = np.zeros((m, ), dtype=int)
        b[:mseed] = np.squeeze(np.where(A[u, v]))
        for i in range(mseed, m):
            C = np.append(0, np.cumsum(P[u, v]))
            r = np.sum(rng.random_sample() * C[-1] >= C)
            b[i] = r
            P = Fd
            P[u[b[:i]], v[b[:i]]] = P[v[b[:i]], u[b[:i]]] = 0

            A[u[r], v[r]] = A[v[r], u[r]] = 1

        return A

    if model_type in ('clu-avg', 'clu_avg'):
        Kseed = k_avg(clustering_coef_bu(A))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = clu_gen(A, Kseed, D, m, ep, gp, model_var, x_avg)

    elif model_type in ('clu-diff', 'clu_diff'):
        Kseed = k_diff(clustering_coef_bu(A))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = clu_gen(A, Kseed, D, m, ep, gp, model_var, x_diff)

    elif model_type in ('clu-max', 'clu_max'):
        Kseed = k_max(clustering_coef_bu(A))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = clu_gen(A, Kseed, D, m, ep, gp, model_var, x_max)

    elif model_type in ('clu-min', 'clu_min'):
        Kseed = k_min(clustering_coef_bu(A))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = clu_gen(A, Kseed, D, m, ep, gp, model_var, x_min)

    elif model_type in ('clu-prod', 'clu_prod'):
        Kseed = k_prod(clustering_coef_bu(A))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = clu_gen(A, Kseed, D, m, ep, gp, model_var, x_prod)

    elif model_type in ('deg-avg', 'deg_avg'):
        Kseed = k_avg(np.sum(A, axis=1))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = deg_gen(A, Kseed, D, m, ep, gp, model_var, s_avg)

    elif model_type in ('deg-diff', 'deg_diff'):
        Kseed = k_diff(np.sum(A, axis=1))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = deg_gen(A, Kseed, D, m, ep, gp, model_var, s_diff)

    elif model_type in ('deg-max', 'deg_max'):
        Kseed = k_max(np.sum(A, axis=1))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = deg_gen(A, Kseed, D, m, ep, gp, model_var, s_max)

    elif model_type in ('deg-min', 'deg_min'):
        Kseed = k_min(np.sum(A, axis=1))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = deg_gen(A, Kseed, D, m, ep, gp, model_var, s_min)

    elif model_type in ('deg-prod', 'deg_prod'):
        Kseed = k_prod(np.sum(A, axis=1))
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = deg_gen(A, Kseed, D, m, ep, gp, model_var, s_prod)

    elif model_type in ('neighbors', ):
        Kseed = np.inner(A, A)
        np.fill_diagonal(Kseed, 0)
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = neighbors_gen(A, Kseed, D, m, ep, gp, model_var)

    elif model_type in ('matching', 'matching-ind', 'matching_ind'):
        mi, _, _ = matching_ind(A)
        Kseed = mi + mi.T
        for j, (ep, gp) in enumerate(zip(eta, gamma)):
            B[:, :, j] = matching_gen(A, Kseed, D, m, ep, gp, model_var)

    elif model_type in ('spatial', 'geometric', 'euclidean'):
        for j, ep in enumerate(eta):
            B[:, :, j] = euclidean_gen(A, D, m, ep, model_var)

    return np.squeeze(B)