Use property decorators for symbols method
[linpy.git] / polyp.py
index 9058c08..d48fd80 100644 (file)
--- a/polyp.py
+++ b/polyp.py
@@ -135,12 +135,13 @@ class Expression:
             context[symbol] = Symbol(symbol)
         return eval(string, context)
 
+    @property
     def symbols(self):
-        yield from sorted(self._coefficients)
+        return tuple(sorted(self._coefficients))
 
     @property
     def dimension(self):
-        return len(list(self.symbols()))
+        return len(list(self.symbols))
 
     def coefficient(self, symbol):
         symbol = _strsymbol(symbol)
@@ -152,7 +153,7 @@ class Expression:
     __getitem__ = coefficient
 
     def coefficients(self):
-        for symbol in self.symbols():
+        for symbol in self.symbols:
             yield symbol, self.coefficient(symbol)
 
     @property
@@ -163,14 +164,14 @@ class Expression:
         return len(self._coefficients) == 0
 
     def values(self):
-        for symbol in self.symbols():
+        for symbol in self.symbols:
             yield self.coefficient(symbol)
         yield self.constant
 
     def symbol(self):
         if not self.issymbol():
             raise ValueError('not a symbol: {}'.format(self))
-        for symbol in self.symbols():
+        for symbol in self.symbols:
             return symbol
 
     def issymbol(self):
@@ -229,7 +230,7 @@ class Expression:
 
     def __repr__(self):
         string = ''
-        symbols = sorted(self.symbols())
+        symbols = self.symbols
         i = 0
         for symbol in symbols:
             coefficient = self[symbol]
@@ -352,10 +353,10 @@ class Polyhedron:
             inequalities = []
         symbols = set()
         for equality in equalities:
-            symbols.update(equality.symbols())
+            symbols.update(equality.symbols)
         for inequality in inequalities:
-            symbols.update(inequality.symbols())
-        symbols = sorted(symbols)
+            symbols.update(inequality.symbols)
+        symbols = list(symbols)
         string = _iscc.set(symbols, equalities, inequalities)
         string = _iscc.eval(string)
         return cls._fromiscc(symbols, string)
@@ -368,7 +369,7 @@ class Polyhedron:
         if re.match(r'^\s*\{\s*\}\s*$', string):
             return empty
         self = super().__new__(cls)
-        self._symbols = _strsymbols(symbols)
+        self._symbols = sorted(_strsymbols(symbols))
         self._equalities = []
         self._inequalities = []
         string = re.sub(r'^\s*\{\s*(.*?)\s*\}\s*$', lambda m: m.group(1), string)
@@ -414,19 +415,26 @@ class Polyhedron:
         yield from self.equalities
         yield from self.inequalities
 
+    @property
     def symbols(self):
-        yield from self._symbols
+        return tuple(self._symbols)
 
     @property
     def dimension(self):
-        return len(self.symbols())
+        return len(self.symbols)
 
     def __bool__(self):
         # return false if the polyhedron is empty, true otherwise
         raise not self.isempty()
 
+    def _symbolunion(self, *others):
+        symbols = set(self.symbols)
+        for other in others:
+            symbols.update(other.symbols)
+        return sorted(symbols)
+
     def __eq__(self, other):
-        symbols = set(self.symbols()) | set(other.symbols())
+        symbols = self._symbolunion(other)
         string = '{} = {}'.format(self._toiscc(symbols), other._toiscc(symbols))
         string = _iscc.eval(string)
         return string == 'True'
@@ -442,7 +450,7 @@ class Polyhedron:
         return (self & other).isempty()
 
     def issubset(self, other):
-        symbols = set(self.symbols()) | set(other.symbols())
+        symbols = self._symbolunion(other)
         string = '{} <= {}'.format(self._toiscc(symbols), other._toiscc(symbols))
         string = _iscc.eval(string)
         return string == 'True'
@@ -451,14 +459,14 @@ class Polyhedron:
         return self.issubset(other)
 
     def __lt__(self, other):
-        symbols = set(self.symbols()) | set(other.symbols())
+        symbols = self._symbolunion(other)
         string = '{} < {}'.format(self._toiscc(symbols), other._toiscc(symbols))
         string = _iscc.eval(string)
         return string == 'True'
 
     def issuperset(self, other):
         # test whether every element in other is in the polyhedron
-        symbols = set(self.symbols()) | set(other.symbols())
+        symbols = self._symbolunion(other)
         string = '{} >= {}'.format(self._toiscc(symbols), other._toiscc(symbols))
         string = _iscc.eval(string)
         return string == 'True'
@@ -467,7 +475,7 @@ class Polyhedron:
         return self.issuperset(other)
 
     def __gt__(self, other):
-        symbols = set(self.symbols() + other.symbols())
+        symbols = self._symbolunion(other)
         string = '{} > {}'.format(self._toiscc(symbols), other._toiscc(symbols))
         string = _iscc.eval(string)
         return string == 'True'
@@ -475,10 +483,7 @@ class Polyhedron:
     def union(self, *others):
         # return a new polyhedron with elements from the polyhedron and all
         # others (convex union)
-        symbols = set(self.symbols())
-        for other in others:
-            symbols.update(other.symbols())
-        symbols = sorted(symbols)
+        symbols = self._symbolunion(*others)
         strings = [self._toiscc(symbols)]
         for other in others:
             strings.append(other._toiscc(symbols))
@@ -490,10 +495,7 @@ class Polyhedron:
         return self.union(other)
 
     def intersection(self, *others):
-        symbols = set(self.symbols())
-        for other in others:
-            symbols.update(other.symbols())
-        symbols = sorted(symbols)
+        symbols = self._symbolunion(*others)
         strings = [self._toiscc(symbols)]
         for other in others:
             strings.append(other._toiscc(symbols))
@@ -507,10 +509,7 @@ class Polyhedron:
     def difference(self, *others):
         # return a new polyhedron with elements in the polyhedron that are not
         # in the others
-        symbols = set(self.symbols())
-        for other in others:
-            symbols.update(other.symbols())
-        symbols = sorted(symbols)
+        symbols = self._symbolunion(*others)
         strings = [self._toiscc(symbols)]
         for other in others:
             strings.append(other._toiscc(symbols))
@@ -523,7 +522,7 @@ class Polyhedron:
 
     def projection(self, symbols):
         symbols = _strsymbols(symbols)
-        string = _iscc.map(symbols, self.symbols(),
+        string = _iscc.map(symbols, self.symbols,
                 self.equalities, self.inequalities)
         string = _iscc.eval('poly (dom ({}))'.format(string))
         return Polyhedron._fromiscc(symbols, string)