-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat: add stats/base/dists/halfnormal/entropy
#9753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * 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 |
lib/node_modules/@stdlib/stats/base/dists/halfnormal/entropy/examples/c/example.c
Outdated
Show resolved
Hide resolved
lib/node_modules/@stdlib/stats/base/dists/halfnormal/entropy/benchmark/benchmark.native.js
Outdated
Show resolved
Hide resolved
lib/node_modules/@stdlib/stats/base/dists/halfnormal/entropy/benchmark/benchmark.js
Show resolved
Hide resolved
lib/node_modules/@stdlib/stats/base/dists/halfnormal/entropy/benchmark/benchmark.native.js
Show resolved
Hide resolved
Signed-off-by: Philipp Burckhardt <pburckhardt@outlook.com>
lib/node_modules/@stdlib/stats/base/dists/halfnormal/entropy/README.md
Outdated
Show resolved
Hide resolved
lib/node_modules/@stdlib/stats/base/dists/halfnormal/entropy/README.md
Outdated
Show resolved
Hide resolved
Signed-off-by: Philipp Burckhardt <pburckhardt@outlook.com>
Planeshifter
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's land this one; thank you!
PR Commit MessagePlease review the above commit message and make any necessary adjustments. |
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>
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And in fact, when tested against SciPy, all tests fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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>
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