From 50f0fde4dca3f10e535314b1c9d325cd9283735b Mon Sep 17 00:00:00 2001 From: Vivien Maisonneuve Date: Mon, 11 Aug 2014 21:37:03 +0200 Subject: [PATCH] Docstrings and simplifications of domains.py --- linpy/domains.py | 181 ++++++++++++++++++++---------------- linpy/tests/test_domains.py | 9 -- 2 files changed, 100 insertions(+), 90 deletions(-) diff --git a/linpy/domains.py b/linpy/domains.py index 21e78db..70e5e4f 100644 --- a/linpy/domains.py +++ b/linpy/domains.py @@ -15,6 +15,13 @@ # You should have received a copy of the GNU General Public License # along with LinPy. If not, see . +""" +Polyhedral domains + +This module provides classes and functions to deal with polyhedral +domains, i.e. unions of polyhedra. +""" + import ast import functools import re @@ -36,6 +43,9 @@ __all__ = [ @functools.total_ordering class Domain(GeometricObject): + """ + This class represents polyhedral domains, i.e. unions of polyhedra. + """ __slots__ = ( '_polyhedra', @@ -44,6 +54,9 @@ class Domain(GeometricObject): ) def __new__(cls, *polyhedra): + """ + Create and return a new domain from a string or a list of polyhedra. + """ from .polyhedra import Polyhedron if len(polyhedra) == 1: argument = polyhedra[0] @@ -74,19 +87,28 @@ class Domain(GeometricObject): @property def polyhedra(self): + """ + The tuple of polyhedra which constitute the domain. + """ return self._polyhedra @property def symbols(self): + """ + The tuple of symbols present in the domain equations. + """ return self._symbols @property def dimension(self): + """ + The dimension of the domain, i.e. the number of symbols. + """ return self._dimension - def disjoint(self): + def make_disjoint(self): """ - Returns this set as disjoint. + Return an equivalent domain, whose polyhedra are disjoint. """ islset = self._toislset(self.polyhedra, self.symbols) islset = libisl.isl_set_make_disjoint(mainctx, islset) @@ -94,7 +116,7 @@ class Domain(GeometricObject): def isempty(self): """ - Returns true if this set is an Empty set. + Return True if the domain is empty. """ islset = self._toislset(self.polyhedra, self.symbols) empty = bool(libisl.isl_set_is_empty(islset)) @@ -102,11 +124,14 @@ class Domain(GeometricObject): return empty def __bool__(self): + """ + Return True if the domain is non-empty. + """ return not self.isempty() def isuniverse(self): """ - Returns true if this set is the Universe set. + Return True if the domain is universal, i.e. with no constraint. """ islset = self._toislset(self.polyhedra, self.symbols) universe = bool(libisl.isl_set_plain_is_universe(islset)) @@ -115,7 +140,7 @@ class Domain(GeometricObject): def isbounded(self): """ - Returns true if this set is bounded. + Return True if the domain is bounded. """ islset = self._toislset(self.polyhedra, self.symbols) bounded = bool(libisl.isl_set_is_bounded(islset)) @@ -124,7 +149,7 @@ class Domain(GeometricObject): def __eq__(self, other): """ - Returns true if two sets are equal. + Return True if the two domains are equal. """ symbols = self._xsymbols([self, other]) islset1 = self._toislset(self.polyhedra, symbols) @@ -136,7 +161,7 @@ class Domain(GeometricObject): def isdisjoint(self, other): """ - Return True if two sets have a null intersection. + Return True if two domains have a null intersection. """ symbols = self._xsymbols([self, other]) islset1 = self._toislset(self.polyhedra, symbols) @@ -148,7 +173,7 @@ class Domain(GeometricObject): def issubset(self, other): """ - Report whether another set contains this set. + Report whether another domain contains the domain. """ symbols = self._xsymbols([self, other]) islset1 = self._toislset(self.polyhedra, symbols) @@ -159,14 +184,12 @@ class Domain(GeometricObject): return equal def __le__(self, other): - """ - Returns true if this set is less than or equal to another set. - """ return self.issubset(other) + __le__.__doc__ = issubset.__doc__ def __lt__(self, other): """ - Returns true if this set is less than another set. + Report whether another domain is contained within the domain. """ symbols = self._xsymbols([self, other]) islset1 = self._toislset(self.polyhedra, symbols) @@ -178,21 +201,37 @@ class Domain(GeometricObject): def complement(self): """ - Returns the complement of this set. + Return the complementary domain of the domain. """ islset = self._toislset(self.polyhedra, self.symbols) islset = libisl.isl_set_complement(islset) return self._fromislset(islset, self.symbols) def __invert__(self): + return self.complement() + __invert__.__doc__ = complement.__doc__ + + def coalesce(self): """ - Returns the complement of this set. + Simplify the representation of the domain by trying to combine pairs of + polyhedra into a single polyhedron. """ - return self.complement() + islset = self._toislset(self.polyhedra, self.symbols) + islset = libisl.isl_set_coalesce(islset) + return self._fromislset(islset, self.symbols) - def simplify(self): + def detect_equalities(self): """ - Returns a set without redundant constraints. + Simplify the representation of the domain by detecting implicit + equalities. + """ + islset = self._toislset(self.polyhedra, self.symbols) + islset = libisl.isl_set_detect_equalities(islset) + return self._fromislset(islset, self.symbols) + + def remove_redundancies(self): + """ + Remove redundant constraints in the domain. """ islset = self._toislset(self.polyhedra, self.symbols) islset = libisl.isl_set_remove_redundancies(islset) @@ -200,7 +239,7 @@ class Domain(GeometricObject): def aspolyhedron(self): """ - Returns polyhedral hull of set. + Return the polyhedral hull of the domain. """ from .polyhedra import Polyhedron islset = self._toislset(self.polyhedra, self.symbols) @@ -210,26 +249,27 @@ class Domain(GeometricObject): def asdomain(self): return self - def project(self, dims): + def project(self, symbols): """ - Return new set with given dimensions removed. + Project out the symbols given in arguments. """ islset = self._toislset(self.polyhedra, self.symbols) n = 0 for index, symbol in reversed(list(enumerate(self.symbols))): - if symbol in dims: + if symbol in symbols: n += 1 elif n > 0: - islset = libisl.isl_set_project_out(islset, libisl.isl_dim_set, index + 1, n) + islset = libisl.isl_set_project_out(islset, + libisl.isl_dim_set, index + 1, n) n = 0 if n > 0: islset = libisl.isl_set_project_out(islset, libisl.isl_dim_set, 0, n) - dims = [symbol for symbol in self.symbols if symbol not in dims] - return Domain._fromislset(islset, dims) + symbols = [symbol for symbol in self.symbols if symbol not in symbols] + return Domain._fromislset(islset, symbols) def sample(self): """ - Returns a single subset of the input. + Return a sample of the domain. """ islset = self._toislset(self.polyhedra, self.symbols) islpoint = libisl.isl_set_sample_point(islset) @@ -247,7 +287,7 @@ class Domain(GeometricObject): def intersection(self, *others): """ - Return the intersection of two sets as a new set. + Return the intersection of two domains as a new domain. """ if len(others) == 0: return self @@ -259,14 +299,12 @@ class Domain(GeometricObject): return self._fromislset(islset1, symbols) def __and__(self, other): - """ - Return the intersection of two sets as a new set. - """ return self.intersection(other) + __and__.__doc__ = intersection.__doc__ def union(self, *others): """ - Return the union of sets as a new set. + Return the union of two domains as a new domain. """ if len(others) == 0: return self @@ -278,20 +316,16 @@ class Domain(GeometricObject): return self._fromislset(islset1, symbols) def __or__(self, other): - """ - Return a new set with elements from both sets. - """ return self.union(other) + __or__.__doc__ = union.__doc__ def __add__(self, other): - """ - Return new set containing all elements in both sets. - """ return self.union(other) + __add__.__doc__ = union.__doc__ def difference(self, other): """ - Return the difference of two sets as a new set. + Return the difference of two domains as a new domain. """ symbols = self._xsymbols([self, other]) islset1 = self._toislset(self.polyhedra, symbols) @@ -300,14 +334,12 @@ class Domain(GeometricObject): return self._fromislset(islset, symbols) def __sub__(self, other): - """ - Return the difference of two sets as a new set. - """ return self.difference(other) + __sub__.__doc__ = difference.__doc__ def lexmin(self): """ - Return a new set containing the lexicographic minimum of the elements in the set. + Return the lexicographic minimum of the elements in the domain. """ islset = self._toislset(self.polyhedra, self.symbols) islset = libisl.isl_set_lexmin(islset) @@ -315,44 +347,23 @@ class Domain(GeometricObject): def lexmax(self): """ - Return a new set containing the lexicographic maximum of the elements in the set. + Return the lexicographic maximum of the elements in the domain. """ islset = self._toislset(self.polyhedra, self.symbols) islset = libisl.isl_set_lexmax(islset) return self._fromislset(islset, self.symbols) - - def involves_vars(self, vars): - """ - Returns true if a set depends on given dimensions. - """ - islset = self._toislset(self.polyhedra, self.symbols) - dims = sorted(vars) - symbols = sorted(list(self.symbols)) - n = 0 - if len(dims)>0: - for dim in dims: - if dim in symbols: - first = symbols.index(dims[0]) - n +=1 - else: - first = 0 - else: - return False - value = bool(libisl.isl_set_involves_dims(islset, libisl.isl_dim_set, first, n)) - libisl.isl_set_free(islset) - return value - _RE_COORDINATE = re.compile(r'\((?P\-?\d+)\)(/(?P\d+))?') def vertices(self): """ - Return a list of vertices for this Polygon. + Return the vertices of the domain. """ from .polyhedra import Polyhedron if not self.isbounded(): raise ValueError('domain must be bounded') - islbset = self._toislbasicset(self.equalities, self.inequalities, self.symbols) + islbset = self._toislbasicset(self.equalities, self.inequalities, + self.symbols) vertices = libisl.isl_basic_set_compute_vertices(islbset); vertices = islhelper.isl_vertices_vertices(vertices) points = [] @@ -385,7 +396,7 @@ class Domain(GeometricObject): def points(self): """ - Returns the points contained in the set. + Return the points with integer coordinates contained in the domain. """ if not self.isbounded(): raise ValueError('domain must be bounded') @@ -456,7 +467,7 @@ class Domain(GeometricObject): def faces(self): """ - Returns the vertices of the faces of a polyhedra. + Return the vertices of the domain, grouped by face. """ faces = [] for polyhedron in self.polyhedra: @@ -518,10 +529,9 @@ class Domain(GeometricObject): axes.set_zlim(zmin, zmax) return axes - def plot(self, plot=None, **kwargs): """ - Display plot of this set. + Plot the domain using matplotlib. """ if not self.isbounded(): raise ValueError('domain must be bounded') @@ -533,6 +543,9 @@ class Domain(GeometricObject): raise ValueError('polyhedron must be 2 or 3-dimensional') def __contains__(self, point): + """ + Return True if point if contained within the domain. + """ for polyhedron in self.polyhedra: if point in polyhedron: return True @@ -540,8 +553,8 @@ class Domain(GeometricObject): def subs(self, symbol, expression=None): """ - Subsitute the given value into an expression and return the resulting - expression. + Subsitute symbol by expression in equations and return the resulting + domain. """ polyhedra = [polyhedron.subs(symbol, expression) for polyhedron in self.polyhedra] @@ -634,6 +647,9 @@ class Domain(GeometricObject): @classmethod def fromstring(cls, string): + """ + Convert a string into a domain. + """ # remove curly brackets string = cls._RE_BRACES.sub(r'', string) # replace '=' by '==' @@ -655,6 +671,9 @@ class Domain(GeometricObject): return cls._fromast(tree) def __repr__(self): + """ + Return repr(self). + """ assert len(self.polyhedra) >= 2 strings = [repr(polyhedron) for polyhedron in self.polyhedra] return 'Or({})'.format(', '.join(strings)) @@ -667,6 +686,9 @@ class Domain(GeometricObject): @classmethod def fromsympy(cls, expr): + """ + Convert a SymPy expression into a domain. + """ import sympy from .polyhedra import Lt, Le, Eq, Ne, Ge, Gt funcmap = { @@ -683,33 +705,30 @@ class Domain(GeometricObject): raise ValueError('non-domain expression: {!r}'.format(expr)) def tosympy(self): + """ + Convert a domain into a SymPy expression. + """ import sympy polyhedra = [polyhedron.tosympy() for polyhedron in polyhedra] return sympy.Or(*polyhedra) def And(*domains): - """ - Return the intersection of two sets as a new set. - """ if len(domains) == 0: from .polyhedra import Universe return Universe else: return domains[0].intersection(*domains[1:]) +And.__doc__ = Domain.intersection.__doc__ def Or(*domains): - """ - Return the union of sets as a new set. - """ if len(domains) == 0: from .polyhedra import Empty return Empty else: return domains[0].union(*domains[1:]) +Or.__doc__ = Domain.union.__doc__ def Not(domain): - """ - Returns the complement of this set. - """ return ~domain +Not.__doc__ = Domain.complement.__doc__ diff --git a/linpy/tests/test_domains.py b/linpy/tests/test_domains.py index 4b8c5ea..9e9f6fa 100644 --- a/linpy/tests/test_domains.py +++ b/linpy/tests/test_domains.py @@ -115,10 +115,6 @@ class TestDomain(unittest.TestCase): self.assertEqual(self.universe.project([]), self.universe) self.assertEqual(self.empty.project([]), Empty) - def test_simplify(self): - self.assertEqual(self.universe.simplify(), self.universe) - self.assertEqual(self.empty.simplify(), Empty) - def test_sample(self): self.assertEqual(self.square6.sample(), {Symbol('x'): 1, Symbol('y'): 3}) with self.assertRaises(ValueError): @@ -168,8 +164,3 @@ class TestDomain(unittest.TestCase): self.assertEqual(self.square1.lexmax(), self.lexmax) self.assertEqual(self.universe.lexmax(), self.universe) self.assertEqual(self.empty.lexmax(), Empty) - - def test_involves_vars(self): - self.assertTrue(self.square1.involves_vars(symbols('x y'))) - self.assertFalse(self.empty.involves_vars(symbols('x'))) - self.assertFalse(self.universe.involves_vars(symbols('x'))) -- 2.20.1