Catch duplicate ids within a single update scenario - #1568
Open
appleweiping wants to merge 1 commit into
Open
Conversation
Fixes PowerGridModel#1552. `validate_ids()` checked that every update id exists in the input dataset, but never that an id occurs at most once within a scenario. Because `_update_component_array_data()` applies an update through a NumPy fancy-index scatter (`input_data[field][idx] = update_data[field][mask]`), duplicate indices silently keep only the last value, and validation runs on the already-merged data. A batch with two rows sharing an id therefore passed `validate_batch_data()` with no error while quietly discarding all but the last of those rows. Add `ids_unique_in_update_data_set()` next to `ids_valid_in_update_data_set()` and expose it through `validate_unique_ids_in_scenario()`, which `validate_batch_data()` now runs per scenario alongside `validate_ids()`. Duplicates are reported as the existing `NotUniqueError`. Unset ids are excluded: they mark an update-by-position scenario, and partially unset ids are already reported by `ids_valid_in_update_data_set()`. Reusing the same id in a different scenario of the same batch remains valid. The new check exposed a broadcasting mistake in the `update_sym_load_r` fixture of `test_optional_ids.py`: assigning `[[4], [7]]` to a `(2, 2)` array broadcasts to `[[4, 4], [7, 7]]`, updating the same id twice per scenario. Corrected to `(2, 1)`, matching its columnar counterpart `update_sym_load_c`. Signed-off-by: appleweiping <vipinapple986@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1552.
validate_ids()checks that every update id exists in the input dataset, but never that an id occurs at most once within a scenario. Because_update_component_array_data()applies updates through a NumPy fancy-index scatter (input_data[field][idx] = update_data[field][mask]), duplicate indices silently keep only the last value — and validation runs on the already-merged data, so it can no longer see the duplicate. A batch with two rows sharing an id passesvalidate_batch_data()with no error while quietly discarding all but the last row.This adds
ids_unique_in_update_data_set()next toids_valid_in_update_data_set(), returning the existingNotUniqueError, and calls it per scenario fromvalidate_batch_dataas a blocking id error so the bad merge is never validated. Unset ids are excluded — they mark update-by-position, and partially-unset ids are already reported by the existing rule. Reusing an id in a different scenario stays valid.One thing worth flagging for the C++ migration question raised in the issue: the compiled core has the same behaviour. Calling
calculate_power_flowdirectly with a duplicate-id batch, bypassing Python validation entirely, also succeeds silently and returns a result reflecting only the last row. So the current state is silent data loss rather than just a missing validator nicety, which may argue for landing a check now rather than waiting. A core-side fix is out of scope here.While adding tests I also found that
update_sym_load_rintests/unit/test_optional_ids.pybuilds a(2, 2)array and assigns[[4], [7]], which NumPy broadcasts to[[4, 4], [7, 7]]— updating the same id twice per scenario. Its columnar counterpart uses(2, 1). I corrected the shape; that was the source of the new check's failures there.Verification
tests/unit/validation→ 358 passed, 1 skipped (324 passed before the added tests)mypy .clean,ruff formatclean,reuse lintcompliant at 1122/1122tests/unitshows 11 pre-existing failures intest_0Z_model_validation.py, identical with and without this change — numerical tolerances from a stale local C++ build on my machine, unrelated to this work. I did not rebuild the core, so I cannot confirm those pass on a fresh build.🤖 Generated with Claude Code