feat: add stats/base/dists/halfnormal/entropy#9753
Conversation
---
type: pre_commit_static_analysis_report
description: Results of running static analysis checks when committing changes.
report:
- task: lint_filenames
status: passed
- task: lint_editorconfig
status: passed
- task: lint_markdown
status: passed
- task: lint_package_json
status: passed
- task: lint_repl_help
status: passed
- task: lint_javascript_src
status: passed
- task: lint_javascript_cli
status: na
- task: lint_javascript_examples
status: passed
- task: lint_javascript_tests
status: passed
- task: lint_javascript_benchmarks
status: passed
- task: lint_python
status: na
- task: lint_r
status: na
- task: lint_c_src
status: missing_dependencies
- task: lint_c_examples
status: missing_dependencies
- task: lint_c_benchmarks
status: missing_dependencies
- task: lint_c_tests_fixtures
status: na
- task: lint_shell
status: na
- task: lint_typescript_declarations
status: passed
- task: lint_typescript_tests
status: passed
- task: lint_license_headers
status: passed
---
Coverage Report
The above coverage report was generated for the changes in this PR. |
Planeshifter
left a comment
There was a problem hiding this comment.
Thanks for this PR! Left initial comment.
| // returns ~2.6238370975295946 | ||
| ``` | ||
|
|
||
| If provided `sigma < 0`, the function returns `NaN`. |
There was a problem hiding this comment.
The documentation says sigma < 0 but the implementation in lib/main.js checks sigma <= 0.0. This should be updated to sigma <= 0 to match the implementation behavior (sigma=0 also returns NaN).
Note: docs/repl.txt correctly uses σ ≤ 0.
|
|
||
| ```c | ||
| double out = stdlib_base_dists_halfnormal_entropy( 1.0 ); | ||
| // returns ~0.726 |
There was a problem hiding this comment.
The expected output value ~0.726 is incorrect. For sigma=1.0, the entropy should be ~1.0143991850954939 (as shown correctly in the JavaScript examples above).
double out = stdlib_base_dists_halfnormal_entropy( 1.0 );
// returns ~1.014| * | ||
| * ## Notes | ||
| * | ||
| * - If provided `σ < 0`, the function returns `NaN`. |
There was a problem hiding this comment.
The documentation says σ < 0 but the implementation checks σ <= 0. This should be updated to σ ≤ 0 to match the implementation behavior (sigma=0 also returns NaN).
Note: docs/repl.txt correctly uses σ ≤ 0.
| var y = entropy( 1.0 ); | ||
| // returns ~1.0143991850954939 | ||
|
|
||
| y = entropy( 5.0 ); | ||
| // returns ~2.6238370975295946 |
There was a problem hiding this comment.
| var y = entropy( 1.0 ); | |
| // returns ~1.0143991850954939 | |
| y = entropy( 5.0 ); | |
| // returns ~2.6238370975295946 | |
| var y = entropy( 1.0 ); | |
| // returns ~1.014 | |
| y = entropy( 5.0 ); | |
| // returns ~2.624 |
stats/base/dists/halfnormal/entropy
---
type: pre_commit_static_analysis_report
description: Results of running static analysis checks when committing changes.
report:
- task: lint_filenames
status: passed
- task: lint_editorconfig
status: passed
- task: lint_markdown
status: passed
- task: lint_package_json
status: na
- task: lint_repl_help
status: na
- task: lint_javascript_src
status: na
- task: lint_javascript_cli
status: na
- task: lint_javascript_examples
status: na
- task: lint_javascript_tests
status: na
- task: lint_javascript_benchmarks
status: na
- task: lint_python
status: na
- task: lint_r
status: na
- task: lint_c_src
status: na
- task: lint_c_examples
status: na
- task: lint_c_benchmarks
status: na
- task: lint_c_tests_fixtures
status: na
- task: lint_shell
status: na
- task: lint_typescript_declarations
status: passed
- task: lint_typescript_tests
status: passed
- task: lint_license_headers
status: passed
---
| @@ -0,0 +1,26 @@ | |||
| {{alias}}( σ ) | |||
There was a problem hiding this comment.
The file should start with a leading blank line before {{alias}}.
| {{alias}}( σ ) | |
| {{alias}}( σ ) |
| * var v = entropy( 1.0 ); | ||
| * // returns ~1.0143991850954939 | ||
| * | ||
| * @example | ||
| * var v = entropy( 5.0 ); | ||
| * // returns ~2.6238370975295946 |
There was a problem hiding this comment.
Same as the repl.txt - the example return values should use short approximations instead of full precision. Reference packages (e.g., rayleigh/entropy) use // returns ~3.139 rather than the full value.
| * var v = entropy( 1.0 ); | |
| * // returns ~1.0143991850954939 | |
| * | |
| * @example | |
| * var v = entropy( 5.0 ); | |
| * // returns ~2.6238370975295946 | |
| * var v = entropy( 1.0 ); | |
| * // returns ~1.014 | |
| * | |
| * @example | |
| * var v = entropy( 5.0 ); | |
| * // returns ~2.624 |
| for ( i = 0; i < expected.length; i++ ) { | ||
| y = entropy( sigma[ i ] ); | ||
| if ( y === expected[ i ] ) { | ||
| t.strictEqual(y, expected[ i ], 'sigma: '+sigma[i]+', y: '+y+', expected: '+expected[i]); |
There was a problem hiding this comment.
Missing space after t.strictEqual( - should be t.strictEqual( y, with a space after the opening parenthesis, matching stdlib's spacing convention.
| t.strictEqual(y, expected[ i ], 'sigma: '+sigma[i]+', y: '+y+', expected: '+expected[i]); | |
| t.strictEqual( y, expected[ i ], 'sigma: '+sigma[i]+', y: '+y+', expected: '+expected[i] ); |
| } else { | ||
| delta = abs( y - expected[ i ] ); | ||
| tol = 40.0 * EPS * abs( expected[ i ] ); | ||
| t.ok(delta <= tol, 'within tolerance. sigma: '+sigma[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.'); |
There was a problem hiding this comment.
Missing space after t.ok( - should be t.ok( delta with a space after the opening parenthesis.
| t.ok(delta <= tol, 'within tolerance. sigma: '+sigma[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.'); | |
| t.ok( delta <= tol, 'within tolerance. sigma: '+sigma[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.' ); |
| } else { | ||
| delta = abs( y - expected[ i ] ); | ||
| tol = 40.0 * EPS * abs( expected[ i ] ); | ||
| t.ok(delta <= tol, 'within tolerance. sigma: '+sigma[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.'); |
There was a problem hiding this comment.
Missing space after t.ok( - should be t.ok( delta with a space after the opening parenthesis.
| t.ok(delta <= tol, 'within tolerance. sigma: '+sigma[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.'); | |
| t.ok( delta <= tol, 'within tolerance. sigma: '+sigma[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.' ); |
| > var v = {{alias}}( 1.0 ) | ||
| ~1.0143991850954939 | ||
| > v = {{alias}}( 5.0 ) | ||
| ~2.6238370975295946 |
There was a problem hiding this comment.
The example output values should use short approximations instead of full precision. Looking at other stdlib repl.txt files (e.g., rayleigh/entropy), they use formats like ~3.34 and ~2.446 rather than ~1.0143991850954939.
| > var v = {{alias}}( 1.0 ) | |
| ~1.0143991850954939 | |
| > v = {{alias}}( 5.0 ) | |
| ~2.6238370975295946 | |
| > var v = {{alias}}( 1.0 ) | |
| ~1.014 | |
| > v = {{alias}}( 5.0 ) | |
| ~2.624 |
| * var v = entropy( 1.0 ); | ||
| * // returns ~1.0143991850954939 | ||
| * | ||
| * v = entropy( 5.0 ); | ||
| * // returns ~2.6238370975295946 |
There was a problem hiding this comment.
| * var v = entropy( 1.0 ); | |
| * // returns ~1.0143991850954939 | |
| * | |
| * v = entropy( 5.0 ); | |
| * // returns ~2.6238370975295946 | |
| * var v = entropy( 1.0 ); | |
| * // returns ~1.014 | |
| * | |
| * v = entropy( 5.0 ); | |
| * // returns ~2.624 |
| * var v = entropy( 1.0 ); | ||
| * // returns ~1.0143991850954939 | ||
| * | ||
| * @example | ||
| * var v = entropy( 5.0 ); | ||
| * // returns ~2.6238370975295946 |
There was a problem hiding this comment.
| * var v = entropy( 1.0 ); | |
| * // returns ~1.0143991850954939 | |
| * | |
| * @example | |
| * var v = entropy( 5.0 ); | |
| * // returns ~2.6238370975295946 | |
| * var v = entropy( 1.0 ); | |
| * // returns ~1.014 | |
| * | |
| * @example | |
| * var v = entropy( 5.0 ); | |
| * // returns ~2.624 |
| * var v = entropy( 1.0 ); | ||
| * // returns ~1.0143991850954939 | ||
| * | ||
| * @example | ||
| * var v = entropy( 5.0 ); | ||
| * // returns ~2.6238370975295946 |
There was a problem hiding this comment.
| * var v = entropy( 1.0 ); | |
| * // returns ~1.0143991850954939 | |
| * | |
| * @example | |
| * var v = entropy( 5.0 ); | |
| * // returns ~2.6238370975295946 | |
| * var v = entropy( 1.0 ); | |
| * // returns ~1.014 | |
| * | |
| * @example | |
| * var v = entropy( 5.0 ); | |
| * // returns ~2.624 |
| * double y = stdlib_base_dists_halfnormal_entropy( 1.0 ); | ||
| * // returns ~1.0143991850954939 |
There was a problem hiding this comment.
| * double y = stdlib_base_dists_halfnormal_entropy( 1.0 ); | |
| * // returns ~1.0143991850954939 | |
| * double y = stdlib_base_dists_halfnormal_entropy( 1.0 ); | |
| * // returns ~1.014 |
---
type: pre_commit_static_analysis_report
description: Results of running static analysis checks when committing changes.
report:
- task: lint_filenames
status: passed
- task: lint_editorconfig
status: passed
- task: lint_markdown
status: na
- task: lint_package_json
status: na
- task: lint_repl_help
status: passed
- task: lint_javascript_src
status: passed
- task: lint_javascript_cli
status: na
- task: lint_javascript_examples
status: na
- task: lint_javascript_tests
status: passed
- task: lint_javascript_benchmarks
status: na
- task: lint_python
status: na
- task: lint_r
status: na
- task: lint_c_src
status: missing_dependencies
- task: lint_c_examples
status: na
- task: lint_c_benchmarks
status: na
- task: lint_c_tests_fixtures
status: na
- task: lint_shell
status: na
- task: lint_typescript_declarations
status: passed
- task: lint_typescript_tests
status: passed
- task: lint_license_headers
status: passed
---
---
type: pre_commit_static_analysis_report
description: Results of running static analysis checks when committing changes.
report:
- task: lint_filenames
status: passed
- task: lint_editorconfig
status: passed
- task: lint_markdown
status: na
- task: lint_package_json
status: na
- task: lint_repl_help
status: na
- task: lint_javascript_src
status: na
- task: lint_javascript_cli
status: na
- task: lint_javascript_examples
status: na
- task: lint_javascript_tests
status: na
- task: lint_javascript_benchmarks
status: na
- task: lint_python
status: na
- task: lint_r
status: na
- task: lint_c_src
status: na
- task: lint_c_examples
status: na
- task: lint_c_benchmarks
status: na
- task: lint_c_tests_fixtures
status: na
- task: lint_shell
status: na
- task: lint_typescript_declarations
status: passed
- task: lint_typescript_tests
status: na
- task: lint_license_headers
status: passed
---
---
type: pre_commit_static_analysis_report
description: Results of running static analysis checks when committing changes.
report:
- task: lint_filenames
status: passed
- task: lint_editorconfig
status: passed
- task: lint_markdown
status: na
- task: lint_package_json
status: na
- task: lint_repl_help
status: na
- task: lint_javascript_src
status: na
- task: lint_javascript_cli
status: na
- task: lint_javascript_examples
status: na
- task: lint_javascript_tests
status: na
- task: lint_javascript_benchmarks
status: na
- task: lint_python
status: missing_dependencies
- task: lint_r
status: na
- task: lint_c_src
status: na
- task: lint_c_examples
status: na
- task: lint_c_benchmarks
status: na
- task: lint_c_tests_fixtures
status: na
- task: lint_shell
status: na
- task: lint_typescript_declarations
status: passed
- task: lint_typescript_tests
status: na
- task: lint_license_headers
status: passed
---
|
Changes applied as requested @Planeshifter. Thanks for the review ! |
|
@Planeshifter I have made the requested changes.Please let me know if it needs further improvements |
Signed-off-by: Philipp Burckhardt <pburckhardt@outlook.com>
Signed-off-by: Philipp Burckhardt <pburckhardt@outlook.com>
Planeshifter
left a comment
There was a problem hiding this comment.
Let's land this one; thank you!
PR Commit MessagePlease review the above commit message and make any necessary adjustments. |
| if ( isnan( sigma ) || sigma <= 0.0 ) { | ||
| return NaN; | ||
| } | ||
| return 0.5 + ln( sigma ) + ln( SQRT_HALF_PI ) + ( 0.5 * GAMMA ); |
There was a problem hiding this comment.
@bhargava-d16 Can you explain how you derived this formula? It doesn't match Wikipedia (ref: https://en.wikipedia.org/wiki/Half-normal_distribution), so I am curious as to its derivation.
There was a problem hiding this comment.
And in fact, when tested against SciPy, all tests fail.
There was a problem hiding this comment.
The initial formulation followed the structure used for related scale distributions (e.g. Rayleigh), where the entropy contains an E[ln X] and thus a gamma/2 contribution.
However, explicitly expanding the half-normal log-density shows that the entropy depends only on a second-moment term E[X **2] and no logarithmic expectation remains after simplification.
I will update the implementation to use the simplified closed-form expression 0.5 + ln(sigma) + ln(sqrt(pi/2))
Please let me know if there are any additional changes or checks you’d recommend.
There was a problem hiding this comment.
@bhargava-d16 Sorry. I am not sure I follow. Would you mind providing the mathematical derivation of the entropy for a half-normal distribution?
There was a problem hiding this comment.
@bhargava-d16 Please do not bother submitting a PR, as I went through and fixed the entire implementation. The implementation now returns the same results as SciPy.
There was a problem hiding this comment.
Starting from the definition of differential entropy
(Ref: https://en.wikipedia.org/wiki/Differential_entropy),
H(X) = -∫ f(x) ln f(x) dx,
where the integral is over [0, infinity) since the half-normal distribution
is supported on x ≥ 0.
For a half-normal distribution with scale parameter sigma > 0, the
probability density function is
(Ref: https://en.wikipedia.org/wiki/Half-normal_distribution)
f(x) = sqrt(2)/(sigmasqrt(pi)) * exp(-x^2/(2sigma^2)), x ≥ 0.
Taking the logarithm on both sides,
ln f(x) = ln(sqrt(2)/(sigmasqrt(pi))) - x^2/(2sigma^2).
Substituting into the entropy definition and splitting terms gives
H(X) = -ln(sqrt(2)/(sigmasqrt(pi))) + E[X^2]/(2sigma^2).
For a half-normal random variable X = |Z| with
Z ~ N(0, sigma^2), we have X^2 = Z^2, and hence
E[X^2] = Var(Z) + (E[Z])^2 = sigma^2.
Therefore the second term evaluates to 1/2, and combining terms yields
H(X) = 0.5 + ln(sigma) + 0.5*ln(pi/2)
= 0.5 + ln(sigma) + ln(sqrt(pi/2))
There was a problem hiding this comment.
Thank you for the implementation.Out of curiosity, purely for learning purposes, whether the derivation I shared earlier was correct or if there were any differences with the approach you ended with.
PR-URL: stdlib-js#9753 Ref: stdlib-js#9416 Co-authored-by: Philipp Burckhardt <pburckhardt@outlook.com> Reviewed-by: Philipp Burckhardt <pburckhardt@outlook.com> Signed-off-by: Philipp Burckhardt <pburckhardt@outlook.com>
PR-URL: stdlib-js#9753 Ref: stdlib-js#9416 Co-authored-by: Philipp Burckhardt <pburckhardt@outlook.com> Reviewed-by: Philipp Burckhardt <pburckhardt@outlook.com> Signed-off-by: Philipp Burckhardt <pburckhardt@outlook.com>
type: pre_commit_static_analysis_report
description: Results of running static analysis checks when committing changes. report:
Progresses #9416
Description
This pull request:
Related Issues
This pull request has the following related issues:
@stdlib/stats/base/dists/halfnormalpackage #9416Questions
No.
Other
No.
Checklist
AI Assistance
If you answered "yes" above, how did you use AI assistance?
Disclosure
I consulted ChatGPT to verify mathematical formulation of half-normal entropy function and to confirm expected numerical values
@stdlib-js/reviewers