Skip to content

Parallelize examples with joblib (closes #5) - #65

Open
endolith wants to merge 2 commits into
reference-values-in-examplesfrom
cursor/add-joblib-parallelization-to-files-5679
Open

Parallelize examples with joblib (closes #5)#65
endolith wants to merge 2 commits into
reference-values-in-examplesfrom
cursor/add-joblib-parallelization-to-files-5679

Conversation

@endolith

@endolith endolith commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #5. Adds joblib parallelization to the remaining Monte Carlo example scripts that still ran serial election loops, and documents the shared parallelism pattern in examples/README.md.

Changes

Newly parallelized (10 scripts): Merrill tables/figures and Weber effectiveness/table scripts now use the same batch_size / Parallel(n_jobs=-3) pattern as the examples that already had joblib.

Documentation: examples/README.md explains batching, worker count, result aggregation, and seed behavior (Monte Carlo scripts intentionally omit fixed seeds; parallelism preserves the same statistical intent as a serial loop).

Scope: examples/ only — no library or test changes.

Reproducibility review

  • Workers return partial Counter / defaultdict totals merged on the main process; completion order does not affect aggregates.
  • Election generation still uses the same RNG entry points as before (random_utilities, impartial_culture, normal_electorate, np.random, tiebreaker='random').
  • Examples remain stochastic verification runs (no global seed); this matches pre-parallel behavior.

CI

  • ruff check examples/ --select=E9,F63,F7,F82 — pass
  • pytest — pass

Overlap with PR #52

PR #52 (elsim.studies API) also refactors the same example files to use JoblibBackend instead of direct joblib.Parallel calls. Only one of these PRs should merge as-is — whichever lands second will need a rebase and either adoption of elsim.studies or manual conflict resolution. This PR is intentionally scoped to examples/ with direct joblib usage to close #5 without depending on the studies API.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Example election simulations now run in parallel batches, improving performance for large-scale analyses.
    • Results from parallel runs are aggregated consistently before generating tables, figures, and reports.
    • Simulations provide progress reporting and support independent random states across workers.
  • Documentation

    • Added guidance on parallel Monte Carlo execution, batch sizing, CPU usage, result aggregation, and reproducibility considerations.
  • Tests

    • Example validation now runs scripts in isolated processes with timeouts and verifies complete, non-empty exported results.

@what-the-diff

what-the-diff Bot commented Jun 12, 2026

Copy link
Copy Markdown

PR Summary

  • Enhanced README with Parallel Monte Carlo Information: Enhanced the README documentation with guidance about implementing parallel processing for Monte Carlo simulations. It now includes instructions on beneficially utilizing joblib, an integral tool for parallel computing.

  • Adoption of Batch Processing in Simulation Scripts: The adoption of batch processing has enhanced various simulation scripts. By defining a batch_size, it's now possible to simulate multiple elections per worker, reducing scheduling overhead. The approach enhances the efficiency by concentrating the loop iterations on the batch_size rather than the total number of elections.

  • Parallel Processing Integration: By integrating Parallel and delayed from joblib, we've parallelized the execution of worker tasks. This development affects various scripts, facilitating faster execution of tasks across multiple CPU cores.

  • Refactoring of Simulation Logic: The simulation logic has undergone significant improvements. We created a new function - simulate_batch(), which neatly encapsulates the logic for processing elections in batches. Also, the method of aggregating results from individual simulations has been adjusted, providing an optimized process.

  • Updated Required Library Imports: We introduced necessary joblib imports in each of the affected scripts, supporting the efficient parallel execution of tasks.

  • Improved Initialization of utility_sums: We revised the initialization process of utility_sums to support both ranked and rated methods for utility accumulation, promoting flexibility.

This update delivers an improved, efficient, and parallel execution process that promises increased productivity and faster task execution. It streamlines the simulation process, allowing us to handle more tasks concurrently.

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.37%. Comparing base (dfa2315) to head (0352683).

Additional details and impacted files
@@                      Coverage Diff                      @@
##           reference-values-in-examples      #65   +/-   ##
=============================================================
  Coverage                         96.37%   96.37%           
=============================================================
  Files                                17       17           
  Lines                               496      496           
=============================================================
  Hits                                478      478           
  Misses                               18       18           
Flag Coverage Δ
no-numba 95.76% <ø> (ø)
numba 88.10% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cursor
cursor Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from 947aef5 to b4436ae Compare June 12, 2026 23:48
@cursor
cursor Bot marked this pull request as ready for review June 12, 2026 23:49
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The example simulations now use Joblib to process 100-election batches in parallel. Workers return partial counters for aggregation. Example tests run scripts in subprocesses and compare complete serialized tables.

Changes

Parallel example simulations

Layer / File(s) Summary
Batch configuration and parallel imports
examples/merrill_1984_*.py, examples/weber_1977_*.py
The scripts import Joblib, configure 100-election batches, calculate batch counts, and enforce exact divisibility.
Batch workers and result aggregation
examples/merrill_1984_*.py, examples/weber_1977_*.py
Each script moves election processing into simulate_batch, runs delayed jobs in parallel, and aggregates returned counters.
Parallel guidance and subprocess validation
examples/README.md, tests/test_examples.py
The documentation describes batching and worker random states. Tests execute scripts in isolated subprocesses and validate complete table rows.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ExampleScript
  participant JoblibParallel
  participant simulate_batch
  participant ElectionMethods
  participant ResultAggregation
  ExampleScript->>JoblibParallel: create delayed batch jobs
  JoblibParallel->>simulate_batch: execute election batches
  simulate_batch->>ElectionMethods: simulate elections and calculate winners
  ElectionMethods-->>simulate_batch: return election results
  simulate_batch-->>JoblibParallel: return partial counters
  JoblibParallel-->>ResultAggregation: provide batch results
  ResultAggregation->>ExampleScript: aggregate counters for tables and figures
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR parallelizes the listed examples with Joblib, but workers generate independent random draws and do not reuse generated data as requested by issue #5. Share or pre-generate reusable election data across workers, or revise issue #5 to remove the data-reuse requirement.
Out of Scope Changes check ⚠️ Warning The PR modifies tests/test_examples.py, although the stated scope is limited to examples/ and excludes test changes. Move the test changes to a separate PR or update the approved scope to include the subprocess-based example test changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding Joblib parallelization to the examples.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/add-joblib-parallelization-to-files-5679

Comment @coderabbitai help to get the list of available commands.

@endolith

endolith commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/README.md`:
- Line 10: Update the Parallel example description so n_jobs=-3 says it uses all
but two CPU cores, and state that n_jobs=-4 should be used when leaving three
cores unused.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f3d2c995-ab62-403f-a7ea-c65898d78aa3

📥 Commits

Reviewing files that changed from the base of the PR and between 14b8d55 and b4436ae.

📒 Files selected for processing (12)
  • .pre-commit-config.yaml
  • examples/README.md
  • examples/merrill_1984_fig_2c_2d.py
  • examples/merrill_1984_fig_2c_2d_updated.py
  • examples/merrill_1984_fig_4a_4b.py
  • examples/merrill_1984_fig_4a_4b_updated.py
  • examples/merrill_1984_table_1_fig_1.py
  • examples/merrill_1984_table_2.py
  • examples/merrill_1984_table_3_fig_3.py
  • examples/merrill_1984_table_4.py
  • examples/weber_1977_effectiveness_table.py
  • examples/weber_1977_table_4.py

Comment thread examples/README.md Outdated
@kilo-code-bot

kilo-code-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Rebased onto current master + before/after verification (via rebase/pr65)

Rebase

  • Cherry-picked this PR's two commits onto master (955101f). Dropped the e20cad0 ruff-pre-commit bump to 0.15.16 since master is already on v0.16.0.
  • Conflicts (master's _iteration/_name unused-loop-var renames from Ruff violations #77 colliding with the simulate_batch restructuring) resolved, keeping the underscore convention and the 79-char limit.
  • Also fixed the ruff issues the parallelization reintroduced: B007 unused loop vars (_iteration, _ymin), E501 comment lines pushed past 79 chars by the new indentation, trailing whitespace, and one-line docstrings on each simulate_batch.

Verification — serial vs parallelized, byte-identical output
Each affected script was run in both forms with an identical injected seed (random.seed, np.random.seed, and elsim.elections.elections_rng, since elsim draws elections from a module-level Generator and tiebreaks via Python's random). With n_jobs=1 joblib runs batches in-process in order, so the RNG draw order is identical to the serial loop, making stdout bit-for-bit comparable:

Script 500 elections Full scale
merrill_1984_fig_2c_2d identical identical (10k)
merrill_1984_fig_2c_2d_updated identical identical (5k)
merrill_1984_fig_4a_4b identical identical (10k)
merrill_1984_fig_4a_4b_updated identical identical (5k)
merrill_1984_table_1_fig_1 identical identical (10k)
merrill_1984_table_2 identical identical (10k × 8 conditions)
merrill_1984_table_3_fig_3 identical identical (10k)
merrill_1984_table_4 identical identical (10k × 8 conditions)
weber_1977_effectiveness_table identical identical (2k)
weber_1977_table_4 identical identical (30k)

"Identical" = normalized stdout (excluding Elapsed:/tasks total: lines) matches the serial master version exactly, so the batching + aggregation refactor is behavior-preserving. Across different seeds the parallelized code path also matches the published reference values within Monte Carlo noise (e.g., weber effectiveness: ≤~5 pp spread at 2,000 elections).

Caveat: the CI sandbox where this was run is a single-CPU container, so actual process-level parallelism (n_jobs=-3) couldn't be exercised — effective_n_jobs(-3) resolves to 1 here. The n_jobs=-3 → "all but two cores" documentation fix follows joblib's n_cpus - k + 1 rule; a real multiprocessing smoke test on a multi-core machine is still worthwhile.

Also added tests/test_examples.py (smoke-runs each script at a reduced election count with a fixed seed; skipped when joblib/matplotlib aren't installed) — happy to drop it if you'd rather keep this PR examples-only.

@kilo-code-bot

kilo-code-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Follow-up on rebase/pr65: tests/test_examples.py now also asserts that the weber_1977_effectiveness_table output stays within 5 pp of its documented reference table (Monte Carlo tolerance; max deviation observed over 10 seeds is ~3 pp). And I added a dedicated smoke-test-examples CI job (installs only joblib + matplotlib, not the full examples extra) so these scripts actually run in CI — happy to drop the job or the reference check if you'd rather keep the PR strictly examples-only.

@endolith

endolith commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kilo-code-bot
kilo-code-bot Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from b4436ae to b6c8f13 Compare August 3, 2026 01:28
@kilo-code-bot

kilo-code-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

The head branch has been force-updated to the rebased history (4 commits on top of current master), so this PR itself now reflects the rebase — it's MERGEABLE with no conflicts. The README now says n_jobs=-3 = "all but two CPU cores". The earlier comments describing the verification still apply to these exact commits.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/python-package.yml (1)

25-25: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Set persist-credentials: false on actions/checkout steps.

None of the three actions/checkout@v7 steps in this file set persist-credentials: false. By default, checkout persists the GITHUB_TOKEN in the local git config. None of these jobs need to push commits or run authenticated git commands afterward. Persisting the token unnecessarily increases the impact of a compromised dependency step that can read local git config.

🔒 Proposed fix (apply to each of the three checkout steps)
       - uses: actions/checkout@v7
+        with:
+          persist-credentials: false

Also applies to: 55-55, 96-96

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/python-package.yml at line 25, Update all three
actions/checkout@v7 steps in the workflow to set persist-credentials to false.
Apply the setting to each checkout invocation, including the steps referenced
near lines 25, 55, and 96, without changing other job behavior.

Source: Linters/SAST tools

🧹 Nitpick comments (1)
tests/test_examples.py (1)

78-83: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Preserve os.environ when building the subprocess environment.

env here fully replaces the parent process environment instead of extending it. This drops variables such as HOME, TMPDIR, and LANG that some libraries use for cache/config resolution, and hardcodes PATH to /usr/bin:/bin, which does not match typical macOS (Homebrew) or Windows layouts. This risks fragile or failing test runs outside the pinned ubuntu-latest CI job.

♻️ Proposed fix
-    env = {'MPLBACKEND': 'Agg',
-           'PYTHONPATH': str(EXAMPLES),
-           'PATH': '/usr/bin:/bin'}
+    env = {**os.environ,
+           'MPLBACKEND': 'Agg',
+           'PYTHONPATH': str(EXAMPLES)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_examples.py` around lines 78 - 83, Update the subprocess
environment construction in the test invoking subprocess.run to start from
os.environ.copy(), then override MPLBACKEND and PYTHONPATH while preserving the
inherited PATH and other environment variables; remove the hardcoded PATH value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_examples.py`:
- Around line 40-46: Update the worker setup around SEED_BLOCK and the
Parallel(n_jobs=-3) batch execution so every Joblib worker receives an explicit
seed or RNG rather than relying on the parent-process assignment to
elsim.elections.elections_rng. Ensure _check_random_state(None) observes the
worker-specific initialized RNG, using per-batch seed propagation or a Joblib
worker initializer.

---

Outside diff comments:
In @.github/workflows/python-package.yml:
- Line 25: Update all three actions/checkout@v7 steps in the workflow to set
persist-credentials to false. Apply the setting to each checkout invocation,
including the steps referenced near lines 25, 55, and 96, without changing other
job behavior.

---

Nitpick comments:
In `@tests/test_examples.py`:
- Around line 78-83: Update the subprocess environment construction in the test
invoking subprocess.run to start from os.environ.copy(), then override
MPLBACKEND and PYTHONPATH while preserving the inherited PATH and other
environment variables; remove the hardcoded PATH value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 076731a9-75ff-493a-9853-6b65f059b0a1

📥 Commits

Reviewing files that changed from the base of the PR and between b4436ae and b6c8f13.

📒 Files selected for processing (13)
  • .github/workflows/python-package.yml
  • examples/README.md
  • examples/merrill_1984_fig_2c_2d.py
  • examples/merrill_1984_fig_2c_2d_updated.py
  • examples/merrill_1984_fig_4a_4b.py
  • examples/merrill_1984_fig_4a_4b_updated.py
  • examples/merrill_1984_table_1_fig_1.py
  • examples/merrill_1984_table_2.py
  • examples/merrill_1984_table_3_fig_3.py
  • examples/merrill_1984_table_4.py
  • examples/weber_1977_effectiveness_table.py
  • examples/weber_1977_table_4.py
  • tests/test_examples.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • examples/merrill_1984_fig_4a_4b_updated.py
  • examples/merrill_1984_fig_2c_2d.py
  • examples/merrill_1984_table_4.py
  • examples/merrill_1984_table_3_fig_3.py
  • examples/merrill_1984_fig_2c_2d_updated.py
  • examples/merrill_1984_table_2.py
  • examples/merrill_1984_fig_4a_4b.py
  • examples/weber_1977_table_4.py

Comment thread tests/test_examples.py Outdated
@kilo-code-bot
kilo-code-bot Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from 2123178 to fc5dc63 Compare August 3, 2026 01:42
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Document two PR workflow rules that keep history clean:

- Rework an existing PR in place: back up the head branch locally, then
  modify and force-push the PR's actual head branch instead of creating a
  new parallel branch.
- Fold follow-up fixes into the commit that caused the problem (fixup)
  rather than stacking fix commits on top.

These came out of rebasing PR #65: the CI fix should have been squashed
into the commit that introduced the job, and the rebase should have been
applied to the PR-attached branch from the start.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/python-package.yml:
- Line 96: Update the actions/checkout@v7 step in the smoke-test job to set
persist-credentials to false, ensuring repository credentials are not retained
while pytest executes repository code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ce7bfffa-a465-4228-b6c3-372b7705a58e

📥 Commits

Reviewing files that changed from the base of the PR and between 2123178 and fc5dc63.

📒 Files selected for processing (2)
  • .github/workflows/python-package.yml
  • tests/test_examples.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_examples.py

Comment thread .github/workflows/python-package.yml
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Document two PR workflow rules that keep history clean:

- Rework an existing PR in place: back up the head branch locally, then
  modify and force-push the PR's actual head branch instead of creating a
  new parallel branch.
- Fold follow-up fixes into the commit that caused the problem (fixup)
  rather than stacking fix commits on top.

These came out of rebasing PR #65: the CI fix should have been squashed
into the commit that introduced the job, and the rebase should have been
applied to the PR-attached branch from the start.
@kilo-code-bot
kilo-code-bot Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch 2 times, most recently from 71fe6a2 to fa94950 Compare August 3, 2026 02:05
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Reviewers can flag pre-existing or out-of-scope issues; those belong in
their own PRs rather than being folded into the PR under review. This came
from CodeRabbit flagging unrelated CI hardening on #65, which was moved to
its own PR.
@endolith
endolith force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from fa94950 to 7966c66 Compare August 3, 2026 02:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
examples/merrill_1984_table_2.py (2)

50-53: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Use explicit validation for the batch partition.

assert is removed under python -O, so Line 53 is not a runtime guarantee. A non-divisible configuration would use the floor from Line 52 and silently simulate fewer elections. Validate that batch_size is positive and divides n_elections before deriving n_batches. Python documents that optimization removes assert statements. (docs.python.org)

Proposed fix
 batch_size = 100
-n_batches = n_elections // batch_size
-assert n_batches * batch_size == n_elections
+if batch_size <= 0 or n_elections % batch_size != 0:
+    raise ValueError(
+        "n_elections must be divisible by a positive batch_size"
+    )
+n_batches = n_elections // batch_size
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/merrill_1984_table_2.py` around lines 50 - 53, Replace the
assert-based validation near batch_size and n_batches with explicit runtime
validation that batch_size is positive and n_elections is evenly divisible by
it, raising an appropriate exception for invalid configuration before
calculating n_batches.

117-119: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Pin the backend or pass per-batch RNG state.

Parallel defaults to loky, so fork-state duplication does not affect the normal path. However, callers can select multiprocessing, while simulate_batch uses module-global elections_rng and Python’s global random state. Pin backend='loky', or pass distinct RNG state to each batch. The current tests only check completion and non-empty output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/merrill_1984_table_2.py` around lines 117 - 119, Update the Parallel
invocation in the batch execution flow to explicitly use the loky backend,
preserving independent random-state behavior when simulate_batch accesses
elections_rng and Python’s global random state. Keep the existing job
construction and parallelism settings unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@examples/merrill_1984_table_2.py`:
- Around line 50-53: Replace the assert-based validation near batch_size and
n_batches with explicit runtime validation that batch_size is positive and
n_elections is evenly divisible by it, raising an appropriate exception for
invalid configuration before calculating n_batches.
- Around line 117-119: Update the Parallel invocation in the batch execution
flow to explicitly use the loky backend, preserving independent random-state
behavior when simulate_batch accesses elections_rng and Python’s global random
state. Keep the existing job construction and parallelism settings unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4a5fb59d-d676-42f9-8c9b-46ce17b5a440

📥 Commits

Reviewing files that changed from the base of the PR and between fc5dc63 and 7966c66.

📒 Files selected for processing (13)
  • .github/workflows/python-package.yml
  • examples/README.md
  • examples/merrill_1984_fig_2c_2d.py
  • examples/merrill_1984_fig_2c_2d_updated.py
  • examples/merrill_1984_fig_4a_4b.py
  • examples/merrill_1984_fig_4a_4b_updated.py
  • examples/merrill_1984_table_1_fig_1.py
  • examples/merrill_1984_table_2.py
  • examples/merrill_1984_table_3_fig_3.py
  • examples/merrill_1984_table_4.py
  • examples/weber_1977_effectiveness_table.py
  • examples/weber_1977_table_4.py
  • tests/test_examples.py
🚧 Files skipped from review as they are similar to previous changes (10)
  • examples/weber_1977_table_4.py
  • examples/merrill_1984_fig_2c_2d_updated.py
  • examples/merrill_1984_fig_4a_4b.py
  • examples/merrill_1984_table_4.py
  • examples/merrill_1984_table_1_fig_1.py
  • .github/workflows/python-package.yml
  • examples/weber_1977_effectiveness_table.py
  • examples/merrill_1984_fig_2c_2d.py
  • examples/merrill_1984_table_3_fig_3.py
  • examples/merrill_1984_fig_4a_4b_updated.py

@endolith
endolith force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from 7966c66 to 640bb08 Compare August 3, 2026 02:52
endolith pushed a commit that referenced this pull request Aug 3, 2026
Document two PR workflow rules that keep history clean:

- Rework an existing PR in place: back up the head branch locally, then
  modify and force-push the PR's actual head branch instead of creating a
  new parallel branch.
- Fold follow-up fixes into the commit that caused the problem (fixup)
  rather than stacking fix commits on top.

These came out of rebasing PR #65: the CI fix should have been squashed
into the commit that introduced the job, and the rebase should have been
applied to the PR-attached branch from the start.
endolith pushed a commit that referenced this pull request Aug 3, 2026
Reviewers can flag pre-existing or out-of-scope issues; those belong in
their own PRs rather than being folded into the PR under review. This came
from CodeRabbit flagging unrelated CI hardening on #65, which was moved to
its own PR.
@kilo-code-bot
kilo-code-bot Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from 640bb08 to 31b2827 Compare August 3, 2026 03:04
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Two rules that PR #65's history violated:

- Code changes, their tests, and the CI that runs them are separate
  commits; don't mix them.
- Agent-generated summary files must not be committed; if one slips in,
  remove it from history rather than adding a delete commit.

Also drop the n_jobs=-4 note from examples/README.md in #65 (unnecessary).
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Two commit-hygiene rules that PR #65's history violated:

- Code changes, their tests, and the CI that runs them are separate
  commits; don't mix them.
- Agent-generated summary files must not be committed; if one slips in,
  remove it from history rather than adding a delete commit.
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Agent-generated summary files must not be committed; if one slips in,
remove it from history rather than adding a delete commit. PR #65's
history violated this.

Also drop the separate code/tests/CI commits rule that contradicted
the existing 'one coherent idea' guideline: tests, documentation, and
CI/workflow changes for an idea belong in the same commit as the code
they describe.
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Document two PR workflow rules that keep history clean:

- Rework an existing PR in place: push a backup of the head branch to
  the remote and confirm it exists, then modify the PR's actual head
  branch and force-push with --force-with-lease instead of creating a
  new parallel branch.
- Fold follow-up fixes into the commit that caused the problem (fixup)
  rather than stacking fix commits on top.

These came out of rebasing PR #65: the CI fix should have been squashed
into the commit that introduced the job, and the rebase should have been
applied to the PR-attached branch from the start.
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Reviewers can flag pre-existing or out-of-scope issues; those belong in
their own PRs rather than being folded into the PR under review. This came
from CodeRabbit flagging unrelated CI hardening on #65, which was moved to
its own PR.
kilo-code-bot Bot added a commit that referenced this pull request Aug 3, 2026
Agent-generated summary files must not be committed; if one slips in,
remove it from history rather than adding a delete commit. PR #65's
history violated this.

Also drop the separate code/tests/CI commits rule that contradicted
the existing 'one coherent idea' guideline: tests, documentation, and
CI/workflow changes for an idea belong in the same commit as the code
they describe.
@kilo-code-bot
kilo-code-bot Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from 31b2827 to 959577f Compare August 4, 2026 03:36
@kilo-code-bot

kilo-code-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Addressed CodeRabbit's backend/RNG comment: pinned backend='loky' in all 10 Parallel(...) calls. loky launches a fresh interpreter per worker (no fork-state RNG duplication), so each batch draws independent elections; backend='multiprocessing' (fork on Linux) would inherit and duplicate the module-global elections_rng across workers, silently simulating duplicate batches. Documented in examples/README.md. Folded into the parallelize/docs commits, so the history stays clean.

@kilo-code-bot
kilo-code-bot Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from 959577f to 244077a Compare August 4, 2026 05:22
@kilo-code-bot
kilo-code-bot Bot force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch 8 times, most recently from fecf7e3 to d58ec07 Compare August 4, 2026 18:38
@endolith

endolith commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/test_examples.py (1)

150-155: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Validate all parallelized scripts.

Four scripts in ALL_SCRIPTS have no entries in REFERENCE_VALUES or TOLERANCES. For those scripts, this test accepts any nonempty table. Add expected rows and tolerances, or add explicit structural assertions for every row and column.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_examples.py` around lines 150 - 155, Extend the validation loop
around REFERENCE_VALUES and TOLERANCES so every script listed in ALL_SCRIPTS is
validated, including the four currently missing entries. Add their expected rows
and tolerances, or provide explicit assertions covering every row and column; do
not allow scripts to pass based only on a nonempty table.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_examples.py`:
- Around line 150-155: Extend the validation loop around REFERENCE_VALUES and
TOLERANCES so every script listed in ALL_SCRIPTS is validated, including the
four currently missing entries. Add their expected rows and tolerances, or
provide explicit assertions covering every row and column; do not allow scripts
to pass based only on a nonempty table.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f9b2553c-f493-4ec9-ba20-4d397ee48b46

📥 Commits

Reviewing files that changed from the base of the PR and between fc5dc63 and d58ec07.

📒 Files selected for processing (12)
  • examples/README.md
  • examples/merrill_1984_fig_2c_2d.py
  • examples/merrill_1984_fig_2c_2d_updated.py
  • examples/merrill_1984_fig_4a_4b.py
  • examples/merrill_1984_fig_4a_4b_updated.py
  • examples/merrill_1984_table_1_fig_1.py
  • examples/merrill_1984_table_2.py
  • examples/merrill_1984_table_3_fig_3.py
  • examples/merrill_1984_table_4.py
  • examples/weber_1977_effectiveness_table.py
  • examples/weber_1977_table_4.py
  • tests/test_examples.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • examples/merrill_1984_table_4.py
  • examples/merrill_1984_fig_4a_4b_updated.py
  • examples/merrill_1984_table_3_fig_3.py
  • examples/weber_1977_effectiveness_table.py
  • examples/merrill_1984_fig_4a_4b.py
  • examples/merrill_1984_table_1_fig_1.py
  • examples/weber_1977_table_4.py
  • examples/merrill_1984_fig_2c_2d.py

endolith and others added 2 commits August 5, 2026 23:01
Each example script now defines its own ``reference_table`` (the values its
computed ``table`` is checked against, in the script's column order) and a
``tolerance`` (absolute comparison tolerance), so the script doubles as a
test.  test_examples.py no longer hardcodes REFERENCE_VALUES/TOLERANCES; it
just runs each script (in a subprocess) and verifies ``table`` against the
script's own ``reference_table``.  Fixes #91.

Reference provenance (see issue #88):

- merrill_1984_table_1/3 and the Weber scripts reproduce the published
  tables, so their references are the paper's values (for table_1 and table_3
  this is the existing ``merrill_table_1`` dict, renamed ``reference_table``).
- merrill_1984_table_2/4 and the four figure scripts do not reproduce the
  papers (up to ~7-9 pp off), so those references are the docstring "Typical
  result"/"Results with N elections" values, with a comment noting they are a
  regression guard until the discrepancy is fixed.

The figure scripts were restructured to keep a table per sub-figure (keyed by
fig label) instead of overwriting a single ``table`` each loop iteration, so
both sub-figures are checked.  The examples README documents the convention.

Co-authored-by: opencode <opencode@anomalyco.ai>
Refactor the Monte Carlo example scripts to run elections in batches
(simulate_batch) executed by joblib.Parallel with n_jobs=-3 and the loky
backend, aggregating the per-worker Counter results in the main process.

Pin backend='loky' so each worker is a fresh interpreter with its own RNG
state; fork-based backends would inherit and duplicate the module-global
elections_rng across workers. joblib already prints elapsed time, so the
manual timing is removed.

Document the pattern in examples/README.md.
@endolith
endolith force-pushed the cursor/add-joblib-parallelization-to-files-5679 branch from d58ec07 to 0352683 Compare August 6, 2026 03:52
@endolith
endolith changed the base branch from master to reference-values-in-examples August 6, 2026 03:52
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.

Parallelize all examples

1 participant