Skip to content

HigherOrderGraph / modified MultiOrderModel - #329

Open
vineetbansal wants to merge 27 commits into
devfrom
vb/hograph
Open

HigherOrderGraph / modified MultiOrderModel#329
vineetbansal wants to merge 27 commits into
devfrom
vb/hograph

Conversation

@vineetbansal

Copy link
Copy Markdown
Collaborator

A HigherOrderGraph class of arbitrary order, constructable from temporal_graph/event_graph/path_data. It delegates most of the work to the MultiOrderModel class which does the iterations on the lifting (with cached=False). It is also constructable using from_aggregated, and has its own .lift method.

The MultiOrderModel class now has HigherOrderGraphs in its layers.

None of the tests for MultiOrderModel needed modifications and still pass, which is reassuring. Tests for HigherOrderModel and MultiOrderModel that assume HigherOrderModel in layers are coming next.

This PR assumes that the EventGraph branch is merged, as it builds on top of it.

Typical workflow using these new classes:

def data() -> pp.TemporalGraph:
    r"""

        a           d
          \        /
            c  (hub)
          /        \
        b           e

    """
    return pp.TemporalGraph.from_edge_list(
        [
            ("a", "c", 1), ("c", "d", 2),   # a -> c -> d
            ("b", "c", 3), ("c", "e", 4),   # b -> c -> e
            ("a", "c", 5), ("c", "d", 6),
            ("b", "c", 7), ("c", "e", 8),
        ]
    )

t = data()
DELTA = 1
eg = EventGraph.from_temporal_graph(t, delta=DELTA)
h1 = HigherOrderGraph.from_temporal_graph(t, order = 1)
assert h1.order == 1

h2 = HigherOrderGraph.from_event_graph(eg)
assert h2.order == 2

paths = PathData(IndexMap(list("abcde")))
paths.append_walk(("a", "c", "d"), weight=3)
paths.append_walk(("b", "c", "e"), weight=3)

h1b = HigherOrderGraph.from_path_data(paths, order = 1)
h1c = HigherOrderGraph.from_event_graph(eg, order = 2)

h5 = HigherOrderGraph.from_event_graph(eg, order=5)  # Create order 5 ho (but still has to go through 2->5 algorithmically)

print("\n=== HigherOrderGraph (order 2) ===")
print("order:", h2.order)                   # 2
print("nodes:", h2.nodes)                   # [('a','c'), ('b','c'), ('c','d'), ('c','e')]
print("edges:", h2.edges)                   # [(('a','c'),('c','d')), (('b','c'),('c','e'))]
print("weights:", h2.data.edge_weight)      # [2., 2.]

assert h2.order == 2
assert h2.n == 4                            # 8 events collapsed into 4 nodes
assert h2.n_first_order == 5
assert h2.first_order_mapping.to_id(0) == "a"

h3 = h2.lift()
assert isinstance(h3, HigherOrderGraph)
assert h3.order == 3
print("order-3 nodes:", h3.nodes)  # [('a', 'c', 'd'), ('b', 'c', 'e')]


MAX_ORDER = 2

# build MultiOrderModel from TemporalGraph
m = MultiOrderModel.from_temporal_graph(t, delta=DELTA, max_order=MAX_ORDER)

for k, layer in sorted(m.layers.items()):
    print(f"  layer {k}: order={layer.order}  n={layer.n}  m={layer.m}")
    #   layer 1: order=1  n=5  m=4
    #   layer 2: order=2  n=4  m=2
    assert isinstance(layer, HigherOrderGraph)
    assert layer.order == k
    assert layer.n_first_order == t.n

# build MultiOrderModel from EventGraph
m_via_eg = MultiOrderModel.from_event_graph(eg, max_order=MAX_ORDER)
assert m_via_eg.layers[2].edges == m.layers[2].edges

# build MultiOrderModel from PathData
paths = pp.PathData(pp.IndexMap(list("abcde")))
paths.append_walks(node_seqs=[("a", "c", "d"), ("b", "c", "e")], weights=[4, 4])
m_paths = MultiOrderModel.from_path_data(paths, max_order=MAX_ORDER)

… namespace); continuations method removed from EventGraph
@vineetbansal vineetbansal changed the title Vb/hograph HigherOrderGraph / modified MultiOrderModel Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant