Skip to content

Add scenic.setSeed() public API#454

Closed
KE7 wants to merge 1 commit intoBerkeleyLearnVerify:mainfrom
KE7:setSeed-api
Closed

Add scenic.setSeed() public API#454
KE7 wants to merge 1 commit intoBerkeleyLearnVerify:mainfrom
KE7:setSeed-api

Conversation

@KE7
Copy link
Copy Markdown

@KE7 KE7 commented Apr 15, 2026

Summary

Exposes the seeding logic that the -s/--seed CLI option already uses as a module-level function, so Scenic scenarios can be made deterministic from Python code without touching random / numpy.random directly.

Motivation

docs/api.rst currently teaches users to call random.seed(n) directly to get deterministic generation:

import random, scenic
random.seed(12345)
scenario = scenic.scenarioFromString('ego = new Object with foo Range(0, 5)')
scene, numIterations = scenario.generate()

This is both:

  1. Incomplete. It only seeds Python's random; it does not seed numpy.random, so any distribution backed by numpy's RNG (and anything that goes through numpy downstream) still drifts across runs.
  2. An implementation detail. It asks users to know which RNGs Scenic draws from internally.

Meanwhile, scenic/__main__.py already does the right thing for the CLI:

# src/scenic/__main__.py (before this PR)
if args.seed is not None:
    ...
    random.seed(args.seed)
    numpy.random.seed(args.seed)

This PR turns that into a named API — scenic.setSeed(seed) — following the same pattern as the existing scenic.setDebuggingOptions, which was added in commit 9b9c850 ("unify control of debugging options; more docs"). Same structural precedent: a scenic.set*(...) public function wrapping CLI-equivalent behavior, documented with .. autofunction:: in api.rst and cross-referenced from options.rst.

I also hit this flakiness myself while using Scenic in a downstream project — having to remember "seed both random and numpy" kept being the wrong answer when constraints got tight enough to make rejection sampling probabilistic.

Changes

File Change
src/scenic/__init__.py Add setSeed(seed), documented, that seeds both random and numpy.random.
src/scenic/__main__.py Replace the inline random.seed(args.seed); numpy.random.seed(args.seed) block with scenic.setSeed(args.seed). Drop the now-unused import random / import numpy at the top. Single source of truth for how --seed works.
tests/syntax/test_basic.py Add test_setSeed next to test_verbose, mirroring the existing tests/test_main.py::test_seed CLI-level structure (same seed → same sample; different seed → different sample). Uses the existing sampleParamPFrom helper.
docs/api.rst Document the new API with .. autofunction:: and update the testcode example to use scenic.setSeed(12345) instead of random.seed(12345). Expected output is unchanged — verified locally that Range(0, 5) produces the same foo = 2.083099362726706 either way.
docs/options.rst Add the standard "can be configured from the Python API using `scenic.setSeed`" cross-reference to the -s/--seed entry, matching the existing pattern for scenic.setDebuggingOptions.

Net: +45 / -7 across 5 files.

Non-goals / deliberately out of scope

  • seed= kwarg on Scenario.generate(). That's a bigger design question (per-call scoping vs. global) and would stall review. This PR is strictly CLI-parity.
  • Wrapping with a fresh random.Random() instance. Keeping the global-RNG semantics matches the CLI exactly and means this PR is pure refactor + API exposure, not a behavior change.

Test plan

Ran locally against this branch (Linux, Python 3.11, pip install -e ".[test-full]" in a fresh venv):

  • black --check / isort --check-only on all touched .py files — clean (versions match .github/workflows/check-formatting.yml: black 25.1.0, isort 5.12.0)
  • pytest --fast --no-graphics (matches .github/workflows/run-tests.yml): 1444 passed, 538 skipped, 3 xfailed, 0 failures
  • pytest --no-graphics (slow suite, including tests/test_docs.py::test_build_docs which builds the Sphinx docs via make html with -W): passes after the docs/api.rst + docs/options.rst updates
  • tests/test_main.py::test_seed (CLI-level, verifies the __main__.py refactor): passes
  • tests/syntax/test_basic.py::test_setSeed (new): passes — determinism and variation-across-seeds both hold

🤖 Generated with Claude Code

Expose the seeding logic that the -s/--seed CLI option already uses as a
module-level function, so Scenic scenarios can be made deterministic from
Python code without touching `random` / `numpy.random` directly.

Motivation: docs/api.rst currently teaches users to call `random.seed(n)`
directly to get deterministic generation, which is incomplete (it does not
seed numpy.random, so any distribution backed by numpy's RNG still drifts)
and exposes an implementation detail. Meanwhile, `scenic/__main__.py`
already does the right thing for the CLI: it seeds both `random` and
`numpy.random`. This PR turns that into a named API following the same
pattern as the existing `scenic.setDebuggingOptions` (added in 9b9c850).

Changes:
- `scenic/__init__.py`: add `setSeed(seed)`, documented, that seeds both
  `random` and `numpy.random`.
- `scenic/__main__.py`: replace the inline `random.seed(args.seed);
  numpy.random.seed(args.seed)` block with `scenic.setSeed(args.seed)`,
  and drop the now-unused `import random` / `import numpy` at the top.
  Single source of truth for how `--seed` works.
- `tests/syntax/test_basic.py`: add `test_setSeed` next to `test_verbose`,
  mirroring the existing `tests/test_main.py::test_seed` CLI-level
  structure (same seed → same sample; different seed → different sample).
- `docs/api.rst`: document the new API with `.. autofunction::` and update
  the testcode example to use `scenic.setSeed(12345)` instead of
  `random.seed(12345)`. Expected output is unchanged — the example's
  `foo Range(0, 5)` is the same whether you seed via `random.seed` alone
  or via `scenic.setSeed` (verified locally).
- `docs/options.rst`: add the standard "can be configured from the Python
  API using `scenic.setSeed`" cross-reference to the `-s`/`--seed` entry,
  matching the pattern already used for `scenic.setDebuggingOptions`.

Local CI sign-off:
- black 25.1.0 + isort 5.12.0 clean on all touched .py files
- pytest --fast --no-graphics: 1444 passed, 538 skipped, 3 xfailed
- pytest --no-graphics (slow, incl. tests/test_docs.py::test_build_docs): clean
- tests/test_main.py::test_seed (verifies the __main__.py refactor): passes
@Eric-Vin
Copy link
Copy Markdown
Collaborator

Closed as feature is already being added in #422.

@Eric-Vin Eric-Vin closed this Apr 15, 2026
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