Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,35 @@ is `0.x` the public API may change with a minor bump, always with an entry here.
latter needs the research repository present and is removed once the
extraction is complete.

### Changed

- PEP 8 names throughout, with the two per-node measure functions merged into
one `block_measures(graph, node, directed=False)`:

| was | is |
|---|---|
| `GARG_AML_node_{un,}directed_measures` | `block_measures` |
| `calculate_score_{un,}directed` | `score_from_measures` |
| `define_gargaml_scores` | `scores_from_measures` |
| `graph_community` | `reduce_graph` |
| `graph_degree` | `drop_hubs` |
| `summaries_neighbourhoors_node` | `neighbour_score_stats` |
| `degree_neighbours_node` | `neighbour_degree_stats` |
| `summarise_gargaml_scores` | `build_features` |
| `measure_NN_function` | private `_block_NN` |

- **`score_type` now defaults to `"weighted_average"`**, the aggregation every
published experiment uses. The previous default, `"basic"`, gives different
numbers.
- `reduce_graph` takes `seed` (default 1997) rather than hard-coding it.
- `build_features` returns every feature column by default rather than only the
score.
- Node identity is preserved: the old directed path cast integer node ids to
float. Cosmetic, but the package no longer does it — see `docs/decisions/0008`.
- Type hints on every function and NumPy-style docstrings with paper references
on every public one, each carrying a doctest that runs in CI.

### Notes

- Public names are still the research repository's (`GARG_AML_node_*_measures`,
`define_gargaml_scores`, ...). Renaming to PEP 8, type hints and NumPy-style
docstrings follow in the next release step, with the fixtures green throughout.
- The original's bare `except:` around the neighbour statistics is written as the
explicit empty check it always was. Same result, verified by both test layers.
29 changes: 29 additions & 0 deletions docs/decisions/0008-node-identity-is-preserved.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 0008 — Node identity is preserved

**Decision.** Whatever the caller's node ids are — `str`, `int`, tuple — they
come back as the index of every returned frame, unchanged.

**Context.** The pre-extraction code did not do this consistently.
`define_gargaml_scores_undirected` collected node ids with
`measures["node"].tolist()`, preserving their dtype;
`define_gargaml_scores_directed` collected them inside a `DataFrame.iterrows()`
loop, which coerces each row to a single dtype. With float measure columns in the
frame, that silently turned integer node ids into floats. The frozen fixtures
record it: `scores_directed_raw.csv` is indexed `0.0, 1.0` where
`scores_undirected_raw.csv` is indexed `0, 1`.

**Why this is not a correction to published results.** It is cosmetic. Python
hashes `0.0` and `0` identically, so the downstream dictionary and networkx
lookups resolve either way, and pandas joins a float64 index against an int64
index by value. The IBM account ids are strings in any case, so `iterrows()`
left them alone. Nothing downstream was reading a wrong number.

**Why change it.** A library that renames its caller's keys is surprising, and
node ids are the one thing a user matches results back to their own data with.
The package uses `.tolist()` on both paths.

**Consequence.** The directed score and feature fixtures carry a float index
that the package deliberately does not reproduce. Both test layers therefore
compare indices **by value** rather than by dtype, and say so inline. That is
strictly stronger than what came before: the golden comparison used to drop the
index entirely, so node alignment was never checked at all.
1 change: 1 addition & 0 deletions docs/decisions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ values produced the results published in
| [0005](0005-synthetic-generator-differs.md) | The synthetic generator does not reproduce the paper's datasets |
| [0006](0006-no-torch-dependency.md) | No PyTorch, ever |
| [0007](0007-directed-score-is-equation-14.md) | The directed score is Eq. 14, without the transpose-max |
| [0008](0008-node-identity-is-preserved.md) | Node ids come back unchanged; the old directed path cast them to float |
19 changes: 3 additions & 16 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,6 @@ max-complexity = 10
# the condition that triggers it; SIM108 would bury them at the end of a
# ternary, in the one file where those values most need to be obvious.
"src/garg_aml/_blocks.py" = ["SIM108"]
# TEMPORARY, remove in Phase 3. Phase 2 moves the implementation across with
# its function bodies unchanged, so that a golden-fixture mismatch can only
# mean the move was wrong. These three rules all ask for a rewrite of a body
# (ternaries, unpacking instead of list concatenation, no inplace=True) --
# correct requests, but ones that belong to the rename-and-modernise pass,
# where the fixtures are already green and can vouch for each change.
"src/garg_aml/*.py" = ["SIM108", "RUF005", "PD002"]

# --- Types ------------------------------------------------------------------
[tool.mypy]
Expand All @@ -96,17 +89,11 @@ warn_unused_ignores = true
module = ["networkx.*", "scipy.*"]
ignore_missing_imports = true

# Phase 2 moves the implementation across verbatim so that any fixture mismatch
# points at the move rather than at a rewrite; annotations are Phase 3. Delete
# this override then, and the global disallow_untyped_defs takes effect.
[[tool.mypy.overrides]]
module = ["garg_aml.*"]
disallow_untyped_defs = false

# --- Tests ------------------------------------------------------------------
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--strict-markers --cov=garg_aml --cov-report=term-missing --cov-fail-under=90"
testpaths = ["tests", "src/garg_aml"]
addopts = """--strict-markers --doctest-modules \
--cov=garg_aml --cov-report=term-missing --cov-fail-under=90"""
markers = [
"requires_data: needs the IBM AMLworld dataset, which is not redistributable",
]
Loading
Loading