torch_concepts.ConceptGraph

class ConceptGraph(data: Tensor, node_names: List[str] | None = None)[source]

Memory-efficient concept graph representation using sparse COO format.

This class stores graphs in sparse format (edge list) internally, making it efficient for large sparse graphs. It provides utilities for graph analysis and conversions to dense/NetworkX/pandas formats.

The graph is stored as:
  • edge_index: Tensor of shape (2, num_edges) with [source, target] indices

  • edge_weight: Tensor of shape (num_edges,) with edge weights

  • node_names: List of node names

edge_index

Edge list of shape (2, num_edges)

Type:

Tensor

edge_weight

Edge weights of shape (num_edges,)

Type:

Tensor

node_names

Names of nodes in the graph

Type:

List[str]

n_nodes

Number of nodes in the graph

Type:

int

Parameters:
  • data (Tensor) – Dense adjacency matrix of shape (n_nodes, n_nodes)

  • node_names (List[str], optional) – Node names. If None, generates default names.

Example

>>> import torch
>>> from torch_concepts import ConceptGraph
>>>
>>> # Create a simple directed graph
>>> # A -> B -> C
>>> # A -> C
>>> adj = torch.tensor([[0., 1., 1.],
...                     [0., 0., 1.],
...                     [0., 0., 0.]])
>>> graph = ConceptGraph(adj, node_names=['A', 'B', 'C'])
>>>
>>> # Get root nodes (no incoming edges)
>>> print(graph.get_root_nodes())
['A']
>>>
>>> # Get leaf nodes (no outgoing edges)
>>> print(graph.get_leaf_nodes())
['C']
>>>
>>> # Check edge existence
>>> print(graph.has_edge('A', 'B'))
True
>>> print(graph.has_edge('B', 'A'))
False
>>>
>>> # Get edge weight
>>> print(graph.get_edge_weight('A', 'C'))
1.0
>>>
>>> # Get successors and predecessors
>>> print(graph.get_successors('A'))
['B', 'C']
>>> print(graph.get_predecessors('C'))
['A', 'B']
>>>
>>> # Check if DAG
>>> print(graph.is_dag())
True
>>>
>>> # Topological sort
>>> print(graph.topological_sort())
['A', 'B', 'C']
>>>
>>> # Convert to NetworkX for visualization
>>> nx_graph = graph.to_networkx()
>>>
>>> # Convert to pandas DataFrame
>>> df = graph.to_pandas()
>>>
>>> # Create from sparse format directly
>>> edge_index = torch.tensor([[0, 0, 1], [1, 2, 2]])
>>> edge_weight = torch.tensor([1.0, 1.0, 1.0])
>>> graph2 = ConceptGraph.from_sparse(
...     edge_index, edge_weight, n_nodes=3,
...     node_names=['X', 'Y', 'Z']
... )
__init__(data: Tensor, node_names: List[str] | None = None)[source]

Create new ConceptGraph instance from dense adjacency matrix.

Methods

__init__(data[, node_names])

Create new ConceptGraph instance from dense adjacency matrix.

dense_to_sparse([threshold])

Get sparse COO format (edge list) representation.

from_sparse(edge_index, edge_weight, n_nodes)

Create ConceptGraph directly from sparse format (more efficient).

get_ancestors(node)

Get all ancestors of a node (transitive predecessors).

get_descendants(node)

Get all descendants of a node (transitive successors).

get_edge_weight(source, target)

Get the weight of an edge.

get_leaf_nodes()

Get nodes with no outgoing edges (out-degree = 0).

get_levels()

Group nodes by depth from the graph roots.

get_predecessors(node)

Get immediate predecessors (parents) of a node.

get_root_nodes()

Get nodes with no incoming edges (in-degree = 0).

get_successors(node)

Get immediate successors (children) of a node.

has_edge(source, target[, threshold])

Check if an edge exists between two nodes.

is_dag()

Check if the graph is a directed acyclic graph (DAG).

is_directed_acyclic()

Check if the graph is a directed acyclic graph (DAG).

to_networkx([threshold])

Convert to NetworkX directed graph.

to_pandas()

Convert adjacency matrix to pandas DataFrame.

topological_sort()

Compute topological ordering of nodes.

Attributes

data

Get dense adjacency matrix representation.

edge_index

Edge list of shape (2, num_edges).

edge_weight

Edge weights of shape (num_edges,).

n_nodes

Get number of nodes in the graph.