]> gitweb.michael.orlitzky.com - dunshire.git/blobdiff - dunshire/games.py
Use "..." for floating point output in doctests.
[dunshire.git] / dunshire / games.py
index 46092c380eca141ff993313bd30ec55989a32ed8..1f672abeb3870f45b13a8d9d169e8df0f1059d98 100644 (file)
@@ -222,7 +222,7 @@ class SymmetricLinearGame:
           e2 = [ 1]
                [ 2]
                [ 3],
           e2 = [ 1]
                [ 2]
                [ 3],
-          Condition((L, K, e1, e2)) = 63.669790.
+          Condition((L, K, e1, e2)) = 31.834...
 
     Lists can (and probably should) be used for every argument::
 
 
     Lists can (and probably should) be used for every argument::
 
@@ -241,7 +241,7 @@ class SymmetricLinearGame:
                [ 1],
           e2 = [ 1]
                [ 1],
                [ 1],
           e2 = [ 1]
                [ 1],
-          Condition((L, K, e1, e2)) = 3.414214.
+          Condition((L, K, e1, e2)) = 1.707...
 
     The points ``e1`` and ``e2`` can also be passed as some other
     enumerable type (of the correct length) without much harm, since
 
     The points ``e1`` and ``e2`` can also be passed as some other
     enumerable type (of the correct length) without much harm, since
@@ -264,7 +264,7 @@ class SymmetricLinearGame:
                [ 1],
           e2 = [ 1]
                [ 1],
                [ 1],
           e2 = [ 1]
                [ 1],
-          Condition((L, K, e1, e2)) = 3.414214.
+          Condition((L, K, e1, e2)) = 1.707...
 
     However, ``L`` will always be intepreted as a list of rows, even
     if it is passed as a :class:`cvxopt.base.matrix` which is
 
     However, ``L`` will always be intepreted as a list of rows, even
     if it is passed as a :class:`cvxopt.base.matrix` which is
@@ -286,7 +286,7 @@ class SymmetricLinearGame:
                [ 1],
           e2 = [ 1]
                [ 1],
                [ 1],
           e2 = [ 1]
                [ 1],
-          Condition((L, K, e1, e2)) = 12.147542.
+          Condition((L, K, e1, e2)) = 6.073...
         >>> L = cvxopt.matrix(L)
         >>> print(L)
         [ 1  3]
         >>> L = cvxopt.matrix(L)
         >>> print(L)
         [ 1  3]
@@ -302,7 +302,7 @@ class SymmetricLinearGame:
                [ 1],
           e2 = [ 1]
                [ 1],
                [ 1],
           e2 = [ 1]
                [ 1],
-          Condition((L, K, e1, e2)) = 12.147542.
+          Condition((L, K, e1, e2)) = 6.073...
 
     """
     def __init__(self, L, K, e1, e2):
 
     """
     def __init__(self, L, K, e1, e2):
@@ -346,7 +346,7 @@ class SymmetricLinearGame:
                           str(self._K),
                           indented_e1,
                           indented_e2,
                           str(self._K),
                           indented_e1,
                           indented_e2,
-                          self._condition())
+                          self.condition())
 
 
     def _zero(self):
 
 
     def _zero(self):
@@ -419,13 +419,13 @@ class SymmetricLinearGame:
             >>> print(SLG.solution())
             Game value: -6.1724138
             Player 1 optimal:
             >>> print(SLG.solution())
             Game value: -6.1724138
             Player 1 optimal:
-              [ 0.5517241]
-              [-0.0000000]
-              [ 0.4482759]
+              [ 0.551...]
+              [-0.000...]
+              [ 0.448...]
             Player 2 optimal:
             Player 2 optimal:
-              [0.4482759]
-              [0.0000000]
-              [0.5517241]
+              [0.448...]
+              [0.000...]
+              [0.551...]
 
         The value of the following game can be computed using the fact
         that the identity is invertible::
 
         The value of the following game can be computed using the fact
         that the identity is invertible::
@@ -439,13 +439,13 @@ class SymmetricLinearGame:
             >>> print(SLG.solution())
             Game value: 0.0312500
             Player 1 optimal:
             >>> print(SLG.solution())
             Game value: 0.0312500
             Player 1 optimal:
-              [0.0312500]
-              [0.0625000]
-              [0.0937500]
+              [0.031...]
+              [0.062...]
+              [0.093...]
             Player 2 optimal:
             Player 2 optimal:
-              [0.1250000]
-              [0.1562500]
-              [0.1875000]
+              [0.125...]
+              [0.156...]
+              [0.187...]
 
         """
         # The cone "C" that appears in the statement of the CVXOPT
 
         """
         # The cone "C" that appears in the statement of the CVXOPT
@@ -505,7 +505,13 @@ class SymmetricLinearGame:
             # objectives match (within a tolerance) and that the
             # primal/dual optimal solutions are within the cone (to a
             # tolerance as well).
             # objectives match (within a tolerance) and that the
             # primal/dual optimal solutions are within the cone (to a
             # tolerance as well).
-            if abs(p1_value - p2_value) > options.ABS_TOL:
+            #
+            # 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) > 2*options.ABS_TOL:
                 raise GameUnsolvableException(self, soln_dict)
             if (p1_optimal not in self._K) or (p2_optimal not in self._K):
                 raise GameUnsolvableException(self, soln_dict)
                 raise GameUnsolvableException(self, soln_dict)
             if (p1_optimal not in self._K) or (p2_optimal not in self._K):
                 raise GameUnsolvableException(self, soln_dict)
@@ -513,18 +519,25 @@ class SymmetricLinearGame:
         return Solution(p1_value, p1_optimal, p2_optimal)
 
 
         return Solution(p1_value, p1_optimal, p2_optimal)
 
 
-    def _condition(self):
+    def condition(self):
         r"""
         Return the condition number of this game.
 
         In the CVXOPT construction of this game, two matrices ``G`` and
         ``A`` appear. When those matrices are nasty, numerical problems
         can show up. We define the condition number of this game to be
         r"""
         Return the condition number of this game.
 
         In the CVXOPT construction of this game, two matrices ``G`` and
         ``A`` appear. When those matrices are nasty, numerical problems
         can show up. We define the condition number of this game to be
-        the sum of the condition numbers of ``G`` and ``A`` in the
+        the average of the condition numbers of ``G`` and ``A`` in the
         CVXOPT construction. If the condition number of this game is
         high, then you can expect numerical difficulty (such as
         :class:`PoorScalingException`).
 
         CVXOPT construction. If the condition number of this game is
         high, then you can expect numerical difficulty (such as
         :class:`PoorScalingException`).
 
+        Returns
+        -------
+
+        float
+            A real number greater than or equal to one that measures how
+            bad this game is numerically.
+
         Examples
         --------
 
         Examples
         --------
 
@@ -534,13 +547,13 @@ class SymmetricLinearGame:
         >>> e1 = [1]
         >>> e2 = e1
         >>> SLG = SymmetricLinearGame(L, K, e1, e2)
         >>> e1 = [1]
         >>> e2 = e1
         >>> SLG = SymmetricLinearGame(L, K, e1, e2)
-        >>> actual = SLG._condition()
-        >>> expected = 3.6180339887498953
+        >>> actual = SLG.condition()
+        >>> expected = 1.8090169943749477
         >>> abs(actual - expected) < options.ABS_TOL
         True
 
         """
         >>> abs(actual - expected) < options.ABS_TOL
         True
 
         """
-        return condition_number(self._G()) + condition_number(self._A())
+        return (condition_number(self._G()) + condition_number(self._A()))/2
 
 
     def dual(self):
 
 
     def dual(self):
@@ -573,7 +586,7 @@ class SymmetricLinearGame:
               e2 = [ 1]
                    [ 1]
                    [ 1],
               e2 = [ 1]
                    [ 1]
                    [ 1],
-              Condition((L, K, e1, e2)) = 88.953530.
+              Condition((L, K, e1, e2)) = 44.476...
 
         """
         # We pass ``self._L`` right back into the constructor, because
 
         """
         # We pass ``self._L`` right back into the constructor, because