fix(rand): In-place uniform_ and normal_ do not rotate seed per block#1074
fix(rand): In-place uniform_ and normal_ do not rotate seed per block#1074IvanaGyro wants to merge 7 commits into
Conversation
…e random methods, docs and tests ### Motivation - Ensure in-place randomization for `UniTensor` is performed via its instance methods instead of allowing the `random` submodule functions to accept `UniTensor` objects. - Align Python bindings and type stubs with the intended API surface by removing `UniTensor` overloads from the `random` module. ### Description - Removed `UniTensor` overloads from the `random` typing stub file `cytnx/cytnx/random.pyi` so `normal_` and `uniform_` are no longer typed to accept `UniTensor`. - Deleted the `UniTensor` bindings for `normal_` and `uniform_` from `pybind/random_py.cpp`, leaving bindings for `Tensor` and `Storage` only. - Updated the example in `docs/code/python/doc_codes/guide_uniten_create_from_generator.py` to demonstrate the `UniTensor` instance methods `normal_()` and `uniform_()` for in-place randomization. - Added unit tests in `pytests/random_test.py` verifying that `UniTensor.normal_()` and `UniTensor.uniform_()` randomize in place and that calling `cytnx.random.normal[_]` and `cytnx.random.uniform[_]` with a `UniTensor` raises `TypeError`. ### Testing - Ran the new tests in `pytests/random_test.py` with `pytest`, and all tests passed. - The new tests cover in-place randomization for `UniTensor` and enforcement that the `random` module functions reject `UniTensor` inputs, and they succeeded.
There was a problem hiding this comment.
Code Review
This pull request removes the normal_ and uniform_ functions for UniTensor from the random module bindings and type stubs, as they are now implemented as in-place methods on the UniTensor class. It also adds documentation examples and comprehensive unit tests for these in-place methods on both dense and block UniTensor instances. The review feedback highlights a style guide violation regarding the use of leading underscores in new helper functions, and recommends using np.testing.assert_allclose instead of np.testing.assert_array_equal for floating-point comparisons to prevent flaky tests.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 587567f1a6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1074 +/- ##
==========================================
+ Coverage 72.11% 72.77% +0.66%
==========================================
Files 225 226 +1
Lines 28207 28179 -28
Branches 71 71
==========================================
+ Hits 20341 20507 +166
+ Misses 7845 7651 -194
Partials 21 21
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 21 files with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
…or randomization docs and tests ### Motivation - Avoid duplicate bindings for UniTensor instances by removing module-level normal_ and uniform_ overloads and document the intended in-place APIs on UniTensor. - Ensure block UniTensor in-place randomization uses different seeded streams per block while remaining reproducible for a given seed. ### Description - Removed normal_ and uniform_ UniTensor overload bindings from pybind/random_py.cpp so only Tensor/Storage module-level overloads remain. - Updated type stubs in cytnx/cytnx/random.pyi to drop UniTensor overloads for normal_ and uniform_. - Added example usage to docs/code/python/doc_codes/guide_uniten_create_from_generator.py showing in-place calls UniTensor.normal_(...) and UniTensor.uniform_(...) on existing UniTensor instances. - Updated UniTensor::normal_ and UniTensor::uniform_ so block UniTensors pass seed + block_index to each block randomization call. - Added unit tests in pytests/unitensor_random_test.py that verify same-seed reproducibility for dense and block UniTensor normal_/uniform_ without hard-coded std::distribution-dependent values, and verify uniform_ produces distinct block values. ### Testing - pre-commit run --files src/UniTensor.cpp pytests/unitensor_random_test.py cytnx/cytnx/random.pyi docs/code/python/doc_codes/guide_uniten_create_from_generator.py pybind/random_py.cpp - .claude/skills/build-test-workflow/scripts/build_preset.sh openblas-cpu --target pycytnx - source build/openblas-cpu-venv/bin/activate && pytest pytests/unitensor_random_test.py -q - git diff --check Co-Authored-By: OpenAI Codex <codex@openai.com>
### Motivation - Keep the per-block seed offset for UniTensor in-place randomization so block tensors receive deterministic but distinct streams. - Restore the Python random module in-place APIs for UniTensor after review feedback, while keeping out-of-place random construction shape-based. - Document both supported in-place entry points and cover the restored bindings with regression tests. ### Description - Re-added pybind overloads for cytnx.random.normal_(UniTensor, ...) and cytnx.random.uniform_(UniTensor, ...), forwarding to the existing C++ in-place UniTensor randomizers. - Restored UniTensor overloads in cytnx.random type stubs. - Kept cytnx.random.normal(UniTensor, ...) and cytnx.random.uniform(UniTensor, ...) absent, so only in-place module functions accept UniTensor templates. - Updated the UniTensor generator guide to mention both instance-method and cytnx.random module in-place randomization. - Added regression coverage that checks the restored module-level UniTensor APIs match the instance-method behavior. ### Testing - pre-commit run --files pybind/random_py.cpp cytnx/cytnx/random.pyi docs/code/python/doc_codes/guide_uniten_create_from_generator.py pytests/unitensor_random_test.py - git submodule update --init --recursive - apt-get update && apt-get install -y --fix-missing libboost-dev libopenblas-dev liblapacke-dev libarpack2-dev libgtest-dev libgmock-dev libbenchmark-dev - .claude/skills/build-test-workflow/scripts/build_preset.sh openblas-cpu --target pycytnx - source build/openblas-cpu-venv/bin/activate && pytest pytests/unitensor_random_test.py -q && git diff --check Co-Authored-By: Codex <codex@openai.com>
### Motivation - Keep the per-block seed offset for UniTensor in-place randomization so block tensors receive deterministic but distinct streams. - Keep the Python random module in-place APIs for UniTensor available after review feedback, while leaving out-of-place random construction shape-based. - Document both supported in-place entry points and stabilize the Arnoldi block-UniTensor regression affected by the random-stream change. ### Description - Kept pybind overloads for cytnx.random.normal_(UniTensor, ...) and cytnx.random.uniform_(UniTensor, ...), forwarding to the existing C++ in-place UniTensor randomizers. - Restored UniTensor overloads in cytnx.random type stubs. - Kept cytnx.random.normal(UniTensor, ...) and cytnx.random.uniform(UniTensor, ...) absent, so only in-place module functions accept UniTensor templates. - Updated the UniTensor generator guide to demonstrate instance normal_ and module-level cytnx.random.uniform_ in-place randomization. - Added regression coverage that checks the restored module-level UniTensor APIs match the instance-method behavior. - Tightened Arnoldi_Gnd.Arnoldi_BK_test convergence settings and replaced boolean comparison assertions with EXPECT_NEAR/EXPECT_LT. ### Testing - cmake --build --preset openblas-cpu --target test_main -- -j3 - build/openblas-cpu/tests/test_main --gtest_filter=Arnoldi_Gnd.Arnoldi_BK_test - pre-commit run --files docs/code/python/doc_codes/guide_uniten_create_from_generator.py tests/linalg_test/Arnoldi_Ut_test.cpp - source build/openblas-cpu-venv/bin/activate && pytest pytests/unitensor_random_test.py -q && git diff --check Co-Authored-By: Codex <codex@openai.com>
…ibution funtions Add examples about initializing UniTensor with: - cytnx.random.normal_(unitensor, ...) - unitensor.normal_(...) - cytnx.random.uniform_(unitensor, ...) - unitensor.uniform_(...)
…rion The previous commit set max iterations too high and convergence criterion too small. We don't need to go that extreme to pass the test.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 61d36ee422
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
(This was posted by Codex after review by @ianmccul - the codex attribution was missing from the original posting) A few comments after looking at the current end state of this PR. The Arnoldi test changeThe modified Also, explicitly setting For context, the other helper in this file, It would be better for the Arnoldi fixture to contain fixed data rather than depend on the precise random streams used by an unrelated randomization API test. Scope and implementationThe current diff no longer matches the PR title/body: it does not remove the module-level UniTensor overloads. It aligns the member The duplicated implementation should be removed rather than synchronized manually. One of UniTensor::uniform_()
random::uniform_(UniTensor&)should forward to the other, and likewise for Testing the distributionsExact equality between two calls using the same seed is appropriate for testing reproducibility; A robust alternative is to retain the exact reproducibility tests and add large-sample property tests. For example, use a dense Double UniTensor with shape def assert_distribution(values, expected_mean, expected_variance,
variance_se_factor, expected_kurtosis):
x = np.asarray(values).ravel()
n = x.size
sample_mean = x.mean()
sample_variance = x.var(ddof=1)
mean_tol = 8.0 * np.sqrt(expected_variance / n)
variance_tol = (
8.0 * expected_variance * np.sqrt(variance_se_factor / n)
)
assert abs(sample_mean - expected_mean) < mean_tol
assert abs(sample_variance - expected_variance) < variance_tol
centered = x - sample_mean
sample_kurtosis = np.mean(centered**4) / np.mean(centered**2) ** 2
assert abs(sample_kurtosis - expected_kurtosis) < 0.25For At this sample size those are deliberately generous tolerances, robust across different valid random streams, while still reliably detecting an ignored range, wrong scale, no-op fill, or wrong distribution family. The small block-UniTensor tests can then concentrate on exact same-seed reproducibility, valid uniform bounds, and ensuring equal-sized blocks do not receive identical streams. |
|
Follow-up with concrete tolerances for the proposed statistical tests. For For
I would round these upward and use: assert np.all(values >= -3.0)
assert np.all(values <= 7.0)
assert abs(values.mean() - 2.0) < 0.10
assert abs(values.var(ddof=1) - 100.0 / 12.0) < 0.25
assert abs(sample_kurtosis(values) - 1.8) < 0.25For
Again rounding upward: assert abs(values.mean() - 2.0) < 0.10
assert abs(values.var(ddof=1) - 9.0) < 0.40
assert abs(sample_kurtosis(values) - 3.0) < 0.25where def sample_kurtosis(values):
x = np.asarray(values).ravel()
centered = x - x.mean()
return np.mean(centered**4) / np.mean(centered**2) ** 2These tolerances are intentionally much wider than ordinary sampling fluctuations. They should be robust across standard-library RNG implementations while still failing clearly if the parameters are ignored, the fill is a no-op, the scaling is wrong, or normal and uniform distributions are confused. Exact same-seed equality should remain a separate reproducibility assertion. — Codex |
cytnx.random.uniform and cytnx.random.normal had no Python test coverage. Add pytests/random_distribution_test.py, which draws large samples (500k elements) and checks them against independent scipy.stats references rather than another cytnx code path: - uniform: boundary containment (samples stay within [low, high)) and a Kolmogorov-Smirnov test of marginal uniformity. - normal: a Cramer-von Mises CDF test, a Kolmogorov-Smirnov test, and a chi-square test over z-score tail bins. Each parametrization's seed is fixed and was chosen so every check passes at alpha=1e-6. Add scipy to the `test` optional-dependency group in pyproject.toml since these goodness-of-fit tests need it. Co-Authored-By: Claude <noreply@anthropic.com>
|
Motivation
In-place
blockunitensor.uniform_andblockunitensor.normal_didn't rotate seed while generating random numbers per block, which leads the values per block use the same sequence.Description
random.uniform_andrandom.normal_.docs/code/python/doc_codes/guide_uniten_create_from_generator.pyshowing in-place and global alls on existingUniTensorinstances.pytests/unitensor_random_test.pythat verify deterministic, seeded behavior for both dense and blockUniTensorusingnormal_anduniform_.Arnoldi_BK_testsmaller to pass the test. The test was wrongly passed with all blocks using the same random sequence.Testing
pytests/unitensor_random_test.pyviapytest, and the tests passed for the seeded deterministic checks ofUniTensor.normal_andUniTensor.uniform_.Arnoldi_Gnd.Arnoldi_BK_test