Skip to content

Commit 366ed59

Browse files
committed
Add NetworkView class for filtered access to Network objects
1 parent 388bfef commit 366ed59

6 files changed

Lines changed: 1317 additions & 303 deletions

File tree

docs/reference/api-full.md

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ For a curated, example-driven API guide, see **[api.md](api.md)**.
1010
> - **[CLI Reference](cli.md)** - Command-line interface
1111
> - **[DSL Reference](dsl.md)** - YAML syntax guide
1212
13-
**Generated from source code on:** July 05, 2025 at 16:54 UTC
13+
**Generated from source code on:** July 05, 2025 at 19:29 UTC
1414

15-
**Modules auto-discovered:** 50
15+
**Modules auto-discovered:** 51
1616

1717
---
1818

@@ -578,8 +578,6 @@ Attributes:
578578
links (Dict[str, Link]): Mapping from link ID -> Link object.
579579
risk_groups (Dict[str, RiskGroup]): Top-level risk groups by name.
580580
attrs (Dict[str, Any]): Optional metadata about the network.
581-
_cached_graph (Optional[StrictMultiDiGraph]): Cached graph representation of the network.
582-
_graph_cache_valid (bool): Indicates whether the cached graph is valid.
583581

584582
**Attributes:**
585583

@@ -640,7 +638,7 @@ the key in the Network's node dictionary.
640638

641639
Attributes:
642640
name (str): Unique identifier for the node.
643-
disabled (bool): Whether the node is disabled (excluded from calculations).
641+
disabled (bool): Whether the node is disabled in the scenario configuration.
644642
risk_groups (Set[str]): Set of risk group names this node belongs to.
645643
attrs (Dict[str, Any]): Additional metadata (e.g., coordinates, region).
646644

@@ -677,6 +675,73 @@ Returns:
677675

678676
---
679677

678+
## ngraph.network_view
679+
680+
NetworkView class for read-only filtered access to Network objects.
681+
682+
### NetworkView
683+
684+
Read-only overlay that hides selected nodes/links from a base Network.
685+
686+
NetworkView provides filtered access to a Network where both scenario-disabled
687+
elements (Node.disabled, Link.disabled) and analysis-excluded elements are
688+
hidden from algorithms. This enables failure simulation and what-if analysis
689+
without mutating the base Network.
690+
691+
Multiple NetworkView instances can safely operate on the same base Network
692+
concurrently, each with different exclusion sets.
693+
694+
Example:
695+
```python
696+
# Create view excluding specific nodes for failure analysis
697+
view = NetworkView.from_failure_sets(
698+
base_network,
699+
failed_nodes=["node1", "node2"],
700+
failed_links=["link1"]
701+
)
702+
703+
# Run analysis on filtered topology
704+
flows = view.max_flow("source.*", "sink.*")
705+
```
706+
707+
Attributes:
708+
_base: The underlying Network object.
709+
_excluded_nodes: Frozen set of node names to exclude from analysis.
710+
_excluded_links: Frozen set of link IDs to exclude from analysis.
711+
712+
**Attributes:**
713+
714+
- `_base` ('Network')
715+
- `_excluded_nodes` (frozenset[str]) = frozenset()
716+
- `_excluded_links` (frozenset[str]) = frozenset()
717+
718+
**Methods:**
719+
720+
- `from_failure_sets(base: "'Network'", failed_nodes: 'Iterable[str]' = (), failed_links: 'Iterable[str]' = ()) -> "'NetworkView'"`
721+
- Create a NetworkView with specified failure exclusions.
722+
- `is_link_hidden(self, link_id: 'str') -> 'bool'`
723+
- Check if a link is hidden in this view.
724+
- `is_node_hidden(self, name: 'str') -> 'bool'`
725+
- Check if a node is hidden in this view.
726+
- `max_flow(self, source_path: 'str', sink_path: 'str', mode: 'str' = 'combine', shortest_path: 'bool' = False, flow_placement: "Optional['FlowPlacement']" = None) -> 'Dict[Tuple[str, str], float]'`
727+
- Compute maximum flow between node groups in this view.
728+
- `max_flow_detailed(self, source_path: 'str', sink_path: 'str', mode: 'str' = 'combine', shortest_path: 'bool' = False, flow_placement: "Optional['FlowPlacement']" = None) -> "Dict[Tuple[str, str], Tuple[float, 'FlowSummary', 'StrictMultiDiGraph']]"`
729+
- Compute maximum flow with complete analytics and graph.
730+
- `max_flow_with_graph(self, source_path: 'str', sink_path: 'str', mode: 'str' = 'combine', shortest_path: 'bool' = False, flow_placement: "Optional['FlowPlacement']" = None) -> "Dict[Tuple[str, str], Tuple[float, 'StrictMultiDiGraph']]"`
731+
- Compute maximum flow and return flow-assigned graph.
732+
- `max_flow_with_summary(self, source_path: 'str', sink_path: 'str', mode: 'str' = 'combine', shortest_path: 'bool' = False, flow_placement: "Optional['FlowPlacement']" = None) -> "Dict[Tuple[str, str], Tuple[float, 'FlowSummary']]"`
733+
- Compute maximum flow with detailed analytics summary.
734+
- `saturated_edges(self, source_path: 'str', sink_path: 'str', mode: 'str' = 'combine', tolerance: 'float' = 1e-10, shortest_path: 'bool' = False, flow_placement: "Optional['FlowPlacement']" = None) -> 'Dict[Tuple[str, str], List[Tuple[str, str, str]]]'`
735+
- Identify saturated edges in max flow solutions.
736+
- `select_node_groups_by_path(self, path: 'str') -> "Dict[str, List['Node']]"`
737+
- Select and group visible nodes matching a regex pattern.
738+
- `sensitivity_analysis(self, source_path: 'str', sink_path: 'str', mode: 'str' = 'combine', change_amount: 'float' = 1.0, shortest_path: 'bool' = False, flow_placement: "Optional['FlowPlacement']" = None) -> 'Dict[Tuple[str, str], Dict[Tuple[str, str, str], float]]'`
739+
- Perform sensitivity analysis on capacity changes.
740+
- `to_strict_multidigraph(self, add_reverse: 'bool' = True) -> "'StrictMultiDiGraph'"`
741+
- Create a StrictMultiDiGraph representation of this view.
742+
743+
---
744+
680745
## ngraph.profiling
681746

682747
Performance profiling instrumentation for NetGraph workflow execution.

docs/reference/api.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,37 @@ network = Network()
4646
- `add_node(name, **attrs)` - Add network node
4747
- `add_link(source, target, **params)` - Add network link
4848

49+
### NetworkView
50+
Provides a read-only filtered view of a Network for failure analysis without modifying the base network.
51+
52+
```python
53+
from ngraph.network_view import NetworkView
54+
55+
# Create view with specific nodes/links excluded (failure simulation)
56+
view = NetworkView.from_failure_sets(
57+
network,
58+
failed_nodes=["spine1", "spine2"],
59+
failed_links=["link_id_123"]
60+
)
61+
62+
# Run analysis on filtered topology
63+
max_flow = view.max_flow("source_path", "sink_path")
64+
```
65+
66+
**Key Features:**
67+
68+
- Read-only overlay that hides disabled and excluded elements
69+
- Supports concurrent analysis with different failure scenarios
70+
- Identical API to Network for flow analysis methods
71+
- Cached graph building for performance
72+
73+
**Key Methods:**
74+
75+
- `from_failure_sets(network, failed_nodes, failed_links)` - Create view with exclusions
76+
- `max_flow()`, `saturated_edges()`, `sensitivity_analysis()` - Same as Network
77+
- `is_node_hidden(name)` - Check if node is visible in this view
78+
- `is_link_hidden(link_id)` - Check if link is visible in this view
79+
4980
### NetworkExplorer
5081
Provides network visualization and exploration capabilities.
5182

@@ -157,6 +188,8 @@ manager = FailureManager(
157188
)
158189
```
159190

191+
**Note:** For failure analysis without modifying the base network, consider using `NetworkView` instead of directly disabling nodes/links. This allows concurrent analysis of different failure scenarios.
192+
160193
### Risk Groups
161194
Model correlated component failures.
162195

docs/reference/dsl.md

Lines changed: 9 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -488,13 +488,17 @@ workflow:
488488

489489
**Available Workflow Steps:**
490490

491-
- **`BuildGraph`**: Builds the network graph from the scenario definition
491+
- **`BuildGraph`**: Builds a StrictMultiDiGraph from scenario.network
492+
- **`CapacityProbe`**: Probes capacity (max flow) between selected groups of nodes
493+
- **`NetworkStats`**: Computes basic capacity and degree statistics
492494
- **`EnableNodes`**: Enables previously disabled nodes matching a path pattern
493-
- **`DistributeExternalConnectivity`**: Creates external connectivity across attachment points
494-
- **`CapacityProbe`**: Probes maximum flow capacity between node groups
495+
- **`DistributeExternalConnectivity`**: Distributes external connectivity to attachment nodes
495496
- **`CapacityEnvelopeAnalysis`**: Performs Monte-Carlo capacity analysis across failure scenarios
496-
- **`NetworkStats`**: Computes basic node/link capacity and degree statistics
497-
- **`NotebookExport`**: Saves scenario results to a Jupyter notebook with configurable content and visualizations
497+
498+
**Note:** NetGraph separates scenario-wide state (persistent configuration) from analysis-specific state (temporary failures). The `NetworkView` class provides a clean way to analyze networks under different failure conditions without modifying the base network, enabling concurrent analysis of multiple failure scenarios.
499+
500+
- **NetworkTransform steps** (like `EnableNodes`, `DistributeExternalConnectivity`) permanently modify the Network's scenario state
501+
- **Analysis steps** (like `CapacityProbe`, `CapacityEnvelopeAnalysis`) should use NetworkView for temporary failure simulation to avoid corrupting the scenario
498502

499503
```yaml
500504
- step_type: NotebookExport
@@ -582,139 +586,3 @@ When using capturing groups `(...)` in regex patterns, NetGraph groups matching
582586
# All matching nodes are grouped under the original pattern string:
583587
# "SEA/spine/switch-\\d+": [SEA/spine/switch-1, SEA/spine/switch-2, ...]
584588
```
585-
586-
### Usage in Different DSL Sections
587-
588-
**Adjacency Matching:**
589-
590-
In `adjacency` blocks (both in blueprints and top-level network):
591-
592-
- `source` and `target` fields accept regex patterns
593-
- Blueprint paths can be relative (no leading `/`) or absolute (with leading `/`)
594-
- Relative paths are resolved relative to the blueprint instance's path
595-
596-
```yaml
597-
adjacency:
598-
- source: "^my_clos1/leaf/switch-\\d+$"
599-
target: "^my_clos1/spine/switch-\\d+$"
600-
pattern: mesh
601-
```
602-
603-
**Node and Link Overrides:**
604-
605-
Use `path` field for nodes or `source`/`target` for links:
606-
607-
```yaml
608-
node_overrides:
609-
- path: ^my_clos1/spine/switch-(1|3|5)$ # Specific switches
610-
disabled: true
611-
attrs:
612-
maintenance_mode: "active"
613-
614-
link_overrides:
615-
- source: ^my_clos1/leaf/switch-1$
616-
target: ^my_clos1/spine/switch-1$
617-
disabled: true
618-
```
619-
620-
**Workflow Steps:**
621-
622-
Workflow steps like `EnableNodes`, `CapacityProbe`, etc., use path patterns:
623-
624-
```yaml
625-
workflow:
626-
- step_type: EnableNodes
627-
path: "^my_clos2/leaf/switch-\\d+$" # All leaf switches
628-
count: 4
629-
630-
- step_type: CapacityProbe
631-
source_path: "^(dc\\d+)/client" # Capturing group creates per-DC groups
632-
sink_path: "^(dc\\d+)/server"
633-
mode: pairwise # Test dc1 client -> dc1 server, dc2 client -> dc2 server
634-
635-
- step_type: CapacityEnvelopeAnalysis
636-
source_path: "(.+)" # Captures each node as its own group
637-
sink_path: "(.+)" # Creates N×N any-to-any analysis
638-
mode: pairwise # Required for per-node analysis
639-
```
640-
641-
### Any-to-Any Analysis Pattern
642-
643-
The pattern `(.+)` is a useful regex for network analysis in workflow steps like `CapacityProbe` and `CapacityEnvelopeAnalysis`:
644-
645-
- **Individual Node Groups**: The capturing group `(.+)` matches each node name, creating separate groups for each node
646-
- **Automatic Combinations**: In pairwise mode, this creates N×N flow analysis for N nodes
647-
- **Full Coverage**: Tests connectivity between every pair of nodes in the network
648-
649-
**Example Use Cases:**
650-
```yaml
651-
# Test capacity between every pair of nodes in the network
652-
- step_type: CapacityEnvelopeAnalysis
653-
source_path: "(.+)" # Every node as source
654-
sink_path: "(.+)" # Every node as sink
655-
mode: pairwise # Creates all node-to-node combinations
656-
iterations: 100 # Monte-Carlo analysis across failures
657-
658-
# Test capacity from all datacenter nodes to all others
659-
- step_type: CapacityProbe
660-
source_path: "(datacenter.*)" # Each datacenter node individually
661-
sink_path: "(datacenter.*)" # Each datacenter node individually
662-
mode: pairwise # All datacenter-to-datacenter flows
663-
```
664-
665-
### Best Practices
666-
667-
1. **Use anchors for precision**: Always use `$` at the end if you want exact matches
668-
2. **Escape special characters in YAML**:
669-
- For digit patterns: Use `\\d+` instead of `\d+` in quoted YAML strings
670-
- For simple wildcards: `.*/spine/.*` works directly in YAML
671-
- In Python code: Use raw strings `r"pattern"` or double escaping `"\\d+"`
672-
3. **Test patterns**: Use capturing groups strategically to create meaningful node groups
673-
4. **Relative vs absolute paths**: In blueprints, prefer relative paths for reusability
674-
5. **Group meaningfully**: Design capturing groups to create logical node groupings for workflow steps
675-
676-
### Common Pitfalls
677-
678-
1. **Missing end anchors**: `switch-1` matches `switch-10`, `switch-11`, etc.
679-
- Fix: Use `switch-1$` for exact match
680-
681-
2. **YAML escaping inconsistencies**:
682-
- Simple patterns like `.*` work directly: `path: .*/spine/.*`
683-
- Complex patterns need escaping: `path: "spine-\\d+$"`
684-
- Python code always needs proper escaping: `"(SEA/leaf\\d)"`
685-
686-
3. **Greedy matching**: `.*` can match more than intended
687-
- Fix: Use specific patterns like `[^/]+` to match within path segments
688-
689-
4. **Empty groups**: Patterns that don't match any nodes create empty results
690-
- Fix: Test patterns against your actual node names
691-
692-
### Regex Escaping Reference
693-
694-
NetGraph processes regex patterns differently depending on context:
695-
696-
**YAML Files (Scenarios):**
697-
```yaml
698-
# Simple wildcards - no escaping needed
699-
adjacency:
700-
- source: .*/spine/.* # Matches any spine nodes
701-
target: .*/spine/.*
702-
703-
# Complex patterns - use quotes and double backslashes
704-
node_overrides:
705-
- path: "spine-\\d+$" # Matches spine-1, spine-2, etc.
706-
attrs:
707-
hw_type: "high_performance"
708-
709-
# Traffic matrix set with capturing groups
710-
traffic_matrix_set:
711-
default:
712-
- source_path: "my_clos1/b.*/t1" # Works in YAML
713-
sink_path: "my_clos2/b.*/t1"
714-
```
715-
716-
**Python Code:**
717-
```python
718-
# Use raw strings (preferred)
719-
pattern = r"^S(\d+)$"
720-
```

0 commit comments

Comments
 (0)