+ def _try_solution(self, c, h, C, b, tolerance):
+ # Actually solve the thing and obtain a dictionary describing
+ # what happened.
+ try:
+ solvers.options['show_progress'] = options.VERBOSE
+ solvers.options['abs_tol'] = tolerance
+ soln_dict = solvers.conelp(c,self._G(),h,C,self._A(),b)
+ except ValueError as e:
+ if str(e) == 'math domain error':
+ # Oops, CVXOPT tried to take the square root of a
+ # negative number. Report some details about the game
+ # rather than just the underlying CVXOPT crash.
+ raise PoorScalingException(self)
+ else:
+ raise e
+
+ # The optimal strategies are named ``p`` and ``q`` in the
+ # background documentation, and we need to extract them from
+ # the CVXOPT ``x`` and ``z`` variables. The objective values
+ # :math:`nu` and :math:`omega` can also be found in the CVXOPT
+ # ``x`` and ``y`` variables; however, they're stored
+ # conveniently as separate entries in the solution dictionary.
+ p1_value = -soln_dict['primal objective']
+ p2_value = -soln_dict['dual objective']
+ p1_optimal = soln_dict['x'][1:]
+ p2_optimal = soln_dict['z'][self._K.dimension():]
+
+ # The "status" field contains "optimal" if everything went
+ # according to plan. Other possible values are "primal
+ # infeasible", "dual infeasible", "unknown", all of which mean
+ # we didn't get a solution. The "infeasible" ones are the
+ # 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(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
+ # dictionary. Often this is the result of numerical
+ # difficulty and we can simply check that the primal/dual
+ # objectives match (within a tolerance) and that the
+ # primal/dual optimal solutions are within the cone (to a
+ # tolerance as well).
+ #
+ # The fudge factor of two is basically unjustified, but
+ # makes intuitive sense when you imagine that the primal
+ # value could be under the true optimal by ``ABS_TOL``
+ # and the dual value could be over by the same amount.
+ #
+ if abs(p1_value - p2_value) > tolerance:
+ raise GameUnsolvableException(self, soln_dict)
+ if (p1_optimal not in self._K) or (p2_optimal not in self._K):
+ raise GameUnsolvableException(self, soln_dict)
+
+ return Solution(p1_value, p1_optimal, p2_optimal)
+
+