Beispiel #1
0
    def fit(self, adjacency: Union[sparse.csr_matrix, np.ndarray]) -> 'PCA':
        """Compute the embedding of the graph.

        Parameters
        ----------
        adjacency :
            Adjacency or biadjacency matrix of the graph.

        Returns
        -------
        self: :class:`PCA`
        """
        adjacency = check_format(adjacency).asfptype()
        n_row, n_col = adjacency.shape
        adjacency_centered = SparseLR(
            adjacency,
            (-np.ones(n_row), adjacency.T.dot(np.ones(n_row)) / n_row))

        if isinstance(self.solver, str):
            self.solver = set_svd_solver(self.solver, adjacency)

        svd = self.solver
        svd.fit(adjacency_centered, self.n_components)
        self.embedding_row_ = svd.singular_vectors_left_
        self.embedding_col_ = svd.singular_vectors_right_
        self.embedding_ = svd.singular_vectors_left_
        self.singular_values_ = svd.singular_values_
        self.singular_vectors_left_ = svd.singular_vectors_left_
        self.singular_vectors_right_ = svd.singular_vectors_right_

        return self
def bipartite2directed(
    biadjacency: Union[sparse.csr_matrix, SparseLR]
) -> Union[sparse.csr_matrix, SparseLR]:
    """Adjacency matrix of the directed graph associated with a bipartite graph
    (with edges from one part to the other).

    The returned adjacency matrix is:

    :math:`A  = \\begin{bmatrix} 0 & B \\\\ 0 & 0 \\end{bmatrix}`

    where :math:`B` is the biadjacency matrix.

    Parameters
    ----------
    biadjacency :
        Biadjacency matrix of the graph.

    Returns
    -------
    adjacency :
        Adjacency matrix (same format as input).
    """
    check_csr_or_slr(biadjacency)
    n_row, n_col = biadjacency.shape
    if type(biadjacency) == sparse.csr_matrix:
        adjacency = sparse.bmat(
            [[None, biadjacency], [sparse.csr_matrix((n_col, n_row)), None]],
            format='csr')
        adjacency.sort_indices()
        return adjacency
    else:
        new_tuples = [(np.hstack(
            (x, np.zeros(n_col))), np.hstack((np.zeros(n_row), y)))
                      for (x, y) in biadjacency.low_rank_tuples]
        return SparseLR(bipartite2directed(biadjacency.sparse_mat), new_tuples)
Beispiel #3
0
    def returnNormalized(self, adjacency):
        n1, n2 = adjacency.shape
        #total weight heuristic stated in De Lara (2019)
        adjacency = SparseLR(
            adjacency, [(self.regularization * np.ones(n1), np.ones(n2))])

        #left side of normalized laplacian (squared later)
        w_row = adjacency.dot(np.ones(adjacency.shape[1]))
        #right side of normalized laplacian (squared later)
        w_col = (adjacency.T).dot(np.ones(adjacency.shape[0]))
        self.diag_row = diag_pinv(np.sqrt(w_row))
        self.diag_col = diag_pinv(np.sqrt(w_col))
        normalized_adj = safe_sparse_dot(
            self.diag_row, safe_sparse_dot(adjacency, self.diag_col))

        return normalized_adj
 def setUp(self):
     """Instanciate les Miserables and regularized version"""
     self.adjacency = miserables()
     self.random_state = np.random.RandomState(123)
     n = self.adjacency.shape[0]
     x = np.random.random(n)
     self.slr = SparseLR(self.adjacency, [(x, x)])
def directed2undirected(
        adjacency: Union[sparse.csr_matrix, SparseLR],
        weighted: bool = True) -> Union[sparse.csr_matrix, SparseLR]:
    """Adjacency matrix of the undirected graph associated with some directed graph.

    The new adjacency matrix becomes either:

    :math:`A+A^T` (default)

    or

    :math:`\\max(A,A^T)`

    If the initial adjacency matrix :math:`A` is binary, bidirectional edges have weight 2
    (first method, default) or 1 (second method).

    Parameters
    ----------
    adjacency :
        Adjacency matrix.
    weighted :
        If ``True``, return the sum of the weights in both directions of each edge.

    Returns
    -------
    new_adjacency :
        New adjacency matrix (same format as input).
    """
    check_csr_or_slr(adjacency)
    if type(adjacency) == sparse.csr_matrix:
        if weighted:
            new_adjacency = adjacency.astype(float)
            new_adjacency += adjacency.T
        else:
            new_adjacency = (adjacency + adjacency.T).astype(bool)
        new_adjacency.tocsr().sort_indices()
        return new_adjacency
    else:
        if weighted:
            new_tuples = [(y, x) for (x, y) in adjacency.low_rank_tuples]
            return SparseLR(directed2undirected(adjacency.sparse_mat),
                            adjacency.low_rank_tuples + new_tuples)
        else:
            raise ValueError(
                'This function only works with ``weighted=True`` for SparseLR objects.'
            )
def bipartite2undirected(
    biadjacency: Union[sparse.csr_matrix, SparseLR]
) -> Union[sparse.csr_matrix, SparseLR]:
    """Adjacency matrix of a bigraph defined by its biadjacency matrix.

    The returned adjacency matrix is:

    :math:`A  = \\begin{bmatrix} 0 & B \\\\ B^T & 0 \\end{bmatrix}`

    where :math:`B` is the biadjacency matrix of the bipartite graph.

    Parameters
    ----------
    biadjacency:
        Biadjacency matrix of the graph.

    Returns
    -------
    adjacency :
        Adjacency matrix (same format as input).
    """
    check_csr_or_slr(biadjacency)
    if type(biadjacency) == sparse.csr_matrix:
        adjacency = sparse.bmat([[None, biadjacency], [biadjacency.T, None]],
                                format='csr')
        adjacency.sort_indices()
        return adjacency
    else:
        n_row, n_col = biadjacency.shape
        new_tuples = []
        for (x, y) in biadjacency.low_rank_tuples:
            new_tuples.append((np.hstack(
                (x, np.zeros(n_col))), np.hstack((np.zeros(n_row), y))))
            new_tuples.append((np.hstack(
                (np.zeros(n_row), y)), np.hstack((x, np.zeros(n_col)))))
        return SparseLR(bipartite2undirected(biadjacency.sparse_mat),
                        new_tuples)
    def fit(self, adjacency: Union[sparse.csr_matrix, np.ndarray]) -> 'BiSpectral':
        """
        Computes the generalized SVD of the adjacency matrix.

        Parameters
        ----------
        adjacency: array-like, shape = (n1, n2)
            Adjacency matrix, where n1 = n2 is the number of nodes for a standard graph,
            n1, n2 are the number of nodes in each part for a bipartite graph.

        Returns
        -------
        self: :class:`BiSpectral`
        """
        adjacency = check_format(adjacency).asfptype()
        n1, n2 = adjacency.shape

        if self.solver == 'auto':
            solver = auto_solver(adjacency.nnz)
            if solver == 'lanczos':
                self.solver: SVDSolver = LanczosSVD()
            else:
                self.solver: SVDSolver = HalkoSVD()

        total_weight = adjacency.dot(np.ones(n2)).sum()
        regularization = self.regularization
        if regularization:
            if self.relative_regularization:
                regularization = regularization * total_weight / (n1 * n2)
            adjacency = SparseLR(adjacency, [(regularization * np.ones(n1), np.ones(n2))])

        w_row = check_weights(self.weights, adjacency)
        w_col = check_weights(self.col_weights, adjacency.T)
        diag_row = diag_pinv(np.sqrt(w_row))
        diag_col = diag_pinv(np.sqrt(w_col))

        normalized_adj = safe_sparse_dot(diag_row, safe_sparse_dot(adjacency, diag_col))

        # svd
        if self.embedding_dimension >= min(n1, n2) - 1:
            n_components = min(n1, n2) - 1
            warnings.warn(Warning("The dimension of the embedding must be less than the number of rows "
                                  "and the number of columns. Changed accordingly."))
        else:
            n_components = self.embedding_dimension + 1
        self.solver.fit(normalized_adj, n_components)

        index = np.argsort(-self.solver.singular_values_)
        self.singular_values_ = self.solver.singular_values_[index[1:]]
        self.row_embedding_ = diag_row.dot(self.solver.left_singular_vectors_[:, index[1:]])
        self.col_embedding_ = diag_col.dot(self.solver.right_singular_vectors_[:, index[1:]])

        if self.scaling:
            if self.scaling == 'multiply':
                self.row_embedding_ *= np.sqrt(self.singular_values_)
                self.col_embedding_ *= np.sqrt(self.singular_values_)
            elif self.scaling == 'divide':
                energy_levels: np.ndarray = np.sqrt(1 - np.clip(self.singular_values_, 0, 1) ** 2)
                energy_levels[energy_levels > 0] = 1 / energy_levels[energy_levels > 0]
                self.row_embedding_ *= energy_levels
                self.col_embedding_ *= energy_levels
            elif self.scaling == 'barycenter':
                self.row_embedding_ *= self.singular_values_
            else:
                warnings.warn(Warning("The scaling must be 'multiply' or 'divide' or 'barycenter'. No scaling done."))

        self.embedding_ = np.vstack((self.row_embedding_, self.col_embedding_))
        return self
Beispiel #8
0
    def fit(self, adjacency: Union[sparse.csr_matrix, np.ndarray]) -> 'GSVD':
        """Compute the GSVD of the adjacency or biadjacency matrix.

        Parameters
        ----------
        adjacency :
            Adjacency or biadjacency matrix of the graph.

        Returns
        -------
        self: :class:`GSVD`
        """
        adjacency = check_format(adjacency).asfptype()
        n_row, n_col = adjacency.shape

        if self.n_components > min(n_row, n_col) - 1:
            n_components = min(n_row, n_col) - 1
            warnings.warn(
                Warning(
                    "The dimension of the embedding must be strictly less than the number of rows "
                    "and the number of columns. Changed accordingly."))
        else:
            n_components = self.n_components

        if self.solver == 'auto':
            solver = auto_solver(adjacency.nnz)
            if solver == 'lanczos':
                self.solver: SVDSolver = LanczosSVD()
            else:
                self.solver: SVDSolver = HalkoSVD()

        regularization = self.regularization
        if regularization:
            if self.relative_regularization:
                regularization = regularization * np.sum(
                    adjacency.data) / (n_row * n_col)
            adjacency_reg = SparseLR(
                adjacency, [(regularization * np.ones(n_row), np.ones(n_col))])
        else:
            adjacency_reg = adjacency

        weights_row = adjacency_reg.dot(np.ones(n_col))
        weights_col = adjacency_reg.T.dot(np.ones(n_row))
        diag_row = diag_pinv(np.power(weights_row, self.factor_row))
        diag_col = diag_pinv(np.power(weights_col, self.factor_col))
        self.solver.fit(
            safe_sparse_dot(diag_row, safe_sparse_dot(adjacency_reg,
                                                      diag_col)), n_components)

        singular_values = self.solver.singular_values_
        index = np.argsort(-singular_values)
        singular_values = singular_values[index]
        singular_vectors_left = self.solver.singular_vectors_left_[:, index]
        singular_vectors_right = self.solver.singular_vectors_right_[:, index]
        singular_left_diag = sparse.diags(
            np.power(singular_values, 1 - self.factor_singular))
        singular_right_diag = sparse.diags(
            np.power(singular_values, self.factor_singular))

        embedding_row = diag_row.dot(singular_vectors_left)
        embedding_col = diag_col.dot(singular_vectors_right)
        embedding_row = singular_left_diag.dot(embedding_row.T).T
        embedding_col = singular_right_diag.dot(embedding_col.T).T

        if self.normalized:
            embedding_row = normalize(embedding_row, p=2)
            embedding_col = normalize(embedding_col, p=2)

        self.embedding_row_ = embedding_row
        self.embedding_col_ = embedding_col
        self.embedding_ = embedding_row
        self.singular_values_ = singular_values
        self.singular_vectors_left_ = singular_vectors_left
        self.singular_vectors_right_ = singular_vectors_right
        self.regularization_ = regularization
        self.weights_col_ = weights_col

        return self
 def setUp(self):
     """Simple biadjacency for tests."""
     self.biadjacency = movie_actor()
     n_row, n_col = self.biadjacency.shape
     self.slr = SparseLR(self.biadjacency, [(np.random.rand(n_row), np.random.rand(n_col))])
 def setUp(self):
     self.adjacency = miserables()
     self.random_state = np.random.RandomState(123)
     n = self.adjacency.shape[0]
     x = np.random.random(n)
     self.slr = SparseLR(self.adjacency, [(x, x)])
Beispiel #11
0
 def setUp(self):
     """Simple biadjacency for tests."""
     self.biadjacency = movie_actor()
     n1, n2 = self.biadjacency.shape
     self.slr = SparseLR(self.biadjacency,
                         [(np.random.rand(n1), np.random.rand(n2))])