From dd98bb15beba1e9eae310598e1b55a7dd9d4aa01 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 16 Oct 2016 00:42:48 -0400 Subject: [PATCH] Print the game data along with every GameUnsolvableException. --- TODO | 1 - src/dunshire/errors.py | 28 +++++++++++++++++++++------- src/dunshire/games.py | 6 +++--- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/TODO b/TODO index b0b503b..d23728e 100644 --- a/TODO +++ b/TODO @@ -12,4 +12,3 @@ 6. Come up with a fast heuristic (like making nu huge and taking e1 as our point) that finds a primal feasible point. -7. Should our one exception also spit out the game parameters? diff --git a/src/dunshire/errors.py b/src/dunshire/errors.py index 0201864..b63344a 100644 --- a/src/dunshire/errors.py +++ b/src/dunshire/errors.py @@ -55,6 +55,12 @@ class GameUnsolvableException(Exception): Examples -------- + >>> from dunshire import * + >>> K = IceCream(2) + >>> L = [[1,2],[3,4]] + >>> e1 = [1, 0.1] + >>> e2 = [3, 0.1] + >>> G = SymmetricLinearGame(L,K,e1,e2) >>> d = {'residual as dual infeasibility certificate': None, ... 'y': matrix([1,1]), ... 'dual slack': 8.779496368228267e-10, @@ -72,8 +78,16 @@ class GameUnsolvableException(Exception): ... 'gap': None, ... 'residual as primal infeasibility certificate': ... 3.986246886102996e-09} - >>> print(GameUnsolvableException(d)) + >>> print(GameUnsolvableException(G,d)) Solution failed with result "primal infeasible." + The linear game (L, K, e1, e2) where + L = [ 1 2] + [ 3 4], + K = Lorentz "ice cream" cone in the real 2-space, + e1 = [1.0000000] + [0.1000000], + e2 = [3.0000000] + [0.1000000]. CVXOPT returned: dual infeasibility: None dual objective: 1.0 @@ -98,11 +112,12 @@ class GameUnsolvableException(Exception): [ 0] [ 0] """ - def __init__(self, solution_dict): + def __init__(self, game, solution_dict): """ Create a new GameUnsolvableException object. """ super().__init__() + self._game = game self._solution_dict = solution_dict @@ -112,14 +127,13 @@ class GameUnsolvableException(Exception): The returned representation highlights the "status" field of the CVXOPT dictionary, since that should explain what went - wrong. The full CVXOPT solution dictionary is included after the - status. + wrong. The game details and full CVXOPT solution dictionary is + included after the status. """ tpl = 'Solution failed with result "{:s}."\n' \ + '{!s}\n' \ 'CVXOPT returned:\n {!s}' cvx_lines = _pretty_format_dict(self._solution_dict).splitlines() - # Indent the whole dict by two spaces. cvx_str = '\n '.join(cvx_lines) - - return tpl.format(self._solution_dict['status'], cvx_str) + return tpl.format(self._solution_dict['status'], self._game, cvx_str) diff --git a/src/dunshire/games.py b/src/dunshire/games.py index 43fa007..80f5f8a 100644 --- a/src/dunshire/games.py +++ b/src/dunshire/games.py @@ -445,7 +445,7 @@ class SymmetricLinearGame: # worst, since they indicate that CVXOPT is convinced the # problem is infeasible (and that cannot happen). if soln_dict['status'] in ['primal infeasible', 'dual infeasible']: - raise GameUnsolvableException(soln_dict) + raise GameUnsolvableException(self, soln_dict) elif soln_dict['status'] == 'unknown': # When we get a status of "unknown", we may still be able # to salvage a solution out of the returned @@ -455,9 +455,9 @@ class SymmetricLinearGame: # primal/dual optimal solutions are within the cone (to a # tolerance as well). if abs(p1_value - p2_value) > options.ABS_TOL: - raise GameUnsolvableException(soln_dict) + raise GameUnsolvableException(self, soln_dict) if (p1_optimal not in self._K) or (p2_optimal not in self._K): - raise GameUnsolvableException(soln_dict) + raise GameUnsolvableException(self, soln_dict) return Solution(p1_value, p1_optimal, p2_optimal) -- 2.43.2