author Vivien Maisonneuve Tue, 2 Dec 2014 06:08:23 +0000 (07:08 +0100) committer Vivien Maisonneuve Tue, 2 Dec 2014 06:48:06 +0000 (07:48 +0100)
17 files changed:
 examples/bac2014.py patch | blob | history examples/menger.py patch | blob | history examples/nsad2010.py patch | blob | history examples/plots.py patch | blob | history examples/tesseract.py patch | blob | history linpy/__init__.py patch | blob | history linpy/domains.py patch | blob | history linpy/geometry.py patch | blob | history linpy/islhelper.py patch | blob | history linpy/linexprs.py patch | blob | history linpy/polyhedra.py patch | blob | history linpy/tests/libhelper.py patch | blob | history linpy/tests/test_domains.py patch | blob | history linpy/tests/test_geometry.py patch | blob | history linpy/tests/test_linexprs.py patch | blob | history linpy/tests/test_polyhedra.py patch | blob | history setup.py patch | blob | history

index cc02126..34ddd81 100755 (executable)
@@ -1,9 +1,9 @@
#!/usr/bin/env python3

-# This example is inspired from a math question in the French baccalaurÃ©at 2014,
+# This example is inspired from a math question in the French baccalaurÃ©at 2014
# consisting in computing the intersection of a plane with a line.

-from linpy import *
+from linpy import Eq, symbols

x, y, z = symbols('x y z')
plane = Eq(x, y) & Eq(z, 6 - 2*x)
index dcba976..8d258b1 100755 (executable)
@@ -20,21 +20,22 @@ import matplotlib.pyplot as plt
from math import ceil

from matplotlib import pylab
-from mpl_toolkits.mplot3d import Axes3D

-from linpy import *
+from linpy import Le, Polyhedron, symbols

x, y, z = symbols('x y z')

_x, _y, _z = x.asdummy(), y.asdummy(), z.asdummy()

+
def translate(domain, *, dx=0, dy=0, dz=0):
domain &= Polyhedron([x - _x + dx, y - _y + dy, z - _z + dz])
domain = domain.project([x, y, z])
domain = domain.subs({_x: x, _y: y, _z: z})
return domain

+
def _menger(domain, size):
result = domain
result |= translate(domain, dx=0, dy=size, dz=0)
@@ -58,6 +59,7 @@ def _menger(domain, size):
result |= translate(domain, dx=2*size, dy=2*size, dz=2*size)
return result

+
def menger(domain, count=1, cut=False):
size = 1
for i in range(count):
@@ -70,9 +72,11 @@ def menger(domain, count=1, cut=False):
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Compute a Menger sponge.')
+        '-n', '--iterations', type=int, default=2,
help='number of iterations (default: 2)')
+        '-c', '--cut', action='store_true', default=False,
help='cut the sponge')
args = parser.parse_args()
cube = Le(0, x) & Le(x, 1) & Le(0, y) & Le(y, 1) & Le(0, z) & Le(z, 1)
index 4b73eef..3de2ebd 100755 (executable)
@@ -8,7 +8,7 @@
# to compute the transitive closure of an affine transformer. A refined version
# of this algorithm is implemented in PIPS.

-from linpy import *
+from linpy import Dummy, Eq, Ge, Polyhedron, symbols

class Transformer:
@@ -28,7 +28,8 @@ class Transformer:
delta_symbols = [symbol.asdummy() for symbol in self.range_symbols]
k = Dummy('k')
polyhedron = self.polyhedron
-        for x, xprime, dx in zip(self.range_symbols, self.domain_symbols, delta_symbols):
+        for x, xprime, dx in zip(
+                self.range_symbols, self.domain_symbols, delta_symbols):
polyhedron &= Eq(dx, xprime - x)
polyhedron = polyhedron.project(self.symbols)
equalities, inequalities = [], []
@@ -40,7 +41,8 @@ class Transformer:
inequalities.append(inequality)
polyhedron = Polyhedron(equalities, inequalities) & Ge(k, 0)
polyhedron = polyhedron.project([k])
-        for x, xprime, dx in zip(self.range_symbols, self.domain_symbols, delta_symbols):
+        for x, xprime, dx in zip(
+                self.range_symbols, self.domain_symbols, delta_symbols):
polyhedron &= Eq(dx, xprime - x)
polyhedron = polyhedron.project(delta_symbols)
return Transformer(polyhedron, self.range_symbols, self.domain_symbols)
@@ -49,6 +51,6 @@ class Transformer:
if __name__ == '__main__':
i0, i, j0, j = symbols('i0 i j0 j')
transformer = Transformer(Eq(i, i0 + 2) & Eq(j, j0 + 1),
-        [i0, j0], [i, j])
+                              [i0, j0], [i, j])
print('T  =', transformer.polyhedron)
print('T* =', transformer.star().polyhedron)
index d172835..4b0f16e 100755 (executable)
@@ -6,30 +6,31 @@
import matplotlib.pyplot as plt

from matplotlib import pylab
-from mpl_toolkits.mplot3d import Axes3D

-from linpy import *
+from linpy import Ge, Le, symbols

x, y, z = symbols('x y z')

diam = Ge(y, x - 1) & Le(y, x + 1) & Ge(y, -x - 1) & Le(y, -x + 1)

-cham = Le(0, x, 3) & Le(0, y, 3) & Le(0, z, 3) & \
-    Le(z - 2, x, z + 2) & Le(1 - z, x, 5 - z) & \
-    Le(z - 2, y, z + 2) & Le(1 - z, y, 5 - z) & \
-    Le(y - 2, x, y + 2) & Le(1 - y, x, 5 - y)
-
-rhom = cham & \
-    Le(x + y + z, 7) & Ge(-2, -x - y - z) & \
-    Le(-1, x + y - z, 4) & Le(-1, x - y + z, 4) & Le(-1, -x + y + z, 4)
-
-cubo = Le(0, x, 5) & Le(0, y, 5) & Le(0, z, 5) & \
-    Le(x -4, y, x + 4) & Le(-x + 1, y, -x + 9) & \
-    Le(y -4, z, y + 4) & Le(-y + 1, z, -y + 9) & \
-    Le(z -4, x, z + 4) & Le(-z + 1, x, -z + 9) & \
-    Le(3, x + y + z, 12) & Le(-2, x - y + z, 7) & \
-    Le(-2, -x + y + z, 7) & Le(-2, x + y - z, 7)
+cham = (
+    Le(0, x, 3) & Le(0, y, 3) & Le(0, z, 3) &
+    Le(z - 2, x, z + 2) & Le(1 - z, x, 5 - z) &
+    Le(z - 2, y, z + 2) & Le(1 - z, y, 5 - z) &
+    Le(y - 2, x, y + 2) & Le(1 - y, x, 5 - y))
+
+rhom = cham & (
+    Le(x + y + z, 7) & Ge(-2, -x - y - z) &
+    Le(-1, x + y - z, 4) & Le(-1, x - y + z, 4) & Le(-1, -x + y + z, 4))
+
+cubo = (
+    Le(0, x, 5) & Le(0, y, 5) & Le(0, z, 5) &
+    Le(x - 4, y, x + 4) & Le(-x + 1, y, -x + 9) &
+    Le(y - 4, z, y + 4) & Le(-y + 1, z, -y + 9) &
+    Le(z - 4, x, z + 4) & Le(-z + 1, x, -z + 9) &
+    Le(3, x + y + z, 12) & Le(-2, x - y + z, 7) &
+    Le(-2, -x + y + z, 7) & Le(-2, x + y - z, 7))

if __name__ == '__main__':
index 383d7bd..d692e37 100755 (executable)
@@ -5,19 +5,22 @@
# the cube consists of 6 square faces, the hypersurface of the tesseract
# consists of 8 cubical cells.

-from linpy import *
+from linpy import Le, symbols

x, y, z, t = symbols('x y z t')

tesseract = Le(0, x, 1) & Le(0, y, 1) & Le(0, z, 1) & Le(0, t, 1)

+
def faces(polyhedron):
for points in polyhedron.faces():
face = points[0].aspolyhedron()
-        face = face.convex_union(*[point.aspolyhedron() for point in points[1:]])
+        face = face.convex_union(*[point.aspolyhedron()
+                                   for point in points[1:]])
yield face

+
if __name__ == '__main__':
print('Faces of tesseract\n\n  {}\n\nare:\n'.format(tesseract))
for face in faces(tesseract):
index bbe5693..d524fbc 100644 (file)
A polyhedral library based on isl
"""

-from .geometry import GeometricObject, Point, Vector
-from .linexprs import LinExpr, Symbol, symbols, Dummy, Rational
-from .polyhedra import Polyhedron, Lt, Le, Eq, Ne, Ge, Gt, Ne, Empty, Universe
-from .domains import Domain, And, Or, Not
from ._version import __version__
+from .domains import And, Domain, Not, Or
+from .geometry import GeometricObject, Point, Vector
+from .linexprs import Dummy, LinExpr, Rational, Symbol, symbols
+from .polyhedra import Empty, Eq, Ge, Gt, Le, Lt, Ne, Polyhedron, Universe

__all__ = [
-    'LinExpr', 'Symbol', 'symbols', 'Dummy', 'Rational',
-    'GeometricObject', 'Point', 'Vector',
-    'Polyhedron', 'Lt', 'Le', 'Eq', 'Ne', 'Ge', 'Gt', 'Empty', 'Universe',
-    'Domain', 'And', 'Or', 'Not',
'__version__',
+    'And',
+    'Domain',
+    'Dummy',
+    'Empty',
+    'Eq',
+    'Ge',
+    'GeometricObject',
+    'Gt',
+    'Le',
+    'LinExpr',
+    'Lt',
+    'Ne',
+    'Not',
+    'Or',
+    'Point',
+    'Polyhedron',
+    'Rational',
+    'Symbol',
+    'symbols',
+    'Universe',
+    'Vector',
]
index f26b2fc..7f4fa65 100644 (file)
@@ -23,14 +23,16 @@ import math
from fractions import Fraction

from . import islhelper
-from .islhelper import mainctx, libisl
-from .linexprs import LinExpr, Symbol
from .geometry import GeometricObject, Point, Vector
+from .islhelper import libisl
+from .linexprs import LinExpr, Symbol

__all__ = [
+    'And',
'Domain',
-    'And', 'Or', 'Not',
+    'Not',
+    'Or',
]

@@ -84,7 +86,7 @@ class Domain(GeometricObject):
return argument.aspolyhedron()
else:
raise TypeError('argument must be a string '
-                    'or a GeometricObject instance')
+                                'or a GeometricObject instance')
else:
for polyhedron in polyhedra:
if not isinstance(polyhedron, Polyhedron):
@@ -289,11 +291,12 @@ class Domain(GeometricObject):
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)
+            islset = libisl.isl_set_project_out(
+                islset, libisl.isl_dim_set, 0, n)
symbols = [symbol for symbol in self.symbols if symbol not in symbols]
return Domain._fromislset(islset, symbols)

@@ -309,8 +312,8 @@ class Domain(GeometricObject):
raise ValueError('domain must be non-empty')
point = {}
for index, symbol in enumerate(self.symbols):
-            coordinate = libisl.isl_point_get_coordinate_val(islpoint,
-                libisl.isl_dim_set, index)
+            coordinate = libisl.isl_point_get_coordinate_val(
+                islpoint, libisl.isl_dim_set, index)
coordinate = islhelper.isl_val_to_int(coordinate)
point[symbol] = coordinate
libisl.isl_point_free(islpoint)
@@ -402,12 +405,11 @@ class Domain(GeometricObject):
Return the vertices of the domain, as a list of rational instances of
Point.
"""
-        from .polyhedra import Polyhedron
if not self.isbounded():
raise ValueError('domain must be bounded')
islbset = self._toislbasicset(self.equalities, self.inequalities,
-            self.symbols)
-        vertices = libisl.isl_basic_set_compute_vertices(islbset);
+                                      self.symbols)
+        vertices = libisl.isl_basic_set_compute_vertices(islbset)
vertices = islhelper.isl_vertices_vertices(vertices)
points = []
for vertex in vertices:
@@ -416,11 +418,13 @@ class Domain(GeometricObject):
if self._RE_COORDINATE is None:
constraints = islhelper.isl_basic_set_constraints(expression)
for constraint in constraints:
-                    constant = libisl.isl_constraint_get_constant_val(constraint)
+                    constant = libisl.isl_constraint_get_constant_val(
+                        constraint)
constant = islhelper.isl_val_to_int(constant)
for index, symbol in enumerate(self.symbols):
-                        coefficient = libisl.isl_constraint_get_coefficient_val(constraint,
-                            libisl.isl_dim_set, index)
+                        coefficient = \
+                            libisl.isl_constraint_get_coefficient_val(
+                                constraint, libisl.isl_dim_set, index)
coefficient = islhelper.isl_val_to_int(coefficient)
if coefficient != 0:
coordinate = -Fraction(constant, coefficient)
@@ -431,7 +435,8 @@ class Domain(GeometricObject):
for symbol, match in zip(self.symbols, matches):
numerator = int(match.group('num'))
denominator = match.group('den')
-                    denominator = 1 if denominator is None else int(denominator)
+                    denominator = \
+                        1 if denominator is None else int(denominator)
coordinate = Fraction(numerator, denominator)
coordinates.append((symbol, coordinate))
points.append(Point(coordinates))
@@ -440,20 +445,19 @@ class Domain(GeometricObject):
def points(self):
"""
Return the integer points of a bounded domain, as a list of integer
-        instances of Point. If the domain is not bounded, a ValueError exception
-        is raised.
+        instances of Point. If the domain is not bounded, a ValueError
+        exception is raised.
"""
if not self.isbounded():
raise ValueError('domain must be bounded')
-        from .polyhedra import Universe, Eq
islset = self._toislset(self.polyhedra, self.symbols)
islpoints = islhelper.isl_set_points(islset)
points = []
for islpoint in islpoints:
coordinates = {}
for index, symbol in enumerate(self.symbols):
-                coordinate = libisl.isl_point_get_coordinate_val(islpoint,
-                    libisl.isl_dim_set, index)
+                coordinate = libisl.isl_point_get_coordinate_val(
+                    islpoint, libisl.isl_dim_set, index)
coordinate = islhelper.isl_val_to_int(coordinate)
coordinates[symbol] = coordinate
points.append(Point(coordinates))
@@ -610,7 +614,7 @@ class Domain(GeometricObject):
similar to LinExpr.subs().
"""
polyhedra = [polyhedron.subs(symbol, expression)
-            for polyhedron in self.polyhedra]
+                     for polyhedron in self.polyhedra]
return Domain(*polyhedra)

@classmethod
@@ -638,12 +642,12 @@ class Domain(GeometricObject):
@classmethod
def _toislset(cls, polyhedra, symbols):
polyhedron = polyhedra[0]
-        islbset = polyhedron._toislbasicset(polyhedron.equalities,
-            polyhedron.inequalities, symbols)
+        islbset = polyhedron._toislbasicset(
+            polyhedron.equalities, polyhedron.inequalities, symbols)
islset1 = libisl.isl_set_from_basic_set(islbset)
for polyhedron in polyhedra[1:]:
-            islbset = polyhedron._toislbasicset(polyhedron.equalities,
-                polyhedron.inequalities, symbols)
+            islbset = polyhedron._toislbasicset(
+                polyhedron.equalities, polyhedron.inequalities, symbols)
islset2 = libisl.isl_set_from_basic_set(islbset)
islset1 = libisl.isl_set_union(islset1, islset2)
return islset1
@@ -754,7 +758,7 @@ class Domain(GeometricObject):
Convert the domain to a SymPy expression.
"""
import sympy
-        polyhedra = [polyhedron.tosympy() for polyhedron in polyhedra]
+        polyhedra = [polyhedron.tosympy() for polyhedron in self.polyhedra]
return sympy.Or(*polyhedra)

@@ -768,6 +772,7 @@ def And(*domains):
else:
return domains[0].intersection(*domains[1:])

+
def Or(*domains):
"""
Create the union domain of the domains given in arguments.
@@ -778,6 +783,7 @@ def Or(*domains):
else:
return domains[0].union(*domains[1:])

+
def Not(domain):
"""
Create the complementary domain of the domain given in argument.
index 0b05493..80f7771 100644 (file)
@@ -19,8 +19,8 @@ import math
import numbers
import operator

-from abc import ABC, abstractproperty, abstractmethod
-from collections import OrderedDict, Mapping
+from abc import ABC, abstractmethod, abstractproperty
+from collections import Mapping, OrderedDict

from .linexprs import Symbol

@@ -79,8 +79,8 @@ class Coordinates:

def __new__(cls, coordinates):
"""
-        Create a coordinate system from a dictionary or a sequence that maps the
-        symbols to their coordinates. Coordinates must be rational numbers.
+        Create a coordinate system from a dictionary or a sequence that maps
+        the symbols to their coordinates. Coordinates must be rational numbers.
"""
if isinstance(coordinates, Mapping):
coordinates = coordinates.items()
@@ -155,7 +155,7 @@ class Coordinates:

def __repr__(self):
string = ', '.join(['{!r}: {!r}'.format(symbol, coordinate)
-            for symbol, coordinate in self.coordinates()])
+                            for symbol, coordinate in self.coordinates()])
return '{}({{{}}})'.format(self.__class__.__name__, string)

def _map(self, func):
@@ -202,8 +202,8 @@ class Point(Coordinates, GeometricObject):
def __sub__(self, other):
"""
If other is a point, substract it from self and return the resulting
-        vector. If other is a vector, translate the point by the opposite vector
-        and returns the resulting point.
+        vector. If other is a vector, translate the point by the opposite
+        vector and returns the resulting point.
"""
coordinates = []
if isinstance(other, Point):
@@ -231,8 +231,8 @@ class Vector(Coordinates):

def __new__(cls, initial, terminal=None):
"""
-        Create a vector from a dictionary or a sequence that maps the symbols to
-        their coordinates, or as the displacement between two points.
+        Create a vector from a dictionary or a sequence that maps the symbols
+        to their coordinates, or as the displacement between two points.
"""
if not isinstance(initial, Point):
initial = Point(initial)
@@ -341,9 +341,6 @@ class Vector(Coordinates):
result += coordinate1 * coordinate2
return result

-    def __hash__(self):
-        return super().__hash__()
-
def norm(self):
"""
Return the norm of the vector.
@@ -361,7 +358,7 @@ class Vector(Coordinates):

def asunit(self):
"""
-        Return the normalized vector, i.e. the vector of same direction but with
-        norm 1.
+        Return the normalized vector, i.e. the vector of same direction but
+        with norm 1.
"""
return self / self.norm()
index b0dffe7..d87eaa3 100644 (file)
# You should have received a copy of the GNU General Public License
# along with LinPy.  If not, see <http://www.gnu.org/licenses/>.

-import ctypes, ctypes.util
+import ctypes
+import ctypes.util
import re

from . import _islhelper
-from ._islhelper import *
+from ._islhelper import (isl_basic_set_constraints, isl_set_basic_sets,
+                         isl_set_points, isl_vertices_vertices)

__all__ = [
-    'libisl',
-    'isl_version',
-    'mainctx',
-    'isl_val_to_int',
-    'isl_basic_set_to_str', 'isl_basic_set_constraints',
-    'isl_set_to_str', 'isl_set_basic_sets',
+    'isl_basic_set_constraints',
+    'isl_basic_set_to_str',
+    'isl_multi_aff_to_str',
+    'isl_set_basic_sets',
'isl_set_points',
+    'isl_set_to_str',
+    'isl_val_to_int',
+    'isl_version',
'isl_vertices_vertices',
-    'isl_multi_aff_to_str',
+    'libisl',
+    'mainctx',
]

@@ -48,24 +52,28 @@ mainctx = libisl.isl_ctx_alloc()

libisl.isl_printer_get_str.restype = ctypes.c_char_p

+
def isl_val_to_int(islval):
islpr = libisl.isl_printer_to_str(mainctx)
islpr = libisl.isl_printer_print_val(islpr, islval)
string = libisl.isl_printer_get_str(islpr).decode()
return int(string)

+
def isl_basic_set_to_str(islbset):
islpr = libisl.isl_printer_to_str(mainctx)
islpr = libisl.isl_printer_print_basic_set(islpr, islbset)
string = libisl.isl_printer_get_str(islpr).decode()
return string

+
def isl_set_to_str(islset):
islpr = libisl.isl_printer_to_str(mainctx)
islpr = libisl.isl_printer_print_set(islpr, islset)
string = libisl.isl_printer_get_str(islpr).decode()
return string

+
def isl_multi_aff_to_str(islmaff):
islpr = libisl.isl_printer_to_str(mainctx)
islpr = libisl.isl_printer_print_multi_aff(islpr, islmaff)
index f361218..ccfbbfa 100644 (file)
@@ -20,14 +20,16 @@ import functools
import numbers
import re

-from collections import OrderedDict, defaultdict, Mapping
+from collections import defaultdict, Mapping, OrderedDict
from fractions import Fraction, gcd

__all__ = [
+    'Dummy',
'LinExpr',
-    'Symbol', 'Dummy', 'symbols',
'Rational',
+    'Symbol',
+    'symbols',
]

@@ -59,8 +61,8 @@ class LinExpr:
def __new__(cls, coefficients=None, constant=0):
"""
Return a linear expression from a dictionary or a sequence, that maps
-        symbols to their coefficients, and a constant term. The coefficients and
-        the constant term must be rational numbers.
+        symbols to their coefficients, and a constant term. The coefficients
+        and the constant term must be rational numbers.

For example, the linear expression x + 2*y + 1 can be constructed using
one of the following instructions:
@@ -79,9 +81,9 @@ class LinExpr:
>>> LinExpr('x + 2y + 1')

A linear expression with a single symbol of coefficient 1 and no
-        constant term is automatically subclassed as a Symbol instance. A linear
-        expression with no symbol, only a constant term, is automatically
-        subclassed as a Rational instance.
+        constant term is automatically subclassed as a Symbol instance. A
+        linear expression with no symbol, only a constant term, is
+        automatically subclassed as a Rational instance.
"""
if isinstance(coefficients, str):
if constant != 0:
@@ -105,8 +107,9 @@ class LinExpr:
symbol, coefficient = coefficients[0]
if coefficient == 1:
return symbol
-        coefficients = [(symbol, Fraction(coefficient))
-            for symbol, coefficient in coefficients if coefficient != 0]
+        coefficients = [(symbol_, Fraction(coefficient_))
+                        for symbol_, coefficient_ in coefficients
+                        if coefficient_ != 0]
coefficients.sort(key=lambda item: item[0].sortkey())
self = object().__new__(cls)
self._coefficients = OrderedDict(coefficients)
@@ -223,7 +226,8 @@ class LinExpr:
Return the product of the linear expression by a rational.
"""
if isinstance(other, numbers.Rational):
-            coefficients = ((symbol, coefficient * other)
+            coefficients = (
+                (symbol, coefficient * other)
for symbol, coefficient in self._coefficients.items())
constant = self._constant * other
return LinExpr(coefficients, constant)
@@ -236,7 +240,8 @@ class LinExpr:
Return the quotient of the linear expression by a rational.
"""
if isinstance(other, numbers.Rational):
-            coefficients = ((symbol, coefficient / other)
+            coefficients = (
+                (symbol, coefficient / other)
for symbol, coefficient in self._coefficients.items())
constant = self._constant / other
return LinExpr(coefficients, constant)
@@ -280,7 +285,7 @@ class LinExpr:
make all values integer.
"""
lcd = functools.reduce(lambda a, b: a*b // gcd(a, b),
-            [value.denominator for value in self.values()])
+                               [value.denominator for value in self.values()])
return self * lcd

def subs(self, symbol, expression=None):
@@ -405,10 +410,12 @@ class LinExpr:
symbol = Symbol(symbol.name)
coefficients.append((symbol, coefficient))
else:
-                raise TypeError('non-linear expression: {!r}'.format(expression))
+                raise TypeError('non-linear expression: {!r}'.format(
+                    expression))
expression = LinExpr(coefficients, constant)
if not isinstance(expression, cls):
-            raise TypeError('cannot convert to a {} instance'.format(cls.__name__))
+            raise TypeError('cannot convert to a {} instance'.format(
+                cls.__name__))
return expression

def tosympy(self):
index 820b014..9e740a4 100644 (file)
# along with LinPy.  If not, see <http://www.gnu.org/licenses/>.

import functools
-import math
import numbers

from . import islhelper

-from .islhelper import mainctx, libisl
+from .domains import Domain
from .geometry import GeometricObject, Point
+from .islhelper import libisl, mainctx
from .linexprs import LinExpr, Rational
-from .domains import Domain

__all__ = [
+    'Empty',
+    'Eq',
+    'Ge',
+    'Gt',
+    'Le',
+    'Lt',
+    'Ne',
'Polyhedron',
-    'Lt', 'Le', 'Eq', 'Ne', 'Ge', 'Gt',
-    'Empty', 'Universe',
+    'Universe',
]

class Polyhedron(Domain):
"""
A convex polyhedron (or simply "polyhedron") is the space defined by a
-    system of linear equalities and inequalities. This space can be unbounded. A
-    Z-polyhedron (simply called "polyhedron" in LinPy) is the set of integer
+    system of linear equalities and inequalities. This space can be unbounded.
+    Z-polyhedron (simply called "polyhedron" in LinPy) is the set of integer
points in a convex polyhedron.
"""

@@ -51,9 +56,9 @@ class Polyhedron(Domain):

def __new__(cls, equalities=None, inequalities=None):
"""
-        Return a polyhedron from two sequences of linear expressions: equalities
-        is a list of expressions equal to 0, and inequalities is a list of
-        expressions greater or equal to 0. For example, the polyhedron
+        Return a polyhedron from two sequences of linear expressions:
+        equalities is a list of expressions equal to 0, and inequalities is a
+        list of expressions greater or equal to 0. For example, the polyhedron
0 <= x <= 2, 0 <= y <= 2 can be constructed with:

>>> x, y = symbols('x y')
@@ -62,8 +67,9 @@ class Polyhedron(Domain):
And(0 <= x, x <= 2, 0 <= y, y <= 2)

It may be easier to use comparison operators LinExpr.__lt__(),
-        LinExpr.__le__(), LinExpr.__ge__(), LinExpr.__gt__(), or functions Lt(),
-        Le(), Eq(), Ge() and Gt(), using one of the following instructions:
+        LinExpr.__le__(), LinExpr.__ge__(), LinExpr.__gt__(), or
+        functions Lt(), Le(), Eq(), Ge() and Gt(), using one of the following
+        instructions:

>>> x, y = symbols('x y')
>>> square1 = (0 <= x) & (x <= 2) & (0 <= y) & (y <= 2)
@@ -74,9 +80,9 @@ class Polyhedron(Domain):
>>> square1 = Polyhedron('0 <= x <= 2, 0 <= y <= 2')

Finally, a polyhedron can be constructed from a GeometricObject
-        instance, calling the GeometricObject.aspolyedron() method. This way, it
-        is possible to compute the polyhedral hull of a Domain instance, i.e.,
-        the convex hull of two polyhedra:
+        instance, calling the GeometricObject.aspolyedron() method. This way,
+        it is possible to compute the polyhedral hull of a Domain instance,
+        i.e., the convex hull of two polyhedra:

>>> square1 = Polyhedron('0 <= x <= 2, 0 <= y <= 2')
>>> square2 = Polyhedron('1 <= x <= 3, 1 <= y <= 3')
@@ -100,7 +106,7 @@ class Polyhedron(Domain):
sc_equalities.append(Rational(equality).scaleint())
else:
raise TypeError('equalities must be linear expressions '
-                        'or rational numbers')
+                                    'or rational numbers')
sc_inequalities = []
if inequalities is not None:
for inequality in inequalities:
@@ -110,7 +116,7 @@ class Polyhedron(Domain):
sc_inequalities.append(Rational(inequality).scaleint())
else:
raise TypeError('inequalities must be linear expressions '
-                        'or rational numbers')
+                                    'or rational numbers')
symbols = cls._xsymbols(sc_equalities + sc_inequalities)
islbset = cls._toislbasicset(sc_equalities, sc_inequalities, symbols)
return cls._fromislbasicset(islbset, symbols)
@@ -148,7 +154,7 @@ class Polyhedron(Domain):

def isuniverse(self):
islbset = self._toislbasicset(self.equalities, self.inequalities,
-            self.symbols)
+                                      self.symbols)
universe = bool(libisl.isl_basic_set_is_universe(islbset))
libisl.isl_basic_set_free(islbset)
return universe
@@ -180,9 +186,9 @@ class Polyhedron(Domain):

def subs(self, symbol, expression=None):
equalities = [equality.subs(symbol, expression)
-            for equality in self.equalities]
+                      for equality in self.equalities]
inequalities = [inequality.subs(symbol, expression)
-            for inequality in self.inequalities]
+                        for inequality in self.inequalities]
return Polyhedron(equalities, inequalities)

def asinequalities(self):
@@ -234,8 +240,8 @@ class Polyhedron(Domain):
constant = islhelper.isl_val_to_int(constant)
coefficients = {}
for index, symbol in enumerate(symbols):
-                coefficient = libisl.isl_constraint_get_coefficient_val(islconstraint,
-                    libisl.isl_dim_set, index)
+                coefficient = libisl.isl_constraint_get_coefficient_val(
+                    islconstraint, libisl.isl_dim_set, index)
coefficient = islhelper.isl_val_to_int(coefficient)
if coefficient != 0:
coefficients[symbol] = coefficient
@@ -260,26 +266,28 @@ class Polyhedron(Domain):
islbset = libisl.isl_basic_set_universe(libisl.isl_space_copy(islsp))
islls = libisl.isl_local_space_from_space(islsp)
for equality in equalities:
-            isleq = libisl.isl_equality_alloc(libisl.isl_local_space_copy(islls))
+            isleq = libisl.isl_equality_alloc(
+                libisl.isl_local_space_copy(islls))
for symbol, coefficient in equality.coefficients():
islval = str(coefficient).encode()
index = indices[symbol]
-                isleq = libisl.isl_constraint_set_coefficient_val(isleq,
-                    libisl.isl_dim_set, index, islval)
+                isleq = libisl.isl_constraint_set_coefficient_val(
+                    isleq, libisl.isl_dim_set, index, islval)
if equality.constant != 0:
islval = str(equality.constant).encode()
isleq = libisl.isl_constraint_set_constant_val(isleq, islval)
for inequality in inequalities:
-            islin = libisl.isl_inequality_alloc(libisl.isl_local_space_copy(islls))
+            islin = libisl.isl_inequality_alloc(
+                libisl.isl_local_space_copy(islls))
for symbol, coefficient in inequality.coefficients():
islval = str(coefficient).encode()
index = indices[symbol]
-                islin = libisl.isl_constraint_set_coefficient_val(islin,
-                    libisl.isl_dim_set, index, islval)
+                islin = libisl.isl_constraint_set_coefficient_val(
+                    islin, libisl.isl_dim_set, index, islval)
if inequality.constant != 0:
islval = str(inequality.constant).encode()
@@ -333,7 +341,8 @@ class Polyhedron(Domain):
def fromsympy(cls, expression):
domain = Domain.fromsympy(expression)
if not isinstance(domain, Polyhedron):
-            raise ValueError('non-polyhedral expression: {!r}'.format(expression))
+            raise ValueError('non-polyhedral expression: {!r}'.format(
+                expression))
return domain

def tosympy(self):
@@ -400,10 +409,11 @@ def _pseudoconstructor(func):
expression = Rational(expression)
else:
raise TypeError('arguments must be rational numbers '
-                        'or linear expressions')
+                                    'or linear expressions')
return func(*expressions)
return wrapper

+
@_pseudoconstructor
def Lt(*expressions):
"""
@@ -414,6 +424,7 @@ def Lt(*expressions):
inequalities.append(right - left - 1)
return Polyhedron([], inequalities)

+
@_pseudoconstructor
def Le(*expressions):
"""
@@ -424,6 +435,7 @@ def Le(*expressions):
inequalities.append(right - left)
return Polyhedron([], inequalities)

+
@_pseudoconstructor
def Eq(*expressions):
"""
@@ -434,6 +446,7 @@ def Eq(*expressions):
equalities.append(left - right)
return Polyhedron(equalities, [])

+
@_pseudoconstructor
def Ne(*expressions):
"""
@@ -445,6 +458,7 @@ def Ne(*expressions):
domain &= ~Eq(left, right)
return domain

+
@_pseudoconstructor
def Ge(*expressions):
"""
@@ -455,6 +469,7 @@ def Ge(*expressions):
inequalities.append(left - right)
return Polyhedron([], inequalities)

+
@_pseudoconstructor
def Gt(*expressions):
"""
index 7cefbb2..be14067 100644 (file)
# along with LinPy.  If not, see <http://www.gnu.org/licenses/>.

import functools
+import importlib
import unittest

try:

-    import sympy
+    importlib.import_module('sympy')

def requires_sympy(func):
@functools.wraps(func)
index 0955a09..2d30b8b 100644 (file)
@@ -17,9 +17,9 @@

import unittest

-from ..domains import *
+from ..domains import And, Or
from ..linexprs import Symbol, symbols
-from ..polyhedra import *
+from ..polyhedra import Empty, Eq, Ge, Polyhedron

class TestDomain(unittest.TestCase):
@@ -27,23 +27,33 @@ class TestDomain(unittest.TestCase):
def setUp(self):
x, y = symbols('x y')
self.square1 = Polyhedron(inequalities=[x, 2 - x, y, 2 - y])
-        self.square2 = Polyhedron(inequalities=[x - 1, 3 - x , y - 1, 3 - y]) #correct representation
+        self.square2 = Polyhedron(inequalities=[x - 1, 3 - x, y - 1, 3 - y])
self.square3 = Polyhedron(inequalities=[x, 3 - x, y, 3 - y])
self.square4 = Polyhedron(inequalities=[x - 1, 2 - x, y - 1, 2 - y])
-        self.square5 = Polyhedron(inequalities=[x - 3, 6 - x, y - 3, 6 -y])
-        self.square6 = Polyhedron(equalities=[3 - y], inequalities=[x - 1, 3 - x, y - 1])
+        self.square5 = Polyhedron(inequalities=[x - 3, 6 - x, y - 3, 6 - y])
+        self.square6 = Polyhedron(equalities=[3 - y],
+                                  inequalities=[x - 1, 3 - x, y - 1])
self.unbound_poly = Polyhedron(inequalities=[x, 3 - x, y])
self.universe = Polyhedron([])
self.empty = Empty
self.disjoint = And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0))
-        self.complement = Or(Ge(-x - 1, 0), Ge(x - 3, 0), And(Ge(x, 0), Ge(-x + 2, 0), Ge(-y - 1, 0)), And(Ge(x, 0), Ge(-x + 2, 0), Ge(y - 3, 0)))
+        self.complement = Or(Ge(-x - 1, 0), Ge(x - 3, 0),
+                             And(Ge(x, 0), Ge(-x + 2, 0), Ge(-y - 1, 0)),
+                             And(Ge(x, 0), Ge(-x + 2, 0), Ge(y - 3, 0)))
self.hull = And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0))
self.dropped = And(Ge(y, 0), Ge(-y + 2, 0))
-        self.intersection = And(Ge(x - 1, 0), Ge(-x + 2, 0), Ge(y - 1, 0), Ge(-y + 2, 0))
-        self.union = Or(And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0)), And(Ge(x - 1, 0), Ge(-x + 3, 0), Ge(y - 1, 0), Ge(-y + 3, 0)))
-        self.sum1 = Or(And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0)), And(Ge(x - 1, 0), Ge(-x + 3, 0), Ge(y - 1, 0), Ge(-y + 3, 0)))
-        self.sum2 =And(Ge(x, 0), Ge(y, 0), Ge(-y + 3, 0), Ge(-x + 3, 0), Ge(x - y + 2, 0), Ge(-x + y + 2, 0))
-        self.difference1 = Or(And(Eq(x - 3, 0), Ge(y - 1, 0), Ge(-y + 3, 0)), And(Eq(y - 3, 0), Ge(x - 1, 0), Ge(-x + 2, 0)))
+        self.intersection = And(Ge(x - 1, 0), Ge(-x + 2, 0), Ge(y - 1, 0),
+                                Ge(-y + 2, 0))
+        self.union = Or(And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0)),
+                        And(Ge(x - 1, 0), Ge(-x + 3, 0), Ge(y - 1, 0),
+                            Ge(-y + 3, 0)))
+        self.sum1 = Or(And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0)),
+                       And(Ge(x - 1, 0), Ge(-x + 3, 0), Ge(y - 1, 0),
+                           Ge(-y + 3, 0)))
+        self.sum2 = And(Ge(x, 0), Ge(y, 0), Ge(-y + 3, 0), Ge(-x + 3, 0),
+                        Ge(x - y + 2, 0), Ge(-x + y + 2, 0))
+        self.difference1 = Or(And(Eq(x - 3, 0), Ge(y - 1, 0), Ge(-y + 3, 0)),
+                              And(Eq(y - 3, 0), Ge(x - 1, 0), Ge(-x + 2, 0)))
self.difference2 = And(Ge(x + y - 4, 0), Ge(-x + 3, 0), Ge(-y + 3, 0))
self.lexmin = And(Eq(y, 0), Eq(x, 0))
self.lexmax = And(Eq(y - 2, 0), Eq(x - 2, 0))
@@ -116,13 +126,15 @@ class TestDomain(unittest.TestCase):
self.assertEqual(self.empty.project([]), Empty)

def test_sample(self):
-        self.assertEqual(self.square6.sample(), {Symbol('x'): 1, Symbol('y'): 3})
+        self.assertEqual(self.square6.sample(),
+                         {Symbol('x'): 1, Symbol('y'): 3})
with self.assertRaises(ValueError):
self.empty.sample()
self.assertEqual(self.universe.sample(), {})

def test_intersection(self):
-        self.assertEqual(self.square1.intersection(self.square2), self.intersection)
+        self.assertEqual(self.square1.intersection(self.square2),
+                         self.intersection)

def test_and(self):
self.assertEqual(self.square2 & self.square1, self.intersection)
@@ -151,7 +163,8 @@ class TestDomain(unittest.TestCase):

def test_difference(self):
self.assertEqual(self.square2 - self.square1, self.difference1)
-        self.assertEqual(Polyhedron(self.square2 - self.square1), self.difference2)
+        self.assertEqual(Polyhedron(self.square2 - self.square1),
+                         self.difference2)
self.assertEqual(self.square2 - self.square2, Empty)
self.assertEqual(self.universe - self.universe, Empty)

index 0f3884c..faa20df 100644 (file)
@@ -18,7 +18,7 @@
import math
import unittest

-from ..geometry import *
+from ..geometry import Point, Vector
from ..linexprs import Symbol
from ..polyhedra import Eq

@@ -37,7 +37,7 @@ class TestPoint(unittest.TestCase):
def test_new(self):
self.assertEqual(Point({self.x: 10, self.y: 5, self.z: 1}), self.pt1)
self.assertEqual(Point([(self.x, 10), (self.y, 5), (self.z, 1)]),
-            self.pt1)
+                         self.pt1)

def test_symbols(self):
self.assertTupleEqual(self.pt1.symbols, (self.x, self.y, self.z))
@@ -57,11 +57,10 @@ class TestPoint(unittest.TestCase):

def test_coordinates(self):
self.assertListEqual(list(self.pt1.coordinates()),
-            [(self.x, 10), (self.y, 5), (self.z, 1)])
+                             [(self.x, 10), (self.y, 5), (self.z, 1)])

def test_values(self):
-        self.assertListEqual(list(self.pt1.values()),
-            [10, 5, 1])
+        self.assertListEqual(list(self.pt1.values()), [10, 5, 1])

def test_isorigin(self):
self.assertFalse(self.pt1.isorigin())
@@ -73,15 +72,15 @@ class TestPoint(unittest.TestCase):

self.assertEqual(self.pt1 + self.vec1,
-            Point({self.x: 30, self.y: 35, self.z: 41}))
+                         Point({self.x: 30, self.y: 35, self.z: 41}))
with self.assertRaises(TypeError):
self.pt1 + self.pt2

def test_sub(self):
self.assertEqual(self.pt1 - self.pt2,
-            Vector({self.x: -5, self.y: -35, self.z: -59}))
+                         Vector({self.x: -5, self.y: -35, self.z: -59}))
self.assertEqual(self.pt1 - self.vec1,
-            Point({self.x: -10, self.y: -25, self.z: -39}))
+                         Point({self.x: -10, self.y: -25, self.z: -39}))

def test_eq(self):
self.assertEqual(self.pt1, self.pt1)
@@ -90,7 +89,7 @@ class TestPoint(unittest.TestCase):

def test_aspolyhedron(self):
self.assertEqual(self.pt1.aspolyhedron(),
-            Eq(self.x, 10) & Eq(self.y, 5) & Eq(self.z, 1))
+                         Eq(self.x, 10) & Eq(self.y, 5) & Eq(self.z, 1))

def test_repr(self):
self.assertEqual(repr(self.pt1), 'Point({x: 10, y: 5, z: 1})')
@@ -108,19 +107,25 @@ class TestVector(unittest.TestCase):
self.vec2 = Vector({self.x: 45, self.y: 70, self.z: 80})

-        self.assertEqual(self.vec1 + self.pt1, Point({self.x: 30, self.y: 35, self.z: 41}))
-        self.assertEqual(self.vec1 + self.vec2, Vector({self.x: 65, self.y: 100, self.z: 120}))
+        self.assertEqual(self.vec1 + self.pt1,
+                         Point({self.x: 30, self.y: 35, self.z: 41}))
+        self.assertEqual(self.vec1 + self.vec2,
+                         Vector({self.x: 65, self.y: 100, self.z: 120}))

def test_angle(self):
self.assertEqual(math.degrees(self.vec1.angle(self.vec1)), 0)
-        self.assertAlmostEqual(math.degrees(self.vec1.angle(self.vec2)), 4.15129, places=5)
-        self.assertAlmostEqual(math.degrees(self.vec2.angle(self.vec1)), 4.15129, places=5)
+        self.assertAlmostEqual(math.degrees(self.vec1.angle(self.vec2)),
+                               4.15129, places=5)
+        self.assertAlmostEqual(math.degrees(self.vec2.angle(self.vec1)),
+                               4.15129, places=5)

def test_cross(self):
-        self.assertEqual(self.vec1.cross(self.vec2), Vector({self.x: -400, self.y: 200, self.z: 50}))
+        self.assertEqual(self.vec1.cross(self.vec2),
+                         Vector({self.x: -400, self.y: 200, self.z: 50}))

def test_div(self):
-        self.assertEqual(self.vec1 / 10, Vector({self.x: 2, self.y: 3, self.z: 4}))
+        self.assertEqual(self.vec1 / 10,
+                         Vector({self.x: 2, self.y: 3, self.z: 4}))

def test_dot(self):
self.assertEqual(self.vec1.dot(self.vec2), 6200)
@@ -130,11 +135,14 @@ class TestVector(unittest.TestCase):
self.assertNotEqual(self.vec1, self.vec2)

def test_mul(self):
-        self.assertEqual(75 * self.vec1, Vector({self.x: 1500, self.y: 2250, self.z: 3000}))
-        self.assertEqual(self.vec1 * 75, Vector({self.x: 1500, self.y: 2250, self.z: 3000}))
+        self.assertEqual(75 * self.vec1,
+                         Vector({self.x: 1500, self.y: 2250, self.z: 3000}))
+        self.assertEqual(self.vec1 * 75,
+                         Vector({self.x: 1500, self.y: 2250, self.z: 3000}))

def test_neg(self):
-        self.assertEqual(-self.vec1, Vector({self.x: -20, self.y: -30, self.z: -40}))
+        self.assertEqual(-self.vec1,
+                         Vector({self.x: -20, self.y: -30, self.z: -40}))

def test_norm(self):
self.assertAlmostEqual(self.vec1.norm(), 53.85165, places=5)
@@ -149,5 +157,7 @@ class TestVector(unittest.TestCase):
self.assertAlmostEqual(unit[self.z], 0.74278, 5)

def test_sub(self):
-        self.assertEqual(self.vec1 - self.pt1, Point({self.x: 10, self.y: 25, self.z: 39}))
-        self.assertEqual(self.vec1 - self.vec2, Vector({self.x: -25, self.y: -40, self.z: -40}))
+        self.assertEqual(self.vec1 - self.pt1,
+                         Point({self.x: 10, self.y: 25, self.z: 39}))
+        self.assertEqual(self.vec1 - self.vec2,
+                         Vector({self.x: -25, self.y: -40, self.z: -40}))
index f189260..0c50e6c 100644 (file)
# You should have received a copy of the GNU General Public License
# along with LinPy.  If not, see <http://www.gnu.org/licenses/>.

-import functools
import unittest

from fractions import Fraction

-from ..linexprs import *
+from ..linexprs import Dummy, LinExpr, Rational, Symbol, symbols
from .libhelper import requires_sympy

@@ -76,7 +75,8 @@ class TestLinExpr(unittest.TestCase):
self.expr[self.expr]

def test_coefficients(self):
-        self.assertListEqual(list(self.expr.coefficients()), [(self.x, 1), (self.y, -2)])
+        self.assertListEqual(list(self.expr.coefficients()),
+                             [(self.x, 1), (self.y, -2)])

def test_constant(self):
self.assertEqual(self.x.constant, 0)
@@ -151,7 +151,7 @@ class TestLinExpr(unittest.TestCase):

def test_scaleint(self):
self.assertEqual((self.x + self.y/2 + self.z/3).scaleint(),
-                6*self.x + 3*self.y + 2*self.z)
+                         6*self.x + 3*self.y + 2*self.z)

def test_subs(self):
self.assertEqual(self.x.subs(self.x, 3), 3)
@@ -161,9 +161,12 @@ class TestLinExpr(unittest.TestCase):
self.assertEqual(self.x.subs(self.y, 3), self.x)
self.assertEqual(self.pi.subs(self.x, 3), self.pi)
self.assertEqual(self.expr.subs(self.x, -3), -2 * self.y)
-        self.assertEqual(self.expr.subs([(self.x, self.y), (self.y, self.x)]), -2*self.x + self.y + 3)
-        self.assertEqual(self.expr.subs({self.x: self.z, self.y: self.z}), 3 - self.z)
-        self.assertEqual(self.expr.subs({self.x: self.z, self.y: self.z}), 3 - self.z)
+        self.assertEqual(self.expr.subs([(self.x, self.y), (self.y, self.x)]),
+                         -2*self.x + self.y + 3)
+        self.assertEqual(self.expr.subs({self.x: self.z, self.y: self.z}),
+                         3 - self.z)
+        self.assertEqual(self.expr.subs({self.x: self.z, self.y: self.z}),
+                         3 - self.z)
with self.assertRaises(TypeError):
self.x.subs('x', 3)
with self.assertRaises(TypeError):
index d0ebe57..60e1b33 100644 (file)
# You should have received a copy of the GNU General Public License
# along with LinPy.  If not, see <http://www.gnu.org/licenses/>.

-import functools
import unittest

from ..linexprs import symbols
-from ..polyhedra import *
+from ..polyhedra import Empty, Polyhedron, Universe
from .libhelper import requires_sympy

@@ -37,11 +36,13 @@ class TestPolyhedron(unittest.TestCase):

def test_repr(self):
self.assertEqual(repr(self.square),
-            "And(0 <= x, x <= 1, 0 <= y, y <= 1)")
+                         'And(0 <= x, x <= 1, 0 <= y, y <= 1)')

def test_fromstring(self):
-        self.assertEqual(Polyhedron.fromstring('{x >= 0, -x + 1 >= 0, '
-            'y >= 0, -y + 1 >= 0}'), self.square)
+        self.assertEqual(
+            Polyhedron.fromstring(
+                '{x >= 0, -x + 1 >= 0, y >= 0, -y + 1 >= 0}'),
+            self.square)

def test_isempty(self):
self.assertFalse(self.square.isempty())
@@ -53,14 +54,17 @@ class TestPolyhedron(unittest.TestCase):
def test_fromsympy(self):
import sympy
sp_x, sp_y = sympy.symbols('x y')
-        self.assertEqual(Polyhedron.fromsympy((sp_x >= 0) & (sp_x <= 1) &
-            (sp_y >= 0) & (sp_y <= 1)), self.square)
+        self.assertEqual(
+            Polyhedron.fromsympy(
+                (sp_x >= 0) & (sp_x <= 1) & (sp_y >= 0) & (sp_y <= 1)),
+            self.square)

@requires_sympy
def test_tosympy(self):
import sympy
sp_x, sp_y = sympy.symbols('x y')
-        self.assertEqual(self.square.tosympy(),
+        self.assertEqual(
+            self.square.tosympy(),
sympy.And(-sp_x + 1 >= 0, -sp_y + 1 >= 0, sp_x >= 0, sp_y >= 0))

index 72569e4..f3f62c1 100755 (executable)
--- a/setup.py
+++ b/setup.py
# You should have received a copy of the GNU General Public License
# along with LinPy.  If not, see <http://www.gnu.org/licenses/>.

-from distutils.core import setup, Extension
+from distutils.core import Extension, setup

with open('linpy/_version.py') as file:
+    __version__ = None