--- /dev/null
+== Overview ==
+
+Dunshire is a CVXOPT-based library for solving cone games. The notion
+of a cone game was introduced by Gowda[1] and extended to asymmetric
+cones in my thesis[2].
+
+== Requirements ==
+
+The only requirement is the CVXOPT library, available for most Linux
+distributions. Dunshire is targeted at python-3.x, but python-2.x will
+probably work too.
+
+[1] M. S. Gowda and G. Ravindran. On the game-theoretic value of a
+ linear transformation relative to a self-dual cone. Linear Algebra
+ and its Applications, 469:440-463, 2015.
+
+[2] You wish.
+
+[3] http://cvxopt.org/
--- /dev/null
+class SymmetricCone:
+ def __init__(self, dimension):
+ self._dimension = dimension
+
+ def dimension(self):
+ return self._dimension
+
+
+class NonnegativeOrthant(SymmetricCone):
+ pass
+
+class IceCream(SymmetricCone):
+ pass
+
+class SymmetricPSD(SymmetricCone):
+ pass
+
+class CartesianProduct(SymmetricCone):
+ def __init__(self, *factors):
+ self._factors = factors
+
+ def factors(self):
+ return self._factors
+
+ def cvxopt_dims(self):
+ d = { 'l':0, 'q':[], 's':[] }
+ d['l'] += sum([ K.dimension() for K in self.factors()
+ if isinstance(K, NonnegativeOrthant) ])
+ d['q'] = [ K.dimension() for K in self.factors()
+ if isinstance(K, IceCream) ]
+ d['s'] = [ K.dimension() for K in self.factors()
+ if isinstance(K, SymmetricPSD) ]
+ return d
+
+ def dimension(self):
+ return sum([ f.dimension() for f in self.factors() ])
+
--- /dev/null
+from cvxopt import matrix, spmatrix
+
+def append_col(A,b):
+ """
+ Append the column ``b`` to the right side of the matrix ``A``.
+ """
+ return matrix([A.trans(),b.trans()]).trans()
+
+def append_cols(cols):
+ """
+ Append a bunch of columns together, left to right.
+ """
+ if len(cols) == 0:
+ return cols
+
+ result = cols[0]
+ del(cols[0])
+ for column in cols:
+ result = append_col(result, column)
+
+ return result
+
+
+def append_row(A,b):
+ """
+ Append the row ``b`` to the bottom of the matrix ``A``.
+ """
+ return matrix([A,b])
+
+def identity(n):
+ """
+ Return the ``n``-by-``n`` identity matrix.
+ """
+ return spmatrix(1,range(n),range(n))
--- /dev/null
+from cvxopt import matrix, printing, solvers
+
+from cones import CartesianProduct, NonnegativeOrthant
+from matrices import append_cols, append_row, identity
+
+class SymmetricLinearGame:
+ """
+ A representation of a symmetric linear game.
+
+ The data for a linear game are,
+
+ * A "payoff" operator ``L``.
+ * A cone ``K``.
+ * A point ``e`` in the interior of ``K``.
+ * A point ``f`` in the interior of the dual of ``K``.
+
+ In a symmetric game, the cone ``K`` is be self-dual. We therefore
+ name the two interior points ``e1`` and ``e2`` to indicate that
+ they come from the same cone but are "chosen" by players one and
+ two respectively.
+
+ The ambient space is assumed to be the span of ``K``.
+ """
+
+ def __init__(self, L, K, e1, e2):
+ """
+ INPUT:
+
+ - ``L`` -- an n-by-b matrix represented as a list of lists
+ of real numbers.
+
+ - ``K`` -- a SymmetricCone instance.
+
+ - ``e1`` -- the interior point of ``K`` belonging to player one,
+ as a column vector.
+
+ - ``e2`` -- the interior point of ``K`` belonging to player two,
+ as a column vector.
+
+ """
+ self._K = K
+ self._C = CartesianProduct(NonnegativeOrthant(2), K, K)
+ n = self._K.dimension()
+ self._L = matrix(L, (n,n))
+ self._e1 = matrix(e1, (n,1)) # TODO: check that e1 and e2
+ self._e2 = matrix(e2, (n,1)) # are in the interior of K...
+ self._h = matrix(0, (self._C.dimension(),1), 'd')
+ self._b = matrix(1, (1,1), 'd')
+ self._c = matrix([-1,1] + ([0]*n), (n+2,1), 'd')
+ self._G = append_row(-identity(n+2),
+ append_cols([self._e1, -self._e1, -self._L]))
+ self._A = matrix([0,0] + e1, (1, n+2), 'd')
+
+ def e1(self):
+ return self._e1
+
+ def e2(self):
+ return self._e2
+
+ def L(self):
+ return self._L
+
+ def h(self):
+ return self._h
+
+ def b(self):
+ return self._b
+
+ def c(self):
+ return self._c
+
+ def G(self):
+ return self._G
+
+ def A(self):
+ return self._A
+
+ def C(self):
+ return self._C
+
+ def solve(self):
+ solvers.options['show_progress'] = False
+ soln = solvers.conelp(self.c(),
+ self.G(),
+ self.h(),
+ self.C().cvxopt_dims(),
+ self.A(),
+ self.b())
+
+ printing.options['dformat'] = '%.7f'
+ value = soln['x'][0] - soln['x'][1]
+ print('Value of the game: {:f}'.format(value))
+
+ opt1 = soln['x'][2:]
+ print('Optimal strategy (player one):')
+ print(opt1)
+
+ #opt2 = soln['y'][2:]
+ #print('Optimal strategy (player two):')
+ #print(opt2)
+
+ return soln