|
Download tasks/task3.md from HWresearch/GNN4Colliders: direct link, hf CLI and curl.
- Browser
- Download file 12.5 kB
-
https://huggingface.co/HWresearch/GNN4Colliders/resolve/main/tasks/task3.md
- Command line
-
hf download hf://HWresearch/GNN4Colliders/tasks/task3.md
-
curl -L -o task3.md https://huggingface.co/HWresearch/GNN4Colliders/resolve/main/tasks/task3.md
12.5 kB
| # Task 3: Characterize Legacy Data and Graph Behavior | |
| Build a deterministic characterization/parity test suite for the active legacy ROOT-GNN preprocessing path. | |
| The ROOT-GNN development environment is now expected to include working PyTorch and DGL support. | |
| Do not implement the new production data pipeline yet. | |
| Before making changes, read: | |
| ```text | |
| AGENTS.md | |
| docs/architecture.md | |
| docs/migration.md | |
| ``` | |
| Then inspect the relevant legacy implementation under: | |
| ```text | |
| legacy/root_gnn_dgl/ | |
| ``` | |
| Focus only on the active data/graph behavior required by the standard ROOT-GNN workflow. | |
| --- | |
| # Goal | |
| Capture the externally observable behavior of the legacy preprocessing stack so that the new implementation can later be rewritten against explicit parity tests. | |
| The relevant flow is: | |
| ```text | |
| ROOT/Awkward event data | |
| -> | |
| node feature construction | |
| -> | |
| graph topology | |
| -> | |
| edge feature construction | |
| -> | |
| labels / tracking / global features | |
| ``` | |
| The tests must characterize what the legacy implementation **actually does**. | |
| Do not encode assumptions solely because they appear in documentation. | |
| If documentation, previous expectations, and observed legacy behavior disagree, treat the running legacy implementation as the behavior to characterize and document the discrepancy. | |
| --- | |
| # Environment validation | |
| Before writing or modifying parity tests, verify that the ROOT-GNN environment is functional. | |
| Run: | |
| ```bash | |
| uv sync --extra root-gnn | |
| uv run python -c "import torch; print(torch.__version__)" | |
| uv run python -c "import dgl; print(dgl.__version__)" | |
| ``` | |
| DGL-dependent parity tests must not silently skip because DGL is absent. | |
| If DGL cannot import, stop and report the environment failure rather than treating skipped tests as successful characterization. | |
| --- | |
| # 1. Node feature characterization | |
| Characterize the active legacy node-feature construction. | |
| Verify: | |
| * feature count | |
| * feature ordering | |
| * feature values | |
| * dtype | |
| * shape | |
| * concatenation across object types where applicable | |
| * feature scaling behavior | |
| The active schema is expected to include: | |
| ```text | |
| pt | |
| eta | |
| phi | |
| energy | |
| btag | |
| charge | |
| node_type | |
| ``` | |
| But verify this against the legacy implementation rather than assuming it. | |
| Characterize derived behavior including: | |
| ```text | |
| CALC_E = pt * cosh(eta) | |
| ``` | |
| if that is what the active legacy path actually implements. | |
| Also verify: | |
| * constant-valued branches | |
| * `NODE_TYPE` | |
| * scale application | |
| * object ordering when multiple object types are combined | |
| Use explicit expected arrays where practical. | |
| --- | |
| # 2. Graph topology characterization | |
| Characterize the graph produced by the active legacy graph builder. | |
| Verify: | |
| * whether the graph is directed | |
| * whether self-loops are present | |
| * number of nodes | |
| * number of edges | |
| * source indices | |
| * destination indices | |
| * edge ordering if deterministic | |
| * behavior for small graph sizes | |
| Do not assume a two-node fully connected directed graph has four edges. | |
| Explicitly characterize the observed behavior. | |
| For example, if the legacy implementation produces: | |
| ```text | |
| 0 -> 1 | |
| 1 -> 0 | |
| ``` | |
| for a two-node graph, encode that exact behavior. | |
| If the topology is fully connected without self-loops, verify the expected edge count: | |
| ```text | |
| N * (N - 1) | |
| ``` | |
| for multiple values of `N`. | |
| At minimum test: | |
| ```text | |
| N = 1 | |
| N = 2 | |
| N = 3 | |
| ``` | |
| where supported by the legacy implementation. | |
| For edge ordering: | |
| * assert exact ordering only if it is deterministic and observable | |
| * otherwise test topology independent of ordering and document the ambiguity | |
| --- | |
| # 3. Edge feature characterization | |
| Characterize the active legacy edge-feature construction. | |
| Verify that edge features correspond to: | |
| ```text | |
| deta | |
| dphi | |
| dR | |
| ``` | |
| in the actual stored order. | |
| Test at least one case where phi wrapping matters. | |
| For example, use objects near: | |
| ```text | |
| phi = +pi | |
| phi = -pi | |
| ``` | |
| so that naive subtraction differs from wrapped angular distance. | |
| Verify: | |
| ```text | |
| dR = sqrt(deta^2 + dphi^2) | |
| ``` | |
| if that is the actual legacy behavior. | |
| Important: | |
| Expected edge-feature arrays must correspond exactly to the graph edges produced by the legacy implementation. | |
| Do not duplicate expectations for edges that do not exist. | |
| Where ordering is deterministic, verify the feature associated with each `(src, dst)` pair. | |
| --- | |
| # 4. Tracking semantics | |
| Characterize tracking information. | |
| Verify at minimum the observed semantics of: | |
| ```text | |
| tracking[:, 0] | |
| tracking[:, 1] | |
| ``` | |
| Expected meanings from the architecture documentation are: | |
| ```text | |
| column 0 -> fold identifier | |
| column 1 -> event weight | |
| ``` | |
| Confirm those semantics against the legacy implementation. | |
| Also characterize: | |
| * dtype | |
| * shape | |
| * whether tracking information is mutated during dataset processing | |
| * behavior of negative or non-unit weights where easily testable | |
| Do not expand into training-weight semantics yet. | |
| --- | |
| # 5. Labels | |
| Characterize labels produced by the active standard dataset path. | |
| Verify: | |
| * shape | |
| * dtype | |
| * scalar vs vector representation | |
| * binary-task representation where applicable | |
| * multiclass representation where practical | |
| Focus on the active configurations. | |
| Do not characterize every experimental loss or task variant. | |
| --- | |
| # 6. Global features | |
| Characterize global-feature behavior in the active path. | |
| Verify: | |
| * whether globals are present | |
| * shape | |
| * dtype | |
| * empty/default behavior when global features are unused | |
| Do not invent a new global-feature abstraction. | |
| The purpose is only to record legacy behavior. | |
| --- | |
| # 7. Fixtures | |
| Use deterministic fixtures under: | |
| ```text | |
| tests/fixtures/ | |
| ``` | |
| Prefer, in order: | |
| 1. small in-memory NumPy/Awkward objects | |
| 2. a very small ROOT file only where actual ROOT I/O must be tested | |
| 3. compact stored expected outputs only when inline arrays become unwieldy | |
| Avoid large external datasets. | |
| Fixtures should exercise meaningful cases such as: | |
| * one object | |
| * two objects | |
| * three or more objects | |
| * multiple object types if relevant | |
| * nontrivial eta values | |
| * phi wrapping across `-pi/pi` | |
| * different node types | |
| * non-unit event weights | |
| Test empty object collections only if the active legacy path supports them meaningfully. | |
| Do not invent impossible legacy inputs just to increase coverage. | |
| --- | |
| # 8. Test organization | |
| Place characterization tests under: | |
| ```text | |
| tests/parity/ | |
| ``` | |
| A reasonable organization is: | |
| ```text | |
| tests/parity/ | |
| conftest.py | |
| test_legacy_node_features.py | |
| test_legacy_graph_and_edges.py | |
| test_legacy_tracking.py | |
| test_legacy_labels_and_globals.py | |
| ``` | |
| Use fewer files if that produces clearer tests. | |
| Shared legacy import/setup helpers may live in: | |
| ```text | |
| tests/parity/conftest.py | |
| ``` | |
| Do not copy production functions from the legacy tree into tests. | |
| Tests should invoke the legacy implementation directly. | |
| --- | |
| # 9. Legacy imports | |
| Avoid permanently modifying Python import paths outside the test process. | |
| If the legacy package requires path adjustment because it is not installable, isolate that behavior in test setup. | |
| Do not modify: | |
| ```text | |
| legacy/root_gnn_dgl/ | |
| ``` | |
| to make imports easier. | |
| Do not introduce repository-wide `sys.path` hacks into production code. | |
| --- | |
| # 10. Expected outputs | |
| Prefer readable explicit expectations. | |
| For example: | |
| ```python | |
| expected_features = torch.tensor( | |
| [ | |
| [...], | |
| [...], | |
| ], | |
| dtype=torch.float32, | |
| ) | |
| ``` | |
| For topology: | |
| ```python | |
| expected_src = torch.tensor([...]) | |
| expected_dst = torch.tensor([...]) | |
| ``` | |
| Use exact equality for: | |
| * shapes | |
| * integer IDs | |
| * node-type codes | |
| * edge endpoints | |
| * fold values | |
| where deterministic. | |
| Use numerical comparison for floating-point values. | |
| Avoid opaque snapshot testing unless there is a strong reason. | |
| --- | |
| # 11. Floating-point tolerances | |
| Use explicit tolerances for numerical parity. | |
| For normal float32 feature calculations, prefer something approximately like: | |
| ```python | |
| torch.testing.assert_close( | |
| actual, | |
| expected, | |
| rtol=1e-5, | |
| atol=1e-6, | |
| ) | |
| ``` | |
| unless observed legacy behavior requires a different tolerance. | |
| Do not use unnecessarily loose tolerances. | |
| If a different tolerance is required, explain why. | |
| --- | |
| # 12. Characterization vs specification | |
| These tests are characterization tests. | |
| They answer: | |
| > What does the legacy system currently do? | |
| They do not automatically answer: | |
| > What should the redesigned system do forever? | |
| When unusual behavior is discovered, classify it as one of: | |
| ```text | |
| compatibility requirement | |
| legacy observation | |
| ambiguous behavior | |
| likely bug requiring later design decision | |
| ``` | |
| Do not silently "fix" questionable behavior in this task. | |
| --- | |
| # 13. Known graph expectation correction | |
| A previous test incorrectly expected four edges for a two-node graph. | |
| The running legacy implementation produced two edges. | |
| Investigate and characterize this behavior explicitly. | |
| If confirmed, the likely topology is: | |
| ```text | |
| directed fully connected graph | |
| without self-loops | |
| ``` | |
| which gives: | |
| ```text | |
| num_edges = N * (N - 1) | |
| ``` | |
| Do not modify legacy code to make it match the old test expectation. | |
| Update the parity test to match actual observed behavior. | |
| Also verify the actual `(src, dst)` pairs and corresponding edge features. | |
| --- | |
| # 14. Documentation of ambiguities | |
| Record meaningful discoveries in: | |
| ```text | |
| docs/migration.md | |
| ``` | |
| or a concise dedicated section if appropriate. | |
| Potential ambiguities include: | |
| * exact edge ordering | |
| * single-node graph behavior | |
| * empty graph behavior | |
| * missing ROOT branches | |
| * phi wrapping convention | |
| * negative weights | |
| * object concatenation ordering | |
| * shape behavior for unused global features | |
| Only document ambiguities actually encountered. | |
| Do not expand documentation unnecessarily. | |
| --- | |
| # Out of scope | |
| Do not implement or modify: | |
| ```text | |
| src/gnn4colliders/data/ | |
| src/gnn4colliders/features/ | |
| src/gnn4colliders/graphs/ | |
| src/gnn4colliders/models/ | |
| src/gnn4colliders/training/ | |
| src/gnn4colliders/inference/ | |
| ``` | |
| except for existing nonfunctional scaffolding if absolutely required for test discovery, and preferably not at all. | |
| Do not implement: | |
| * new data readers | |
| * new feature builders | |
| * new graph builders | |
| * model code | |
| * training code | |
| * losses | |
| * metrics | |
| * checkpoint handling | |
| * Hydra configuration behavior | |
| * runtime optimizations | |
| Do not refactor legacy code. | |
| Do not modernize legacy code. | |
| Do not run Ruff against the frozen legacy tree. | |
| --- | |
| # Validation | |
| Run: | |
| ```bash | |
| uv run python -c "import torch, dgl; print(torch.__version__, dgl.__version__)" | |
| uv run pytest tests/parity -v | |
| uv run ruff check tests | |
| uv run ruff format --check tests | |
| ``` | |
| Then run the full current suite: | |
| ```bash | |
| uv run pytest | |
| ``` | |
| The expected result for Task 3 is: | |
| ```text | |
| all characterization tests pass | |
| no DGL tests skipped because DGL is unavailable | |
| ``` | |
| If a test fails because its expectation disagrees with running legacy behavior: | |
| 1. investigate the legacy implementation | |
| 2. determine the observed behavior | |
| 3. fix the test expectation if the test was wrong | |
| 4. document ambiguity if appropriate | |
| Do not modify legacy behavior to satisfy a characterization test. | |
| --- | |
| # Git inspection | |
| Before committing, inspect: | |
| ```bash | |
| git status | |
| git diff | |
| ``` | |
| Verify that: | |
| * legacy files are unchanged | |
| * no new production implementation exists | |
| * fixtures are small | |
| * no caches are tracked | |
| * no model checkpoints were added | |
| * no generated DGL files were added unintentionally | |
| * no unrelated changes are included | |
| --- | |
| # Completion criteria | |
| Task 3 is complete when: | |
| 1. PyTorch and DGL import successfully. | |
| 2. Active node-feature behavior is characterized. | |
| 3. Graph topology is characterized. | |
| 4. Edge features and phi wrapping are characterized. | |
| 5. Tracking semantics are characterized. | |
| 6. Labels and global-feature behavior are characterized to the extent exercised by the active path. | |
| 7. Important ambiguities are documented. | |
| 8. All parity tests pass. | |
| 9. No DGL-dependent parity tests are skipped because of missing dependencies. | |
| 10. Legacy production code remains untouched. | |
| --- | |
| # Completion report | |
| Report: | |
| 1. files created | |
| 2. files modified | |
| 3. fixtures created | |
| 4. behaviors characterized | |
| 5. graph topology observed | |
| 6. edge ordering observed | |
| 7. numerical tolerances used | |
| 8. ambiguities discovered | |
| 9. behavior classified as compatibility requirement vs observation | |
| 10. validation commands and results | |
| 11. anything intentionally deferred | |
| After validation succeeds, create one Git commit containing only Task 3 changes. | |
| Use: | |
| ```text | |
| test: characterize legacy data and graph behavior | |
| ``` | |
| Before committing, inspect the final diff and ensure no unrelated files are included. | |