From 6c2ec23c8d74bc42fd7e4a9d67da3adefe8f0332 Mon Sep 17 00:00:00 2001 From: Theodore Turocy Date: Wed, 11 Feb 2026 14:02:18 +0000 Subject: [PATCH 1/3] Restrict search space for `enumpoly` to be strictly interior. This shrinks the search space for searching for equilibria on a given support to be in the interior of the simplex (rather than including the boundaries as before). This solves the behaviour noted in #756, in which degenerate situations which required a solution to be on the boundary would be very slow as it tried to approach the solution on the boundary. --- src/solvers/enumpoly/efgpoly.cc | 4 ++-- src/solvers/enumpoly/nfgpoly.cc | 4 ++-- src/solvers/enumpoly/poly.h | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/solvers/enumpoly/efgpoly.cc b/src/solvers/enumpoly/efgpoly.cc index e30210949..ad7ada9c2 100644 --- a/src/solvers/enumpoly/efgpoly.cc +++ b/src/solvers/enumpoly/efgpoly.cc @@ -161,8 +161,8 @@ std::list> SolveSupport(const BehaviorSupportProfil // set up the rectangle of search Vector bottoms(data.space->GetDimension()), tops(data.space->GetDimension()); - bottoms = 0; - tops = 1; + bottoms = 1e-12; + tops = 1 - 1e-12; PolynomialSystemSolver solver(equations); std::list> roots; diff --git a/src/solvers/enumpoly/nfgpoly.cc b/src/solvers/enumpoly/nfgpoly.cc index 3334b7de7..a77d730f5 100644 --- a/src/solvers/enumpoly/nfgpoly.cc +++ b/src/solvers/enumpoly/nfgpoly.cc @@ -111,8 +111,8 @@ EnumPolyStrategySupportSolve(const StrategySupportProfile &support, bool &is_sin const PolynomialSystem equations = ConstructEquations(space, support, strategy_poly); Vector bottoms(space->GetDimension()), tops(space->GetDimension()); - bottoms = 0; - tops = 1; + bottoms = 1e-12; + tops = 1 - 1e-12; PolynomialSystemSolver solver(equations); is_singular = false; std::list> roots; diff --git a/src/solvers/enumpoly/poly.h b/src/solvers/enumpoly/poly.h index 2cc2db670..eb3390c6f 100644 --- a/src/solvers/enumpoly/poly.h +++ b/src/solvers/enumpoly/poly.h @@ -375,7 +375,11 @@ template class Polynomial { }); } [[nodiscard]] const std::vector> &GetTerms() const noexcept { return m_terms; } - bool IsZero() const noexcept { return m_terms.empty(); } + bool IsZero() const noexcept + { + return m_terms.empty() || std::all_of(m_terms.begin(), m_terms.end(), + [](const auto &mono) { return mono.IsZero(); }); + } bool IsConstant() const noexcept { return m_terms.size() == 1 && m_terms.front().TotalDegree() == 0; From 3111b8ba541315eb3b2b6faeb0857ee9c5c7ebbf Mon Sep 17 00:00:00 2001 From: Theodore Turocy Date: Tue, 10 Mar 2026 10:08:50 +0000 Subject: [PATCH 2/3] Mark additional tests as xfail while enumpoly is evolving. --- tests/test_nash.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/test_nash.py b/tests/test_nash.py index a2af4de44..5e9d84e84 100644 --- a/tests/test_nash.py +++ b/tests/test_nash.py @@ -2070,7 +2070,10 @@ def test_nash_strategy_solver_w_start(test_case: EquilibriumTestCaseWithStart, s regret_tol=TOL, prob_tol=TOL, ), - marks=pytest.mark.nash_enumpoly_behavior, + marks=[ + pytest.mark.nash_enumpoly_behavior, + pytest.mark.xfail(reason="Changes in operation of enumpoly"), + ], id="test_enumpoly_behavior_7", ), pytest.param( @@ -2084,7 +2087,10 @@ def test_nash_strategy_solver_w_start(test_case: EquilibriumTestCaseWithStart, s regret_tol=TOL, prob_tol=TOL, ), - marks=pytest.mark.nash_enumpoly_behavior, + marks=[ + pytest.mark.nash_enumpoly_behavior, + pytest.mark.xfail(reason="Changes in operation of enumpoly"), + ], id="test_enumpoly_behavior_8", ), # 4-player game From c1f75a4549175fd017fd4e7c00d69fb763d098cf Mon Sep 17 00:00:00 2001 From: Theodore Turocy Date: Tue, 10 Mar 2026 10:43:36 +0000 Subject: [PATCH 3/3] Mark additional tests as xfail while enumpoly is evolving. --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 09faf69fd..7dc653c18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ ### Changed - `Game.comment` has been renamed to `Game.description` +### Fixed +- `enumpoly` would take a very long time on some supports where an equilibrium is located on the + boundary of the projected game. Search is now restricted to the interior of the space ruling + these out; these will always be found by another projection. (#756) ## [16.5.1] - unreleased