Skip to content

Commit c155539

Browse files
committed
MSD (Maximum Supported Demand) workstep
1 parent fa54fdc commit c155539

File tree

5 files changed

+565
-18
lines changed

5 files changed

+565
-18
lines changed

docs/reference/api-full.md

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ Quick links:
1212
- [CLI Reference](cli.md)
1313
- [DSL Reference](dsl.md)
1414

15-
Generated from source code on: August 11, 2025 at 12:27 UTC
15+
Generated from source code on: August 11, 2025 at 19:00 UTC
1616

17-
Modules auto-discovered: 65
17+
Modules auto-discovered: 66
1818

1919
---
2020

@@ -1194,6 +1194,15 @@ Implements Dijkstra-like SPF with pluggable edge-selection policies and a
11941194
Yen-like KSP generator. Specialized fast paths exist for common selection
11951195
strategies without exclusions.
11961196

1197+
Notes:
1198+
When a destination node is known, SPF supports an optimized mode that
1199+
terminates once the destination's minimal distance is settled. In this mode:
1200+
1201+
- The destination node is not expanded (no neighbor relaxation from ``dst``).
1202+
- The algorithm continues processing any nodes with equal distance to capture
1203+
1204+
equal-cost predecessors (needed by proportional flow placement).
1205+
11971206
### ksp(graph: ngraph.graph.strict_multidigraph.StrictMultiDiGraph, src_node: Hashable, dst_node: Hashable, edge_select: ngraph.algorithms.base.EdgeSelect = <EdgeSelect.ALL_MIN_COST: 1>, edge_select_func: Optional[Callable[[ngraph.graph.strict_multidigraph.StrictMultiDiGraph, Hashable, Hashable, Dict[Hashable, Dict[str, Any]], Set[Hashable], Set[Hashable]], Tuple[Union[int, float], List[Hashable]]]] = None, max_k: Optional[int] = None, max_path_cost: Union[int, float] = inf, max_path_cost_factor: Optional[float] = None, multipath: bool = True, excluded_edges: Optional[Set[Hashable]] = None, excluded_nodes: Optional[Set[Hashable]] = None) -> Iterator[Tuple[Dict[Hashable, Union[int, float]], Dict[Hashable, Dict[Hashable, List[Hashable]]]]]
11981207

11991208
Yield up to k shortest paths using a Yen-like algorithm.
@@ -1220,7 +1229,7 @@ Args:
12201229
Yields:
12211230
Tuple of ``(costs, pred)`` per discovered path in ascending cost order.
12221231

1223-
### spf(graph: ngraph.graph.strict_multidigraph.StrictMultiDiGraph, src_node: Hashable, edge_select: ngraph.algorithms.base.EdgeSelect = <EdgeSelect.ALL_MIN_COST: 1>, edge_select_func: Optional[Callable[[ngraph.graph.strict_multidigraph.StrictMultiDiGraph, Hashable, Hashable, Dict[Hashable, Dict[str, Any]], Set[Hashable], Set[Hashable]], Tuple[Union[int, float], List[Hashable]]]] = None, multipath: bool = True, excluded_edges: Optional[Set[Hashable]] = None, excluded_nodes: Optional[Set[Hashable]] = None) -> Tuple[Dict[Hashable, Union[int, float]], Dict[Hashable, Dict[Hashable, List[Hashable]]]]
1232+
### spf(graph: ngraph.graph.strict_multidigraph.StrictMultiDiGraph, src_node: Hashable, edge_select: ngraph.algorithms.base.EdgeSelect = <EdgeSelect.ALL_MIN_COST: 1>, edge_select_func: Optional[Callable[[ngraph.graph.strict_multidigraph.StrictMultiDiGraph, Hashable, Hashable, Dict[Hashable, Dict[str, Any]], Set[Hashable], Set[Hashable]], Tuple[Union[int, float], List[Hashable]]]] = None, multipath: bool = True, excluded_edges: Optional[Set[Hashable]] = None, excluded_nodes: Optional[Set[Hashable]] = None, dst_node: Optional[Hashable] = None) -> Tuple[Dict[Hashable, Union[int, float]], Dict[Hashable, Dict[Hashable, List[Hashable]]]]
12241233

12251234
Compute shortest paths from a source node.
12261235

@@ -1239,6 +1248,11 @@ Args:
12391248
multipath: Whether to record multiple same-cost paths.
12401249
excluded_edges: A set of edge IDs to ignore in the graph.
12411250
excluded_nodes: A set of node IDs to ignore in the graph.
1251+
dst_node: Optional destination node. If provided, SPF avoids expanding
1252+
from the destination and performs early termination once the next
1253+
candidate in the heap would exceed the settled distance for
1254+
``dst_node``. This preserves equal-cost predecessors while avoiding
1255+
unnecessary relaxations beyond the destination.
12421256

12431257
Returns:
12441258
tuple[dict[NodeID, Cost], dict[NodeID, dict[NodeID, list[EdgeID]]]]:
@@ -2625,6 +2639,59 @@ Attributes:
26252639

26262640
---
26272641

2642+
## ngraph.workflow.maximum_supported_demand
2643+
2644+
Maximum Supported Demand (MSD) search workflow step.
2645+
2646+
Search for the largest scaling factor ``alpha`` such that the selected traffic
2647+
matrix is feasible under the demand placement procedure. The search brackets a
2648+
feasible/infeasible interval, then performs bisection on feasibility.
2649+
2650+
This implementation provides the hard-feasibility rule only: every OD must be
2651+
fully placed. The step records search parameters, the decision rule, and the
2652+
original (unscaled) demands so the result is interpretable without the scenario.
2653+
2654+
### MaximumSupportedDemandAnalysis
2655+
2656+
Search for Maximum Supported Demand (MSD) by scaling and bisection.
2657+
2658+
Args:
2659+
matrix_name: Name of the traffic matrix to scale and test.
2660+
acceptance_rule: Only "hard" is implemented: all OD pairs must be fully placed.
2661+
alpha_start: Initial guess for alpha.
2662+
growth_factor: Factor g>1 to expand/shrink during bracketing.
2663+
alpha_min: Minimum alpha allowed during bracketing.
2664+
alpha_max: Maximum alpha allowed during bracketing.
2665+
resolution: Stop when upper-lower <= resolution.
2666+
max_bracket_iters: Limit on growth/shrink iterations during bracketing.
2667+
max_bisect_iters: Limit on iterations during bisection.
2668+
seeds_per_alpha: Number of repeated runs per alpha; alpha is feasible if
2669+
majority of seeds satisfy the rule. Deterministic policies will yield identical results.
2670+
placement_rounds: Rounds passed to TrafficManager.place_all_demands().
2671+
2672+
**Attributes:**
2673+
2674+
- `name` (str)
2675+
- `seed` (Optional[int])
2676+
- `matrix_name` (str) = default
2677+
- `acceptance_rule` (str) = hard
2678+
- `alpha_start` (float) = 1.0
2679+
- `growth_factor` (float) = 2.0
2680+
- `alpha_min` (float) = 1e-06
2681+
- `alpha_max` (float) = 1000000000.0
2682+
- `resolution` (float) = 0.01
2683+
- `max_bracket_iters` (int) = 32
2684+
- `max_bisect_iters` (int) = 32
2685+
- `seeds_per_alpha` (int) = 1
2686+
- `placement_rounds` (int | str) = auto
2687+
2688+
**Methods:**
2689+
2690+
- `execute(self, scenario: "'Scenario'") -> 'None'` - Execute the workflow step with logging and metadata storage.
2691+
- `run(self, scenario: "'Any'") -> 'None'` - Execute MSD search and store results.
2692+
2693+
---
2694+
26282695
## ngraph.workflow.network_stats
26292696

26302697
Workflow step for basic node and link statistics.

ngraph/workflow/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .base import WorkflowStep, register_workflow_step
44
from .build_graph import BuildGraph
55
from .capacity_envelope_analysis import CapacityEnvelopeAnalysis
6+
from .maximum_supported_demand import MaximumSupportedDemandAnalysis
67
from .network_stats import NetworkStats
78
from .traffic_matrix_placement_analysis import TrafficMatrixPlacementAnalysis
89

@@ -13,4 +14,5 @@
1314
"CapacityEnvelopeAnalysis",
1415
"NetworkStats",
1516
"TrafficMatrixPlacementAnalysis",
17+
"MaximumSupportedDemandAnalysis",
1618
]

0 commit comments

Comments
 (0)