X-Git-Url: https://svn.cri.ensmp.fr/git/linpy.git/blobdiff_plain/1695c920d030869b3a842736fe5bcf963f2ffc52..77d9e641db24dc1edb6d0e2b91b58d395761616f:/pypol/polyhedra.py diff --git a/pypol/polyhedra.py b/pypol/polyhedra.py index 5d1bfa1..f8d413e 100644 --- a/pypol/polyhedra.py +++ b/pypol/polyhedra.py @@ -5,8 +5,8 @@ import numbers from . import islhelper from .islhelper import mainctx, libisl -from .geometry import GeometricObject, Point, Vector -from .linexprs import Expression, Symbol, Rational +from .geometry import GeometricObject, Point +from .linexprs import Expression, Rational from .domains import Domain @@ -114,6 +114,10 @@ class Polyhedron(Domain): @classmethod def _fromislbasicset(cls, islbset, symbols): + if libisl.isl_basic_set_is_empty(islbset): + return Empty + if libisl.isl_basic_set_is_universe(islbset): + return Universe islconstraints = islhelper.isl_basic_set_constraints(islbset) equalities = [] inequalities = [] @@ -184,33 +188,23 @@ class Polyhedron(Domain): return domain def __repr__(self): - if self.isempty(): - return 'Empty' - elif self.isuniverse(): - return 'Universe' + strings = [] + for equality in self.equalities: + strings.append('Eq({}, 0)'.format(equality)) + for inequality in self.inequalities: + strings.append('Ge({}, 0)'.format(inequality)) + if len(strings) == 1: + return strings[0] else: - strings = [] - for equality in self.equalities: - strings.append('Eq({}, 0)'.format(equality)) - for inequality in self.inequalities: - strings.append('Ge({}, 0)'.format(inequality)) - if len(strings) == 1: - return strings[0] - else: - return 'And({})'.format(', '.join(strings)) + return 'And({})'.format(', '.join(strings)) def _repr_latex_(self): - if self.isempty(): - return '$\\emptyset$' - elif self.isuniverse(): - return '$\\Omega$' - else: - strings = [] - for equality in self.equalities: - strings.append('{} = 0'.format(equality._repr_latex_().strip('$'))) - for inequality in self.inequalities: - strings.append('{} \\ge 0'.format(inequality._repr_latex_().strip('$'))) - return '${}$'.format(' \\wedge '.join(strings)) + strings = [] + for equality in self.equalities: + strings.append('{} = 0'.format(equality._repr_latex_().strip('$'))) + for inequality in self.inequalities: + strings.append('{} \\ge 0'.format(inequality._repr_latex_().strip('$'))) + return '$${}$$'.format(' \\wedge '.join(strings)) @classmethod def fromsympy(cls, expr): @@ -228,141 +222,50 @@ class Polyhedron(Domain): constraints.append(sympy.Ge(inequality.tosympy(), 0)) return sympy.And(*constraints) - @classmethod - def _polygon_inner_point(cls, points): - symbols = points[0].symbols - coordinates = {symbol: 0 for symbol in symbols} - for point in points: - for symbol, coordinate in point.coordinates(): - coordinates[symbol] += coordinate - for symbol in symbols: - coordinates[symbol] /= len(points) - return Point(coordinates) - @classmethod - def _sort_polygon_2d(cls, points): - if len(points) <= 3: - return points - o = cls._polygon_inner_point(points) - angles = {} - for m in points: - om = Vector(o, m) - dx, dy = (coordinate for symbol, coordinate in om.coordinates()) - angle = math.atan2(dy, dx) - angles[m] = angle - return sorted(points, key=angles.get) +class EmptyType(Polyhedron): + + __slots__ = Polyhedron.__slots__ + + def __new__(cls): + self = object().__new__(cls) + self._equalities = (Rational(1),) + self._inequalities = () + self._constraints = self._equalities + self._symbols = () + self._dimension = 0 + return self + + def __repr__(self): + return 'Empty' + + def _repr_latex_(self): + return '$$\\emptyset$$' + +Empty = EmptyType() + + +class UniverseType(Polyhedron): + + __slots__ = Polyhedron.__slots__ + + def __new__(cls): + self = object().__new__(cls) + self._equalities = () + self._inequalities = () + self._constraints = () + self._symbols = () + self._dimension = () + return self + + def __repr__(self): + return 'Universe' + + def _repr_latex_(self): + return '$$\\Omega$$' + +Universe = UniverseType() - @classmethod - def _sort_polygon_3d(cls, points): - if len(points) <= 3: - return points - o = cls._polygon_inner_point(points) - a = points[0] - oa = Vector(o, a) - norm_oa = oa.norm() - for b in points[1:]: - ob = Vector(o, b) - u = oa.cross(ob) - if not u.isnull(): - u = u.asunit() - break - else: - raise ValueError('degenerate polygon') - angles = {a: 0.} - for m in points[1:]: - om = Vector(o, m) - normprod = norm_oa * om.norm() - cosinus = max(oa.dot(om) / normprod, -1.) - sinus = u.dot(oa.cross(om)) / normprod - angle = math.acos(cosinus) - angle = math.copysign(angle, sinus) - angles[m] = angle - return sorted(points, key=angles.get) - - def faces(self): - vertices = self.vertices() - faces = [] - for constraint in self.constraints: - face = [] - for vertex in vertices: - if constraint.subs(vertex.coordinates()) == 0: - face.append(vertex) - faces.append(face) - return faces - - def plot(self): - """ - Display 3D plot of set. - """ - import matplotlib.pyplot as plt - import matplotlib.patches as patches - - if len(self.symbols)> 3: - raise TypeError - - elif len(self.symbols) == 2: - import pylab - points = [] - for verts in self.vertices(): - pairs=() - for coordinate, point in verts.coordinates(): - pairs = pairs + (float(point),) - points.append(pairs) - cent=(sum([p[0] for p in points])/len(points),sum([p[1] for p in points])/len(points)) - points.sort(key=lambda p: math.atan2(p[1]-cent[1],p[0]-cent[0])) - pylab.scatter([p[0] for p in points],[p[1] for p in points]) - pylab.gca().add_patch(patches.Polygon(points,closed=True,fill=True)) - pylab.grid() - pylab.show() - - elif len(self.symbols)==3: - from mpl_toolkits.mplot3d import Axes3D - from mpl_toolkits.mplot3d.art3d import Poly3DCollection - faces = self.faces() - fig = plt.figure() - ax = Axes3D(fig) - for face in faces: - points = [] - vertices = Polyhedron._sort_polygon_3d(face) - for verts in vertices: - pairs=() - for coordinate, point in verts.coordinates(): - pairs = pairs + (float(point),) - points.append(pairs) - collection = Poly3DCollection([points], alpha=0.7) - face_color = [0.5, 0.5, 1] # alternative: matplotlib.colors.rgb2hex([0.5, 0.5, 1]) - collection.set_facecolor(face_color) - ax.add_collection3d(collection) - ax.set_xlabel('X') - ax.set_xlim(0, 5) - ax.set_ylabel('Y') - ax.set_ylim(0, 5) - ax.set_zlabel('Z') - ax.set_zlim(0, 5) - plt.grid() - plt.show() - return points - - @classmethod - def limit(cls, faces, variable, lim): - sym = [] - if variable is 'x': - n = 0 - elif variable is 'y': - n = 1 - elif variable is 'z': - n = 2 - for face in faces: - for vert in face: - coordinates = vert.coordinates() - for point in enumerate(coordinates): - coordinates.get(n) - sym.append(points) - if lim == 0: - value = min(sym) - else: - value = max(sym) - return value def _polymorphic(func): @functools.wraps(func) @@ -423,8 +326,3 @@ def Ge(left, right): Return true if the first set is greater than or equal the second set. """ return Polyhedron([], [left - right]) - - -Empty = Eq(1, 0) - -Universe = Polyhedron([])