Skip to content

Reuse sorted row traversal in native CSR ILU factorization - #405

Merged
moyner merged 4 commits into
sintefmath:mainfrom
moyner:perf/ilu-sorted-search
Oct 22, 2026
Merged

moyner merged 4 commits into
sintefmath:mainfrom
moyner:perf/ilu-sorted-search

Conversation

@moyner

@moyner moyner commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Native CSR ILU factorization currently restarts a source-row lookup for every target column. At the two partial-row update sites, merge the sorted target columns with the source row using one advancing position. Skip absent source entries with continue and stop once the source row is exhausted. The production-source diff is +25/-2 lines.

Preserve the first duplicate and the arithmetic order for present entries. Missing entries contribute nothing and leave their targets untouched. This deliberately avoids the previous multiplier * zero calculation: for an infinite/NaN multiplier or signed-zero target, skipping a structural zero can differ from an explicit IEEE zero multiplication. General CSR indexing and generic-matrix behavior remain unchanged. This is independent of the secondary-variable scheduling PR and changes no ILU scaling, partitioning, or worker policy.

Validation

  • 477 assertions pass at both one and 15 threads: 169 targeted traversal assertions plus existing scalar/block ILU and backend checks. Covers Float32/Float64, Int32/Int64, duplicate/missing columns, empty source rows, range views, signed zeros, NaN/Inf, and arbitrary-order generic-matrix fallback. Present entries match general lookup arithmetic; absent entries remain untouched, including with nonfinite multipliers.
  • Saved evolved Norne z8 and Olympus z4 factors and inverse diagonals compare exactly equal numerically, with zero timed allocation or compilation. Bitwise comparisons differ in signed zeros, as expected when absent entries are no longer updated.

Performance and standard-library comparison

Three rotated rounds under Julia 1.13.2 on a Ryzen 7950X, using Float64 evolved reservoir matrices from the first 20% of the original schedules; each sample is the median of seven numeric factorizations:

Numeric factorization Original scan, ms Previous cursor with zero multiplication, ms Clearer skip/break traversal, ms
Norne z8 100.084 84.633 78.165
Olympus z4 61.523 53.237 47.502

Skipping missing entries and stopping at the source-row end reduces numeric factorization time by 7.6% / 10.8% versus the previous cursor, and 21.9% / 22.8% versus the original scan. These are component results, not new whole-simulation speedups.

The earlier standard-library comparison below used the previous cursor with explicit zero multiplication:

Numeric factorization Original scan, ms Cursor, ms Suffix view + searchsortedfirst, ms Bounded searchsortedfirst, ms
Norne z8 99.642 84.499 95.907 92.204
Olympus z4 61.682 53.296 58.708 56.164

This earlier cursor version reduced numeric factorization time by roughly 14-15%. The best standard-library form was still 9.1% / 5.4% slower than the three-line cursor scan. A separate global row-view binary-search experiment also regressed reservoir factorization, despite helping synthetic long star rows, so general CSR lookup is left alone.

Earlier matched serial full-run pairs measured about 1.33% lower Norne / 0.89% lower Olympus simulation times with the previous zero-multiplying cursor. The clearer skip/break version has new component measurements only; those older whole-run percentages do not measure this revision.

The numerical validation and measurements start from 3b90948f. A test-include placement adjustment keeps this branch mergeable with current main dc6e630c without incorporating unrelated solver or worker changes.

@moyner
moyner merged commit 26adc28 into sintefmath:main Oct 22, 2026
5 checks passed
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