Skip to content

Align behavior of random parameters with numpy.random.#3738

Open
heplesser wants to merge 6 commits intonest:mainfrom
heplesser:fix-3736
Open

Align behavior of random parameters with numpy.random.#3738
heplesser wants to merge 6 commits intonest:mainfrom
heplesser:fix-3736

Conversation

@heplesser
Copy link
Copy Markdown
Contributor

@heplesser heplesser commented Feb 11, 2026

This PR aligns the non-spatial normal, lognormal and exponential parameters in NEST by allowing std == 0 or beta == 0, respectively. For the exponential parameter, a test against negative beta is introduced.

This PR only modifies the plain random parameters. For spatial random parameters, we still require that parameters are strictly positive.

This fixes #3736.

@heplesser heplesser added this to Kernel Feb 11, 2026
@heplesser heplesser added T: Enhancement New functionality, model or documentation S: Normal Handle this with default priority I: No breaking change Previously written code will work as before, no one should note anything changing (aside the fix) labels Feb 11, 2026
@github-project-automation github-project-automation Bot moved this to In progress in Kernel Feb 11, 2026
Copy link
Copy Markdown

@tomtetzlaff tomtetzlaff left a comment

Choose a reason for hiding this comment

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

Thanks a lot, @heplesser, for this fast fix. All three functions nest.random.normal(), nest.random.lognormal() and nest.random.exponential() behave as expected now.

Copy link
Copy Markdown
Contributor

@terhorstd terhorstd left a comment

Choose a reason for hiding this comment

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

Looks like a good change. For consistency we could briefly check testing strategy for the changed behavior covers also new cases.

("lognormal", {"mu": 0.0, "std": -1.0}),
("lognormal", {"mu": 0.0, "std": 1.0}),
("exponential", {"beta": -1.0}),
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are acceptable parameter values also tested? I'd have expected also a good_random_parameters = […, ("normal", {"mean": 1.0, "std": 0.0}, 1.0)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

After considering to decouple this into a separate issue, it seems too directly related, so I add to this comment:

In this change of aligning random parameters to numpy behavior formerly throwing tests are removed. However, no corresponding tests of the – now possible – good behavior are introduced.

Describe the solution you'd like
Currently the new expected behavior is not tested. Arguments that other statistical tests cover this implicitly are invalid, as

  • the other tests did not run into std==0 cases before (otherwise they would have thrown, and would now not throw anymore).
  • any catch behavior outside the changed functionality that defines values may already include branches for std==0 case, causing the new functionality not to be used.

Additionally the std=0 parameter would explicit test that the exact mean value is returned

good_random_parameters = [
    …,
    ("normal", {"mean": 0.0, "std": 0.0}, 0.0),
    ("normal", {"mean": 1.0, "std": 0.0}, 1.0),
]

Testing this for different mean values makes sure

  • the new functionality does actually work, and ensures that the code does not bypass calculations returning default values.
  • returned values are exact and internal calculations don't cause float bit-differences, i.e. mean = 0.1result == 0.1 without rounding errors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have now added tests to check correct behavior for std==0.

("lognormal", {"mu": 0.0, "std": -1.0}),
("lognormal", {"mu": 0.0, "std": 1.0}),
("exponential", {"beta": -1.0}),
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

After considering to decouple this into a separate issue, it seems too directly related, so I add to this comment:

In this change of aligning random parameters to numpy behavior formerly throwing tests are removed. However, no corresponding tests of the – now possible – good behavior are introduced.

Describe the solution you'd like
Currently the new expected behavior is not tested. Arguments that other statistical tests cover this implicitly are invalid, as

  • the other tests did not run into std==0 cases before (otherwise they would have thrown, and would now not throw anymore).
  • any catch behavior outside the changed functionality that defines values may already include branches for std==0 case, causing the new functionality not to be used.

Additionally the std=0 parameter would explicit test that the exact mean value is returned

good_random_parameters = [
    …,
    ("normal", {"mean": 0.0, "std": 0.0}, 0.0),
    ("normal", {"mean": 1.0, "std": 0.0}, 1.0),
]

Testing this for different mean values makes sure

  • the new functionality does actually work, and ensures that the code does not bypass calculations returning default values.
  • returned values are exact and internal calculations don't cause float bit-differences, i.e. mean = 0.1result == 0.1 without rounding errors.

@github-project-automation github-project-automation Bot moved this from In progress to PRs pending approval in Kernel Mar 5, 2026
@heplesser heplesser requested a review from terhorstd March 22, 2026 13:48
@heplesser
Copy link
Copy Markdown
Contributor Author

Here we have the curious situation that the test for std=0 crashes the testsuite completely under Linux while it passes under macOS. I will investigate this further. It does not seem to be caused by differences in the libc++ (Clang) and libstdc++ (gcc) implementation of the normal distribution.

@heplesser
Copy link
Copy Markdown
Contributor Author

The problem persists with Ubuntu 24.04 on the runner, gcc 13.3, Python 3.12.

@heplesser
Copy link
Copy Markdown
Contributor Author

OK, mystery understood: It is not a bug, it is a feature. The C++ standard requires in its §26.5.8.4.4 that the stddev parameter to std::normal_distribution is strictly positive (https://stackoverflow.com/a/9186515). Now Clang does not check this at all, while GCC checks it only if __GLIBCXX_ASSERTIONS is set—which is the case in our CI runners for Linux, but nowhere else.

So from a strict interpretation of the C++ standard, we must have stddev > 0. In practice, this does not matter, given that the algorithm (gcc and clang) only multiplies by stddev, so nothing bad can happen.

I assume that the logic of the C++ standard designers was that for stddev == 0, the normal distribution no longer is a continuous distribution but a pathological case.

This means that we cannot permit "sigma==0" for normal and lognormal parameters in a straightforward way. So the question is, @tomtetzlaff, how important is it for us to allow zero here just to allow what NumPy allows?

@heplesser
Copy link
Copy Markdown
Contributor Author

I have now implemented a slightly brute-force way of handling sigma=0 — after all, we don't need a random distribution if we know the result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

I: No breaking change Previously written code will work as before, no one should note anything changing (aside the fix) S: Normal Handle this with default priority T: Enhancement New functionality, model or documentation

Projects

Status: PRs pending approval

Development

Successfully merging this pull request may close these issues.

Permit std=0 in nest.random.normal()

3 participants