Change stop_after to std::optional<size_t> and reject stop_after <= 0 in pygambit - #1071
Change stop_after to std::optional<size_t> and reject stop_after <= 0 in pygambit#1071rahulsavani with Copilot wants to merge 11 commits into
Conversation
… stop_after <= 0 in Python Closes #1067 Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
…After input Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
There was a problem hiding this comment.
Can we have the following changes:
-
We need to deal with <=0 values for the command line tools too.
-
At the moment things like 0.5 or 1.2 are accepted as values of
stop_after. Can we include a check that input really is a whole number. In python,float.is_integerwould do for this, but we need the check at the C++ level too, e.g. for the command line tools. -
Please ensure we pass the code formatting tests too.
rahulsavani
left a comment
There was a problem hiding this comment.
Nothing has been committed since my last review, so I am not sure why a re-review has been requested. See requested changes from last review.
|
@copilot try again |
Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
Addressed all three items:
Tests added for |
rahulsavani
left a comment
There was a problem hiding this comment.
@copilot Actually for non-positive, or non-integer arguments to the gambit-lcp or gambit-enumpoly CLI tools, we don't want to silently ignore. Instead, print an message and then exit(1).
…lues Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
Updated both |
Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.
Suppressed comments (4)
Previously missed (1) — in code that hasn't changed since the last review.
src/pygambit/nash.py:249
- This validation still accepts
1.0because it compares equal toint(1.0), whilefloat("inf")raisesOverflowErrorfromint()instead of the promisedValueError. Since the public parameter is anintand non-integer values are rejected, validate the type before the range rather than converting arbitrary values.
This issue also appears on line 721 of the same file.
if stop_after is not None and int(stop_after) != stop_after:
src/pygambit/nash.py:721
- This validation still accepts
1.0because it compares equal toint(1.0), whilefloat("inf")raisesOverflowErrorfromint()instead of the promisedValueError. Since the public parameter is anintand non-integer values are rejected, validate the type before the range rather than converting arbitrary values.
if stop_after is not None and int(stop_after) != stop_after:
src/solvers/enumpoly/efgpoly.cc:205
value_or(...)has typesize_t, butPolynomialSystemSolver::FindRootsstill acceptsint. A valid limit aboveINT_MAXis therefore narrowed implementation-definedly; for example,2^32commonly becomes zero and makes the per-support search terminate prematurely. Change theFindRootsroot-limit API tosize_t(and use asize_tunlimited value), or reject/cap such inputs before this call.
roots =
solver.FindRoots({bottoms, tops}, p_stopAfter.value_or(std::numeric_limits<int>::max()),
p_maxRectangles, p_budgetExceeded, p_cancel);
src/solvers/enumpoly/nfgpoly.cc:124
value_or(...)has typesize_t, butPolynomialSystemSolver::FindRootsstill acceptsint. A valid limit aboveINT_MAXis therefore narrowed implementation-definedly; for example,2^32commonly becomes zero and makes the per-support search terminate prematurely. Change theFindRootsroot-limit API tosize_t(and use asize_tunlimited value), or reject/cap such inputs before this call.
roots =
solver.FindRoots({bottoms, tops}, p_stopAfter.value_or(std::numeric_limits<int>::max()),
p_maxRectangles, p_budgetExceeded, p_cancel);
|
@copilot fix remaining 4 comments from latest copilot review |
Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
Addressed in |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (4)
Previously missed (3) — in code that hasn't changed since the last review.
src/pygambit/nash.py:249
stop_after=float("inf")bypasses the positivity check andint(stop_after)raisesOverflowErrorbefore this intendedValueError; NaN likewise bypasses the custom message. Catch conversion failures (or validate the numeric value before converting) so every non-integer value is rejected with the new API error consistently.
This issue also appears on line 721 of the same file.
if stop_after is not None and int(stop_after) != stop_after:
src/tools/lcp/lcp.cc:103
- The PR description says non-positive
-evalues are ignored, but this branch exits with status 1 for both zero and negative values. Either keepstopAfterdisengaged for non-positive input as described, or update the stated CLI behavior if rejection is intentional.
if (result.ec != std::errc{} || result.ptr != end || parsed == 0) {
std::cerr << "Error: -e argument must be a positive integer; got '" << optarg << "'."
<< std::endl;
exit(1);
src/tools/enumpoly/enumpoly.cc:187
- The PR description says non-positive
-evalues are ignored, but this branch exits with status 1 for both zero and negative values. Either keepstopAfterdisengaged for non-positive input as described, or update the stated CLI behavior if rejection is intentional.
if (result.ec != std::errc{} || result.ptr != end || parsed == 0) {
std::cerr << "Error: -e argument must be a positive integer; got '" << optarg << "'."
<< std::endl;
exit(1);
src/pygambit/nash.py:721
stop_after=float("inf")bypasses the positivity check andint(stop_after)raisesOverflowErrorbefore this intendedValueError; NaN likewise bypasses the custom message. Catch conversion failures (or validate the numeric value before converting) so every non-integer value is rejected with the new API error consistently.
if stop_after is not None and int(stop_after) != stop_after:
rahulsavani
left a comment
There was a problem hiding this comment.
- Ensure that
stop_after=float("inf")gives aValueError(lines 249 and 721 in src/pygambit/nash.py) - Update the PR description for the CLI tools: "non-positive -e values are ignored" is incorrect
Co-authored-by: rahulsavani <743139+rahulsavani@users.noreply.github.com>
Addressed in |
This needs to be corrected in the PR description which has not been edited in 8 hours. Make sure the PR description is up-to-date and fully represents the latest version of the code. |
I can’t edit the PR body directly with the tools available in this environment, but the code is already up to date at
|
Issues closed by this PR
Description of the changes in this PR
stop_after=0was silently accepted in pygambit as equivalent tostop_after=None(find all equilibria), inheriting the C++ convention whereint stopAfter = 0meant "no limit." This is confusing for users.C++ solvers (
enumpoly,lcp):int p_stopAfter→std::optional<size_t>.nulloptmeans no limit;0is no longer a valid sentinel.Cython layer (
.pxd,.pxi): Declarations updated tooptional[size_t]. Wrappers convert PythonNoneto C++nullopt.Python (
nash.py):stop_after <= 0, non-integer values, andfloat("inf")now raiseValueErrorin bothenumpoly_solveandlcp_solve.Noneis passed through directly instead of being converted to0.CLI tools:
stopAfterchanged tostd::optional<size_t>; invalid-evalues (non-positive or non-integer) print an error message and exit with status 1.GUI:
nashspec.hstructs updated tostd::optional<size_t>withnulloptdefault.How to review this PR
std::optionalcomparisons/arithmetic innfglcp.cc,nfgpoly.cc,efgpoly.cccorrectly handlenulloptvs valued casestest_nash.pycover the rejection ofstop_after=0andstop_after=-1along with fractionalstop_aftervalues andfloat("inf").