Skip to content

Commit 3fa3dc0

Browse files
committed
DSL syntax refinement
1 parent 6ee4620 commit 3fa3dc0

103 files changed

Lines changed: 7516 additions & 6363 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/netgraph-dsl/SKILL.md

Lines changed: 137 additions & 91 deletions
Large diffs are not rendered by default.

.claude/skills/netgraph-dsl/references/EXAMPLES.md

Lines changed: 269 additions & 274 deletions
Large diffs are not rendered by default.

.claude/skills/netgraph-dsl/references/REFERENCE.md

Lines changed: 205 additions & 213 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.17.0] - 2026-01-10
9+
10+
### Changed
11+
12+
- **BREAKING**: DSL syntax refinement with renamed fields and restructured expansion blocks; see updated [DSL reference](docs/reference/dsl.md)
13+
814
## [0.16.0] - 2025-12-21
915

1016
### Changed

README.md

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -103,52 +103,55 @@ seed: 42
103103
# Define reusable topology templates
104104
blueprints:
105105
Clos_Fabric:
106-
groups:
107-
spine: {node_count: 2, name_template: "spine{node_num}"}
108-
leaf: {node_count: 4, name_template: "leaf{node_num}"}
109-
adjacency:
106+
nodes:
107+
spine: {count: 2, template: "spine{n}"}
108+
leaf: {count: 4, template: "leaf{n}"}
109+
links:
110110
- source: /leaf
111111
target: /spine
112112
pattern: mesh
113-
link_params: {capacity: 100, cost: 1}
113+
capacity: 100
114+
cost: 1
114115
- source: /spine
115116
target: /leaf
116117
pattern: mesh
117-
link_params: {capacity: 100, cost: 1}
118+
capacity: 100
119+
cost: 1
118120

119121
# Instantiate network from templates
120122
network:
121-
groups:
122-
site1: {use_blueprint: Clos_Fabric}
123-
site2: {use_blueprint: Clos_Fabric}
124-
adjacency:
123+
nodes:
124+
site1: {blueprint: Clos_Fabric}
125+
site2: {blueprint: Clos_Fabric}
126+
links:
125127
- source: {path: site1/spine}
126128
target: {path: site2/spine}
127129
pattern: one_to_one
128-
link_params: {capacity: 50, cost: 10}
130+
capacity: 50
131+
cost: 10
129132

130-
# Define traffic matrix
131-
traffic_matrix_set:
133+
# Define traffic demands
134+
demands:
132135
global_traffic:
133136
- source: ^site1/leaf/
134-
sink: ^site2/leaf/
135-
demand: 100.0
137+
target: ^site2/leaf/
138+
volume: 100.0
136139
mode: combine
137-
flow_policy_config: SHORTEST_PATHS_ECMP
140+
flow_policy: SHORTEST_PATHS_ECMP
138141

139142
# Define analysis workflow
140143
workflow:
141-
- step_type: NetworkStats
144+
- type: NetworkStats
142145
name: stats
143-
- step_type: MaxFlow
146+
- type: MaxFlow
144147
name: site_capacity
145148
source: ^site1/leaf/
146-
sink: ^site2/leaf/
149+
target: ^site2/leaf/
147150
mode: combine
148151
shortest_path: false
149-
- step_type: MaximumSupportedDemand
152+
- type: MaximumSupportedDemand
150153
name: max_demand
151-
matrix_name: global_traffic
154+
demand_set: global_traffic
152155
```
153156
154157
## Repository Structure

docs/examples/basic.md

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,46 +44,40 @@ network:
4444
# Parallel edges between A->B
4545
- source: A
4646
target: B
47-
link_params:
48-
capacity: 1
49-
cost: 1
47+
capacity: 1
48+
cost: 1
5049
- source: A
5150
target: B
52-
link_params:
53-
capacity: 2
54-
cost: 1
51+
capacity: 2
52+
cost: 1
5553
5654
# Parallel edges between B->C
5755
- source: B
5856
target: C
59-
link_params:
60-
capacity: 1
61-
cost: 1
57+
capacity: 1
58+
cost: 1
6259
- source: B
6360
target: C
64-
link_params:
65-
capacity: 2
66-
cost: 1
61+
capacity: 2
62+
cost: 1
6763
6864
# Alternative path A->D->C
6965
- source: A
7066
target: D
71-
link_params:
72-
capacity: 3
73-
cost: 2
67+
capacity: 3
68+
cost: 2
7469
- source: D
7570
target: C
76-
link_params:
77-
capacity: 3
78-
cost: 2
71+
capacity: 3
72+
cost: 2
7973
"""
8074

8175
# Create the network
8276
scenario = Scenario.from_yaml(scenario_yaml)
8377
network = scenario.network
8478
```
8579

86-
Note that here we used a simple `nodes` and `links` structure to directly define the network topology. The optional `seed` parameter ensures reproducible results when using randomized workflow steps. In more complex scenarios, you would typically use `groups` and `adjacency` to define groups of nodes and their connections, or even leverage the `blueprints` to create reusable components. This advanced functionality is explained in the [DSL Reference](../reference/dsl.md) and used in the [Clos Fabric Analysis](clos-fabric.md) example.
80+
Note that here we used a simple `nodes` and `links` structure to directly define the network topology. The optional `seed` parameter ensures reproducible results when using randomized workflow steps. In more complex scenarios, you would typically use node groups with `count` and `template` to define groups of nodes and link rules to define their connections, or even leverage the `blueprints` to create reusable components. This advanced functionality is explained in the [DSL Reference](../reference/dsl.md) and used in the [Clos Fabric Analysis](clos-fabric.md) example.
8781

8882
### Flow Analysis Variants
8983

@@ -138,7 +132,7 @@ result = analyze(network).max_flow_detailed(
138132
)
139133

140134
# Extract flow value and summary
141-
(src_label, sink_label), summary = next(iter(result.items()))
135+
(src_label, target_label), summary = next(iter(result.items()))
142136

143137
print(f"Total flow: {summary.total_flow}")
144138
print(f"Cost distribution: {summary.cost_distribution}")

docs/examples/bundled-scenarios.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ NetGraph ships with ready-to-run scenarios that demonstrate the DSL, workflow st
77
Inspect first, then run:
88

99
```bash
10-
# Inspect (structure, steps, matrices, failure policies)
10+
# Inspect (structure, steps, demands, failure policies)
1111
ngraph inspect scenarios/backbone_clos.yml --detail
1212

1313
# Run and write JSON results next to the scenario (or under --output)
@@ -21,8 +21,8 @@ You can filter output by workflow step names with `--keys` (see each scenario se
2121
- **Purpose**: Toy 4-node full mesh to exercise MSD search, TM placement, and pairwise MaxFlow.
2222
- **Highlights**:
2323

24-
- Failure policy: single link choice (`failure_policy_set.single_link_failure`)
25-
- Traffic matrix: pairwise demands across all nodes (`baseline_traffic_matrix`)
24+
- Failure policy: single link choice (`failures.single_link_failure`)
25+
- Demand set: pairwise demands across all nodes (`baseline_traffic_matrix`)
2626
- Workflow steps: `msd_baseline`, `tm_placement`, `node_to_node_capacity_matrix`
2727

2828
Run:
@@ -40,9 +40,9 @@ ngraph run scenarios/square_mesh.yaml --keys msd_baseline --stdout
4040
- **Purpose**: Small Clos/metro fabric with components, SRLG-like risk groups, and multi-step workflow.
4141
- **Highlights**:
4242

43-
- Uses `blueprints`, attribute-based adjacency selectors, and hardware component attrs
44-
- Failure policy: weighted multi-mode (`failure_policy_set.weighted_modes`)
45-
- Traffic matrix: inter-metro DC flows with TE/WCMP policy
43+
- Uses `blueprints`, attribute-based link selectors, and hardware component attrs
44+
- Failure policy: weighted multi-mode (`failures.weighted_modes`)
45+
- Demand set: inter-metro DC flows with TE/WCMP policy
4646
- Workflow steps: `network_statistics`, `msd_baseline`, `tm_placement`, `cost_power`
4747

4848
Run:
@@ -76,4 +76,4 @@ ngraph run scenarios/nsfnet.yaml --keys node_to_node_capacity_matrix_1 --stdout
7676

7777
## Notes on results
7878

79-
All runs emit a consistent JSON shape with `workflow`, `steps`, and `scenario` sections. Steps like `MaxFlow` and `TrafficMatrixPlacement` store per-iteration lists under `data.flow_results` with `summary` and optional `cost_distribution` or `min_cut` fields. See Reference Workflow for the exact schema.
79+
All runs emit a consistent JSON shape with `workflow`, `steps`, and `scenario` sections. Steps like `MaxFlow` and `TrafficMatrixPlacement` store per-iteration lists under `data.flow_results` with `summary` and optional `cost_distribution` or `min_cut` fields. See Reference -> Workflow for the exact schema.

docs/examples/clos-fabric.md

Lines changed: 44 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Refer to [Tutorial](../getting-started/tutorial.md) for running bundled scenario
99
We'll create two separate 3-tier Clos networks and analyze the maximum flow capacity between them. This scenario showcases:
1010

1111
- Hierarchical blueprint composition
12-
- Complex adjacency patterns
12+
- Complex link patterns
1313
- Flow analysis with different placement policies
1414

1515
## Programmatic scenario
@@ -21,65 +21,61 @@ from ngraph import analyze, Mode, FlowPlacement
2121
scenario_yaml = """
2222
blueprints:
2323
brick_2tier:
24-
groups:
24+
nodes:
2525
t1:
26-
node_count: 8
27-
name_template: "t1-{node_num}"
26+
count: 8
27+
template: "t1-{n}"
2828
t2:
29-
node_count: 8
30-
name_template: "t2-{node_num}"
29+
count: 8
30+
template: "t2-{n}"
3131
32-
adjacency:
32+
links:
3333
- source: /t1
3434
target: /t2
3535
pattern: mesh
36-
link_params:
37-
capacity: 2
38-
cost: 1
36+
capacity: 2
37+
cost: 1
3938
4039
3tier_clos:
41-
groups:
40+
nodes:
4241
b1:
43-
use_blueprint: brick_2tier
42+
blueprint: brick_2tier
4443
b2:
45-
use_blueprint: brick_2tier
44+
blueprint: brick_2tier
4645
spine:
47-
node_count: 64
48-
name_template: "t3-{node_num}"
46+
count: 64
47+
template: "t3-{n}"
4948
50-
adjacency:
49+
links:
5150
- source: b1/t2
5251
target: spine
5352
pattern: one_to_one
54-
link_params:
55-
capacity: 2
56-
cost: 1
53+
capacity: 2
54+
cost: 1
5755
- source: b2/t2
5856
target: spine
5957
pattern: one_to_one
60-
link_params:
61-
capacity: 2
62-
cost: 1
58+
capacity: 2
59+
cost: 1
6360
6461
network:
6562
name: "3tier_clos_network"
6663
version: 1.0
6764
68-
groups:
65+
nodes:
6966
my_clos1:
70-
use_blueprint: 3tier_clos
67+
blueprint: 3tier_clos
7168
7269
my_clos2:
73-
use_blueprint: 3tier_clos
70+
blueprint: 3tier_clos
7471
75-
adjacency:
72+
links:
7673
- source: my_clos1/spine
7774
target: my_clos2/spine
7875
pattern: one_to_one
79-
link_count: 4
80-
link_params:
81-
capacity: 1
82-
cost: 1
76+
count: 4
77+
capacity: 1
78+
cost: 1
8379
"""
8480

8581
# Create and analyze the scenario
@@ -104,7 +100,7 @@ print(f"Maximum flow with ECMP: {max_flow_ecmp}")
104100
The result `{('b1|b2', 'b1|b2'): 256.0}` means:
105101

106102
- **Source**: All t1 nodes in both b1 and b2 segments of my_clos1
107-
- **Sink**: All t1 nodes in both b1 and b2 segments of my_clos2
103+
- **Target**: All t1 nodes in both b1 and b2 segments of my_clos2
108104
- **Capacity**: Maximum flow of 256.0 units
109105

110106
## ECMP vs WCMP: Impact of Link Failures
@@ -133,26 +129,26 @@ from ngraph.scenario import Scenario
133129
scenario_yaml = """
134130
blueprints:
135131
brick_2tier:
136-
groups:
137-
t1: {node_count: 8, name_template: "t1-{node_num}"}
138-
t2: {node_count: 8, name_template: "t2-{node_num}"}
139-
adjacency:
140-
- {source: /t1, target: /t2, pattern: mesh, link_params: {capacity: 2, cost: 1}}
132+
nodes:
133+
t1: {count: 8, template: "t1-{n}"}
134+
t2: {count: 8, template: "t2-{n}"}
135+
links:
136+
- {source: /t1, target: /t2, pattern: mesh, capacity: 2, cost: 1}
141137
3tier_clos:
142-
groups:
143-
b1: {use_blueprint: brick_2tier}
144-
b2: {use_blueprint: brick_2tier}
145-
spine: {node_count: 64, name_template: "t3-{node_num}"}
146-
adjacency:
147-
- {source: b1/t2, target: spine, pattern: one_to_one, link_params: {capacity: 2, cost: 1}}
148-
- {source: b2/t2, target: spine, pattern: one_to_one, link_params: {capacity: 2, cost: 1}}
138+
nodes:
139+
b1: {blueprint: brick_2tier}
140+
b2: {blueprint: brick_2tier}
141+
spine: {count: 64, template: "t3-{n}"}
142+
links:
143+
- {source: b1/t2, target: spine, pattern: one_to_one, capacity: 2, cost: 1}
144+
- {source: b2/t2, target: spine, pattern: one_to_one, capacity: 2, cost: 1}
149145
network:
150146
name: 3tier_clos_network
151-
groups:
152-
my_clos1: {use_blueprint: 3tier_clos}
153-
my_clos2: {use_blueprint: 3tier_clos}
154-
adjacency:
155-
- {source: my_clos1/spine, target: my_clos2/spine, pattern: one_to_one, link_count: 4, link_params: {capacity: 1, cost: 1}}
147+
nodes:
148+
my_clos1: {blueprint: 3tier_clos}
149+
my_clos2: {blueprint: 3tier_clos}
150+
links:
151+
- {source: my_clos1/spine, target: my_clos2/spine, pattern: one_to_one, count: 4, capacity: 1, cost: 1}
156152
"""
157153

158154
scenario = Scenario.from_yaml(scenario_yaml)

docs/getting-started/tutorial.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ This guide shows the fastest way to run a scenario from the CLI and a minimal pr
55
## CLI: run and inspect
66

77
```bash
8-
# Inspect (validate and preview structure, steps, matrices)
8+
# Inspect (validate and preview structure, steps, demands)
99
ngraph inspect scenarios/square_mesh.yaml --detail
1010

1111
# Run and store results (JSON) next to the scenario or under --output
@@ -28,9 +28,9 @@ network:
2828
A: {}
2929
B: {}
3030
links:
31-
- {source: A, target: B, link_params: {capacity: 10.0, cost: 1.0}}
31+
- {source: A, target: B, capacity: 10.0, cost: 1.0}
3232
workflow:
33-
- step_type: NetworkStats
33+
- type: NetworkStats
3434
name: baseline_stats
3535
"""
3636

0 commit comments

Comments
 (0)