Skip to content

feat(netflow-db): add measure-weighted MAAD estimator - #111

Open
flamboh wants to merge 5 commits into
maad/04-ipv6from
maad/05-weighted-estimator
Open

flamboh wants to merge 5 commits into
maad/04-ipv6from
maad/05-weighted-estimator

Conversation

@flamboh

@flamboh flamboh commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Note

🤖 Claude Opus 5.5 on behalf of Oliver

ELI5

Teaches the MAAD analysis to weight each address by how much traffic it sent (packets or bytes), instead of counting every address once.

Why

Address-count MAAD misses volume anomalies. In our study, one bogus flow claiming 465 G packets was invisible to address-count MAAD but drove packet-weighted D1 to 0. A source-address spike showed the opposite pattern. The two views complement each other.

Flows to exercise

  1. Weighted CLI vs the upstream oracle. Setup: a release build (cargo build --release -p atlantis-netflow-db), an upstream MAAD checkout, and an address,packets CSV. Run python3 scripts/local/validate_maad.py --weighted --rust target/release/netflow-db --haskell /path/to/MAAD name=addr_packets.csv. Expected: every structure row and D0/D1/D2 match within the validator's default 1e-10 tolerance.
  2. Invalid weights. Add a row with weight 0, a negative weight, or NaN and run netflow-db maad --weighted. Expected: the command exits non-zero and names the offending address.
  3. Unweighted output unchanged. netflow-db maad without --weighted produces byte-identical JSON to the base branch.

Decisions and edge cases

  • Matches upstream --csv --meas-col. Distinct-address counts decide prefix validity and pruning. Summed weights drive moments, D2, and D1 entropy. Weights on duplicate addresses are summed.
  • Weights must be finite and > 0, and their total must be finite. There is no weighted spectrum, because upstream's spectrum collapses on weighted measures.
  • Scale invariance. Multiplying every weight by a constant does not change the result. If a q's raw powers overflow or underflow, or a moment's partition sum is not finite, that q is recomputed from masses rescaled within each moment. Example: 10.0.0.0 and 10.0.0.128 with equal weights give D2 = 1/17 whether the weights are 1, 1e160, or 1e-200. Before this fix, 1e160 gave NaN and 1e-200 gave 0. Ordinary inputs keep the raw path, so unit weights still reproduce the unweighted result exactly.
  • Masses that normalize to zero. A positive weight can be too small to register against the total, such as 1e-300 next to 1e50. It contributes 0 to the entropy (the 0·log 0 = 0 limit), so D1 stays finite instead of becoming NaN.
  • Performance: all measures share one prefix walk, each distinct mass is raised to a power once per q, and q values run in parallel.

Follow-up

#112 covers the integration work: handling zero-packet flows, storing weighted results, and showing them in the dashboard. This PR only adds the estimator and the CLI/validator surface.

Verification

  • Automated: cargo fmt --all --check, cargo clippy --workspace --all-targets --all-features --locked -- -D warnings, and cargo test -p atlantis-netflow-db maad. The tests cover:
    • unit weights reproduce the unweighted result exactly;
    • permutation and duplicate invariance;
    • a hand-computed case;
    • an independent ordered-map reference;
    • scale invariance across 1e-300…1e300;
    • finite D1 when masses normalize to zero.
  • The unweighted JSON was byte-identical to main on fixtures and 20 real windows. Weighted output matched the oracle to about 1e-15.
  • Remaining manual verification: none. Flow 1 is an optional spot check for reviewers who have an upstream MAAD checkout.

Made by Claude Opus 5.5 (with Opus 5.5 subagents) via Claude Code.

@flamboh
flamboh added this pull request to stack #113 September 25, 2026 10:02
@flamboh flamboh changed the title maad/05 weighted estimator feat(netflow-db): add measure-weighted MAAD estimator Sep 25, 2026
Add compute_weighted for (address, weight) pairs of either family, generic over MaadAddress like compute. Duplicate addresses sum their weights; non-finite or non-positive weights are rejected. Prefix validity and path pruning keep using distinct-address counts, while moments, D2 and D1 entropy use summed weights. Weighted results carry structure and dimensions only.

The unweighted path keeps its integer power table and prefix-count layout, and its JSON output is byte-identical to the previous release on 20 real windows.

Extend validate_maad.py with --weighted (ADDR,MEASURE CSV, oracle --csv --meas-col 1) and add a matching netflow-db maad --weighted flag; both combine with --ipv6.
Walk prefix levels top-down holding only a parent and a child level, so MAAD memory is linear in the address count instead of address count times prefix levels. compute_measures evaluates the distinct-address result and any number of weight columns over one sort and one walk, because validity and path pruning depend only on the distinct addresses. Weighted structure uses an exact per-q power table for small integral masses.

Unweighted JSON is byte-identical to the previous layer on the conformance fixtures and 20 real windows, and weighted JSON is byte-identical to the previous estimator on 42 packet, byte and IPv6 inputs.
…lues across threads

Weighted structure maps each moment's masses to indices into the sorted distinct masses, so every q computes one powf per distinct mass. Structure rows for different q values are independent and now run in parallel on the caller's rayon pool. Output stays byte-identical: unweighted on the fixtures and 20 real windows, weighted on 42 packet, byte and IPv6 inputs.
…ference

compute_weighted now evaluates only its weighted result instead of building and discarding the distinct-address result, so the zero-weight fallback in the pipeline computes the unweighted measure once. Entries sort stably by address only, so repeated addresses sum their weights in input order for every column and compute_measures matches compute_weighted exactly. A weighted ordered-map reference, shared with the unweighted one, checks IPv4 with duplicates and IPv6.
@flamboh
flamboh force-pushed the maad/05-weighted-estimator branch from 804d55d to b7aff01 Compare September 27, 2026 05:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant