[
https://issues.apache.org/jira/browse/MATH-1679?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
ASF GitHub Bot updated MATH-1679:
---------------------------------
Labels: pull-request-available (was: )
> MultivariateFunctionMappingAdapter constructor allows equal lower and upper
> bounds, causing invalid mappings
> -------------------------------------------------------------------------------------------------------------
>
> Key: MATH-1679
> URL: https://issues.apache.org/jira/browse/MATH-1679
> Project: Commons Math
> Issue Type: Bug
> Components: legacy
> Affects Versions: 3.6.1
> Reporter: Ruiqi Dong
> Priority: Major
> Labels: pull-request-available
> Original Estimate: 0.5h
> Remaining Estimate: 0.5h
>
> The {{MultivariateFunctionMappingAdapter}} constructor does not validate the
> case where {{lower[i] == upper[i]}} for bounded parameters. This creates
> mathematically invalid mappers that use {{Sigmoid}} and {{Logit}} functions
> with degenerate intervals. When lower and upper bounds are equal, the
> parameter space collapses to a single point, making the {{Logit}} function
> mathematically undefined (division by zero). This can lead to {{NaN}} or
> infinity values during optimization, causing numerical instability.
> Test Case:
> @Test
> void testConstructorThrowsWhenLowerEqualsUpper() {
> MultivariateFunction bounded = point -> 0.0;
> double[] lower = \{2.0};
> double[] upper = \{2.0};
>
> assertThrows(NumberIsTooSmallException.class, () ->
> new MultivariateFunctionMappingAdapter(bounded, lower, upper),
> "Should throw when lower and upper bounds are equal");
> }
>
> Test Result:
> [*ERROR*]
> org.apache.commons.math4.legacy.optim.nonlinear.scalar.MultivariateFunctionMappingAdapterTest.testConstructorThrowsWhenLowerEqualsUpper
> -- Time elapsed: 0.004 s <<< FAILURE!
> org.opentest4j.AssertionFailedError: Should throw when lower and upper bounds
> are equal ==> Expected
> org.apache.commons.math4.legacy.exception.NumberIsTooSmallException to be
> thrown, but nothing was thrown.
> at
> org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
> at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:73)
> at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:39)
> at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3153)
> at
> org.apache.commons.math4.legacy.optim.nonlinear.scalar.MultivariateFunctionMappingAdapterTest.testConstructorThrowsWhenLowerEqualsUpper(MultivariateFunctionMappingAdapterTest.java:181)
> at java.lang.reflect.Method.invoke(Method.java:498)
> at java.util.ArrayList.forEach(ArrayList.java:1259)
> at java.util.ArrayList.forEach(ArrayList.java:1259)
>
> Root Cause Analysis:
> The current validation code only checks:
> if (!(upper[i] >= lower[i])) {
> throw new NumberIsTooSmallException(upper[i], lower[i], true);
> }
> This correctly handles {{upper < lower}} and {{NaN}} cases (as noted in the
> comment), but allows {{upper == lower}} to pass through.
> Suggested Fix:
> for (int i = 0; i < lower.length; ++i) {
> // existing check
> if (!(upper[i] >= lower[i])) {
> throw new NumberIsTooSmallException(upper[i], lower[i], true);
> }
> // add this check
> if (upper[i] == lower[i] && !Double.isInfinite(lower[i])) {
> throw new NumberIsTooSmallException(upper[i], lower[i], false);
> }
> }
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)