Skip to content

perf: replace stats::stepfun with stepfun2 in expected_event#642

Open
yihui wants to merge 4 commits into
mainfrom
perf/expected-event-stepfun2
Open

perf: replace stats::stepfun with stepfun2 in expected_event#642
yihui wants to merge 4 commits into
mainfrom
perf/expected-event-stepfun2

Conversation

@yihui

@yihui yihui commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replace 4 stats::stepfun() calls with stepfun2() in expected_event()
  • Improve stepfun2() itself: use a for-loop of vectorized comparisons (x >= b) for small breakpoint vectors (n <= 10), falling back to findInterval for larger ones

Why

stats::stepfun() is 57x slower to create than stepfun2() due to S3 class setup, environment construction, and method registration. In expected_event, step functions are created fresh on every call and evaluated once on small vectors (3-5 elements) — creation cost dominates.

The loop approach avoids findInterval's dispatch overhead and binary search, which are overkill for 3-4 breakpoints. Each iteration is a single vectorized primitive (x >= b), with no allocation.

Benchmark (the 4-stepfun create+eval pattern in expected_event, 50k calls)

Implementation Time Speedup vs stats::stepfun
stats::stepfun 10.8s 1x
stepfun2 (old, findInterval) 1.0s 11x
stepfun2 (new, loop for n<=10) 0.5s 21x

Test plan

  • test-developer-expected_event.R passes
  • test-independent-expected_event.R passes
  • Verified stepfun2 produces identical results to stats::stepfun for both right = FALSE and right = TRUE

🤖 Generated with Claude Code

yihui and others added 3 commits June 22, 2026 16:59
…_event

stats::stepfun has high creation overhead (~57x slower than stepfun2).
In expected_event, step functions are created per call and evaluated on
small vectors (3-5 elements), making creation cost dominant.

Additionally, improve stepfun2 eval speed for small breakpoint vectors
(n <= 10) by replacing findInterval with a for-loop of vectorized
comparisons (x >= b). This avoids findInterval's dispatch overhead and
binary search, which are overkill for 3-4 breakpoints.

Net speedup for the step-function portion of expected_event: ~21x vs
stats::stepfun, ~2x vs the previous findInterval-based stepfun2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@yihui yihui marked this pull request as ready for review June 22, 2026 21:20
Comment thread R/utils.R

@yihui yihui left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LittleBeannie I'm very confident that the new stepfun2() can safely replace stats::stepfun(), but please feel free to close the PR if you are not comfortable with changes in expected_event().

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.

2 participants