Extract the main path(s) from a traversal-weighted DAG
Description
Given a DAG that already carries edge-traversal weights (see
traversal_weights()), extracts the main path(s) using one of three
strategies:
-
"global"– the single source-to-sink path whose cumulative edge weight is highest (longest-path dynamic programming on the DAG). -
"local"– a greedy forward search from every source: at each node follow the highest-weight outgoing edge until a sink is reached. Returns the union of all such paths. -
"key_route"– selects the top-highest-weight edges (the key routes), then, for each key-route edge, finds the best incoming path from a source and the best outgoing path to a sink; the union of all these extended paths forms the key-route main path.
Broadening the path with threshold
The classic algorithms above produce a single, narrow path. The
threshold argument relaxes this to include near-optimal edges,
producing a wider subgraph that captures alternative routes through the
network. Set threshold to a value in (0, 1):
-
"global"– runs both a forward and a backward dynamic-programming pass. An edgeis included if the best source-to-sink path through that edge has total weight, whereis the optimal total weight. Atthreshold = 0.8, all edges on paths within 80 \ optimal are included. -
"local"– at each node, follows every outgoing edge whose weight is, instead of only the single best. Branches are explored via BFS until all reachable sinks are reached. -
"key_route"– expands the seed set to all edges with weight, whereis the-th highest weight. Useful when you want to pickseeds but also catch edges of similar importance.
Usage
main_path( g, type = c("global", "local", "key_route"), weight = NULL, k = 1L, threshold = 1 )main_path( g, type = c("global", "local", "key_route"), weight = NULL, k = 1L, threshold = 1 )
Arguments
g |
An |
type |
Character; one of |
weight |
Character; which traversal-weight edge attribute to use.
Defaults to the first of |
k |
Integer; number of key-route seed edges. Only used when
|
threshold |
Numeric in |
Value
An igraph subgraph containing only the vertices and edges
that belong to the main path(s). The subgraph retains the vertex
name attribute and the original traversal-weight edge attribute.
References
Hummon, N. P., & Doreian, P. (1989). Connectivity in a citation network: The development of DNA theory. Social Networks, 11(1), 39–63. doi:10.1016/0378-8733(89)90017-8
Garfield, E., Pudovkin, A. I., & Istomin, V. S. (2003). Why do we need algorithmic historiography? Journal of the American Society for Information Science and Technology, 54(5), 400–412.
See Also
mpa() for a one-call wrapper, traversal_weights() to compute
edge weights, plot_mpa() to visualise the result.
Examples
library(igraph) # Small diamond-shaped network (two competing routes from 1 to 5) el <- data.frame( from = c(1, 1, 2, 3, 2, 4), to = c(2, 3, 4, 4, 5, 5) ) g_w <- traversal_weights(el, method = "SPC") # --- Classic algorithms (threshold = 1.0, default) ----------------------- # Global: single best source-to-sink path mp_global <- main_path(g_w, type = "global", weight = "SPC") igraph::as_edgelist(mp_global) igraph::vcount(mp_global) # narrow — just the optimal chain # Local: greedy from every source, union of all resulting paths mp_local <- main_path(g_w, type = "local", weight = "SPC") igraph::vcount(mp_local) # Key-route: extend from the single highest-weight edge mp_kr <- main_path(g_w, type = "key_route", weight = "SPC", k = 1L) # Key-route with k = 3: seed from the top 3 edges mp_kr3 <- main_path(g_w, type = "key_route", weight = "SPC", k = 3L) igraph::vcount(mp_kr3) # --- Broadened paths (threshold < 1.0) ----------------------------------- # Global, broadened: include all edges on paths >= 80% of optimal weight mp_broad <- main_path(g_w, type = "global", weight = "SPC", threshold = 0.8) igraph::vcount(mp_broad) # more nodes than mp_global # Local, broadened: at each node follow edges within 90% of the local max mp_local_broad <- main_path(g_w, type = "local", weight = "SPC", threshold = 0.9) # Key-route, broadened: cast a wider seed net around k = 1 mp_kr_broad <- main_path(g_w, type = "key_route", weight = "SPC", k = 1L, threshold = 0.7) # Compare path sizes as threshold decreases sizes <- sapply(c(1.0, 0.9, 0.8, 0.7, 0.5), function(t) { igraph::vcount(main_path(g_w, type = "global", weight = "SPC", threshold = t)) }) names(sizes) <- c("1.0", "0.9", "0.8", "0.7", "0.5") print(sizes)library(igraph) # Small diamond-shaped network (two competing routes from 1 to 5) el <- data.frame( from = c(1, 1, 2, 3, 2, 4), to = c(2, 3, 4, 4, 5, 5) ) g_w <- traversal_weights(el, method = "SPC") # --- Classic algorithms (threshold = 1.0, default) ----------------------- # Global: single best source-to-sink path mp_global <- main_path(g_w, type = "global", weight = "SPC") igraph::as_edgelist(mp_global) igraph::vcount(mp_global) # narrow — just the optimal chain # Local: greedy from every source, union of all resulting paths mp_local <- main_path(g_w, type = "local", weight = "SPC") igraph::vcount(mp_local) # Key-route: extend from the single highest-weight edge mp_kr <- main_path(g_w, type = "key_route", weight = "SPC", k = 1L) # Key-route with k = 3: seed from the top 3 edges mp_kr3 <- main_path(g_w, type = "key_route", weight = "SPC", k = 3L) igraph::vcount(mp_kr3) # --- Broadened paths (threshold < 1.0) ----------------------------------- # Global, broadened: include all edges on paths >= 80% of optimal weight mp_broad <- main_path(g_w, type = "global", weight = "SPC", threshold = 0.8) igraph::vcount(mp_broad) # more nodes than mp_global # Local, broadened: at each node follow edges within 90% of the local max mp_local_broad <- main_path(g_w, type = "local", weight = "SPC", threshold = 0.9) # Key-route, broadened: cast a wider seed net around k = 1 mp_kr_broad <- main_path(g_w, type = "key_route", weight = "SPC", k = 1L, threshold = 0.7) # Compare path sizes as threshold decreases sizes <- sapply(c(1.0, 0.9, 0.8, 0.7, 0.5), function(t) { igraph::vcount(main_path(g_w, type = "global", weight = "SPC", threshold = t)) }) names(sizes) <- c("1.0", "0.9", "0.8", "0.7", "0.5") print(sizes)