-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
BUG: Add test for Stackoverflow example from issue 8174. #9096
Conversation
Huh. Well that's convenient. Do you think #8909 fixed this? |
I guess so? #8909 implemented the only major changes to actually help fix bugs rather than to educate users. I must admit, I hadn't actually run a test on that particular issue. |
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.
Functionally looks good. You appear to have copy-pasted the example code by @sschnug from #8174 (good) and made minor formatting tweaks; and the required objective value is the same as what IPM reported then, so it seems to be the intended test. In addition to requiring that objective value match, you require that presolve catch the row redundancy. Just two minor suggestions.
scipy/optimize/tests/test_linprog.py
Outdated
]) | ||
b_eq = np.array([[100],[0],[0],[0],[0]]) | ||
|
||
shoud_warn_A_not_full_rank = ( |
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.
misspelled should here and below : )
scipy/optimize/tests/test_linprog.py
Outdated
|
||
shoud_warn_A_not_full_rank = ( | ||
self.options.get('presolve', True) | ||
and self.method == 'interior-point' |
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.
Because only interior point currently implements presolve, this is redundant with the line above, right? And when simplex does implement presolve, we would want it to be subject to the same condition. So I suggest removing this second condition.
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.
pytest.warns(...)
fails the test if no warning is raised. Removing the second condition will cause the tests to fail because the simplex method does not implment presolve (yet).
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.
@Kai-Striega Maybe I'm wrong, but I thought currently simplex is never passed a presolve
option at all. So the first condition self.options.get('presolve', True)
will always be False
for simplex tests. Because and
is a short circuit operator, the second condition checking for interior point will never even be evaluated, so it is redundant. shoud_warn_A_not_full_rank
will be false, so the pytest.warns
part won't apply to simplex tests, so it wouldn't cause simplex tests to fail.
Please forgive me if I'm being dense! What part of this is wrong?
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.
Actually... I don't think presolve
is ever going to be in self.options
for this test, even for interior point. So I think that should_warn_A_not_full_rank
is never True
. Are you sure that the with pytest.warns(OptimizeWarning)
is ever reached?
Since presolve
is never in self.options
, you don't really need to check it at all. Since presolve
is on for IPM by default, I think what you want to do is something like:
if method = "interior point":
# run linprog, checking for OptimizeWarning
else
# run linprog normally
_assert_success(...)
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.
@mdhaber Yes you're right. I'll change this test. I was trying to leave this open incase we end up adding any tests without using presolve.
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.
Yes you're right. I'll change the test. I wasn't sure if there are any tests for problems without presolve and wanted to be able to accomodate those. I'm pretty sure that, mathematically, every problem should return the same result regardless of whether presolve is used.
@Kai-Striega Please consider the minor comments, then when you're done ping me again and I'll merge this. I don't think this quite allows us to close #8174 because doesn't the first code example from #8174 still return success incorrectly? Even though simplex now warns the user, it still needs to return an error code when constraints aren't satisfied - please see my last comment in #9076. Anyway, I believe your next planned PR was to use the IPM pre- and post- routines, and that will fix this, allowing us to close #8174 and several other issues. Very exciting! |
scipy/optimize/tests/test_linprog.py
Outdated
c=c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, | ||
method=self.method, options=self.options | ||
) | ||
_assert_success(res, desired_fun=43.3333333331385) |
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.
@Kai-Striega Why not just one of these outside the if-elif
?
But I suppose If I see the tests pass tonight I'll merge.
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.
If added this using if-elseif to avoid having the test run if an invalid test is run.
However having the test run outside of the if block raises an unbound local error.
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.
I don't understand what you mean by:
"If added this using if-elseif to avoid having the test run if an invalid test is run."
It sounds like by "invalid test" you mean if self.method
takes on some value other than simplex
or interior-point
. That will not happen until we add a new method, and then we'll have to review this test anyway. It would probably be better if this caused the test to fail, actually, because it reminds us that we need to reconsider how this test should be applied for the new method.
Also, we're going to adding presolve to simplex
soon, right? So soon enough, we'll actually want to take out the if/elif altogether, because the test should be applied to both methods the same way. I don't anticipate that we'll be adding any new methods before then.
Whether you use this if-elif
or if-else
like I suggest, res
is guaranteed to be defined as the tests are currently written, so I don't see the harm of putting a single _assert_success
outside these blocks.
I don't see how an UnboundLocalError
is relevant, as no assignments are made to res
(see here for an explanation UnboundLocalError
).
I suggest trying my suggestion out. If you do get some error, please let me know, but if the tests pass with a single _assert_success
outside these blocks, I think that's how it should be.
scipy/optimize/tests/test_linprog.py
Outdated
) | ||
_assert_success(res, desired_fun=43.3333333331385) | ||
|
||
elif self.method == 'interior-point': |
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.
@Kai-Striega Shouldn't this just be an else
? In any case, certainly not self.method == 'interior-point'
!
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.
I've avoided else
incase a different variable is added. This is probably overkill / or should raise a valuerror instead.
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.
@Kai-Striega I'm not sure what you mean by "incase a different variable is added". Do you mean if a different value for method
is added?
As the test is written, if a different value for method
is added, then this test will effectively not run at all, because neither the if
or elif
code block will run.
In fact, even if the method
is simplex
, neither of these blocks will run because you have if self.method == 'interior-point':
and elif self.method == 'interior-point':
. If you really think the elif
is appropriate, shouldn't it at least be elif self.method == 'simplex':
?
I don't understand the part about raising a ValueError
.
I don't think it's necessary to anticipate additions of other methods right now, as all tests that have method-dependent requirements will have to be reconsidered if we add a new method.
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.
Sorry this has been a mental short circuit on my part. I'm going to change it to your suggestion and fix the logic (again).
scipy/optimize/tests/test_linprog.py
Outdated
@@ -820,20 +820,18 @@ def test_issue_8174_stackoverflow(self): | |||
|
|||
if self.method == 'interior-point': | |||
# Warning is raised in presolve method, | |||
# which is not yet implemented in the simplex method. | |||
# which is not hyet implemented in the simplex method. |
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.
typo
scipy/optimize/tests/test_linprog.py
Outdated
@@ -797,10 +797,10 @@ def test_bug_5400(self): | |||
with pytest.warns(OptimizeWarning): | |||
res = linprog(c, A_ub, b_ub, bounds=bounds, | |||
method=self.method, options=self.options) | |||
elif self.method == 'interior-point': | |||
else self.method == 'interior-point': |
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.
else:
scipy/optimize/tests/test_linprog.py
Outdated
_assert_success(res, desired_fun=43.3333333331385) | ||
|
||
elif self.method == 'interior-point': | ||
else self.method == 'simplex': |
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.
: /
fc2d7c3
to
0030cc1
Compare
Sorry. This was supposed to be a quick test and it’s turning fast turning into an embarrassment for me. Have a look and check if anything is better, otherwise I’m going to let it sit for a few days and come back to it. |
@Kai-Striega I think you've got it! Fingers crossed that the tests pass : ) Thanks for your patience with this. |
The failing test comes from: $ python -c 'import mpmath.libmp; assert mpmath.libmp.BACKEND == "gmpy"'
Traceback (most recent call last):
File "<string>", line 1, in <module>
AssertionError Which seems to be a problem for quite a few PRs right now (see #9106).Once that’s fixed it should be good to go. |
@mdhaber can we merge this? All the tests pass, except those on OSX. The same error occurs for most (all?) of the current PRs. |
I know. I thought it would be ok to wait for the macOS issue to be resolved and get a clean bill of health. |
please go ahead and merge. no point in waiting |
Test of the stackoverflow issue in issue #8174 as suggested by @mdhaber. The result returned from
linprog(method='simplex')
now matches that oflinprog(method='interior-point')
: