Example #1
0
def convert_ensmallen_graph_to_networkx_graph(graph: Graph) -> nx.Graph:
    """Return networkX graph derived from the provided Ensmallen Graph.
    
    Parameters
    -----------
    graph: Graph
        The graph to be converted.
    """
    if graph.is_directed():
        result_graph = nx.DiGraph()
    else:
        result_graph = nx.Graph()

    result_graph.add_nodes_from(graph.get_node_ids())

    if graph.has_edge_weights():
        result_graph.add_weighted_edges_from([
            (src_name, dst_name, edge_weight)
            for (src_name, dst_name), edge_weight in zip(
                graph.get_directed_edge_node_ids(), graph.get_edge_weights())
        ])
    else:
        result_graph.add_edges_from(
            graph.get_edge_node_ids(directed=graph.is_directed()))

    return result_graph
Example #2
0
def graph_to_sparse_tensor(
    graph: Graph,
    use_weights: bool,
    use_simmetric_normalized_laplacian: bool,
    handling_multi_graph: str = "warn",
) -> tf.SparseTensor:
    """Returns provided graph as sparse Tensor.

    Parameters
    -------------------
    graph: Graph,
        The graph to convert.
    use_weights: bool,
        Whether to load the graph weights.
    use_simmetric_normalized_laplacian: bool
        Whether to use the symmetrically normalized laplacian 
    handling_multi_graph: str = "warn"
        How to behave when dealing with multigraphs.
        Possible behaviours are:
        - "warn", which warns the user and drops the multi-edges.
        - "raise"
        - "drop"

    Raises
    -------------------
    ValueError,
        If the weights are requested but the graph does not contain any.
    ValueError,
        If the graph contains singletons.
    ValueError,
        If the graph is a multigraph.

    Returns
    -------------------
    SparseTensor with (weighted) adjacency matrix.
    """
    if use_weights and not graph.has_edge_weights():
        raise ValueError("Edge weights were requested but the provided graph "
                         "does not contain any edge weight.")

    if graph.has_singleton_nodes():
        raise ValueError(
            f"In the provided {graph.get_name()} graph there are "
            f"{graph.get_number_of_singleton_nodes()} singleton nodes."
            "The GCN model does not support operations on graph containing "
            "singletons. You can either choose to drop singletons from "
            "the graph by using the `graph.remove_singleton_nodes()` "
            "method or alternatively you can add selfloops to them by "
            "using the `graph.add_selfloops()` method.")

    if graph.is_multigraph():
        message = (
            "The GCN model does not currently support convolutions on a multigraph. "
            "We are dropping the parallel edges before computing the adjacency matrix."
        )
        if handling_multi_graph == "warn":
            warnings.warn(message)
        elif handling_multi_graph == "raise":
            raise ValueError(message)

        graph = graph.remove_parallel_edges()

    if use_simmetric_normalized_laplacian:
        edge_node_ids, weights = graph.get_symmetric_normalized_laplacian_coo_matrix(
        )
        return tf.sparse.reorder(
            tf.SparseTensor(
                edge_node_ids, np.abs(weights),
                (graph.get_number_of_nodes(), graph.get_number_of_nodes())))

    return tf.SparseTensor(
        graph.get_directed_edge_node_ids(),
        (graph.get_edge_weights()
         if use_weights else tf.ones(graph.get_number_of_directed_edges())),
        (graph.get_number_of_nodes(), graph.get_number_of_nodes()))
Example #3
0
    def _fit_transform(self,
                       graph: Graph,
                       return_dataframe: bool = True,
                       verbose: bool = True) -> EmbeddingResult:
        """Return node embedding."""
        matrix = None
        if self._metric == "Jaccard":
            edges, weights = graph.get_jaccard_coo_matrix()
        elif self._metric == "Laplacian":
            edges, weights = graph.get_laplacian_coo_matrix()
        elif self._metric == "Modularity":
            matrix = graph.get_dense_modularity_matrix()
        elif self._metric == "Left Normalized Laplacian":
            edges, weights = graph.get_left_normalized_laplacian_coo_matrix()
        elif self._metric == "Right Normalized Laplacian":
            edges, weights = graph.get_right_normalized_laplacian_coo_matrix()
        elif self._metric == "Symmetric Normalized Laplacian":
            edges, weights = graph.get_symmetric_normalized_laplacian_coo_matrix(
            )
        elif self._metric == "Neighbours Intersection size":
            edges, weights = graph.get_neighbours_intersection_size_coo_matrix(
            )
        elif self._metric == "Ancestors Jaccard":
            matrix = graph.get_shared_ancestors_jaccard_adjacency_matrix(
                graph.get_breadth_first_search_from_node_names(
                    src_node_name=self._root_node_name,
                    compute_predecessors=True),
                verbose=verbose)
        elif self._metric == "Ancestors size":
            matrix = graph.get_shared_ancestors_size_adjacency_matrix(
                graph.get_breadth_first_search_from_node_names(
                    src_node_name=self._root_node_name,
                    compute_predecessors=True),
                verbose=verbose)
        elif self._metric == "Adamic-Adar":
            edges, weights = graph.get_adamic_adar_coo_matrix()
        elif self._metric == "Adjacency":
            edges, weights = graph.get_directed_edge_node_ids(), np.ones(
                graph.get_number_of_directed_edges())
        else:
            raise NotImplementedError(f"The provided metric {self._metric} "
                                      "is not currently supported.")

        if matrix is None:
            matrix = coo_matrix((weights, (edges[:, 0], edges[:, 1])),
                                shape=(graph.get_number_of_nodes(),
                                       graph.get_number_of_nodes()),
                                dtype=np.float32)

            U, sigmas, Vt = sparse_svds(matrix,
                                        k=int(self._embedding_size / 2))
        else:
            U, sigmas, Vt = randomized_svd(matrix,
                                           n_components=int(
                                               self._embedding_size / 2))

        sigmas = np.diagflat(np.sqrt(sigmas))
        left_embedding = np.dot(U, sigmas)
        right_embedding = np.dot(Vt.T, sigmas)

        if return_dataframe:
            node_names = graph.get_node_names()
            left_embedding = pd.DataFrame(left_embedding, index=node_names)
            right_embedding = pd.DataFrame(right_embedding, index=node_names)
        return EmbeddingResult(
            embedding_method_name=self.model_name(),
            node_embeddings=[left_embedding, right_embedding])