From 98936866ae400d45b7b74f7ba0d04c66ace0424f Mon Sep 17 00:00:00 2001 From: Danielle Bolan Date: Tue, 22 Jul 2014 16:49:25 +0200 Subject: [PATCH 1/1] Changes that need to be merged --- doc/domain.rst | 121 +++++++++---------- doc/domain.rst~ | 121 +++++++++---------- doc/examples.rst | 22 ++++ doc/examples.rst~ | 22 ++++ doc/geometry.rst | 55 +++++++-- doc/geometry.rst~ | 57 +++++++-- doc/index.rst | 2 +- doc/index.rst~ | 2 +- doc/install.rst | 8 +- doc/install.rst~ | 5 + doc/linexpr.rst | 1 - doc/linexpr.rst~ | 11 +- doc/polyhedra.rst | 57 +++++---- doc/polyhedra.rst~ | 47 ++++---- pypol/geometry.py | 40 ++++++- pypol/geometry.py~ | 284 +++++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 641 insertions(+), 214 deletions(-) create mode 100644 doc/examples.rst~ create mode 100644 pypol/geometry.py~ diff --git a/doc/domain.rst b/doc/domain.rst index 217acba..91b96f8 100644 --- a/doc/domain.rst +++ b/doc/domain.rst @@ -9,132 +9,127 @@ Domains Module Domain Properties ----------------- - .. py:method:: symbols(self) + .. py:method:: symbols - Returns a list of the symbols used in a set. + Returns a tuple of the symbols that exsist in a domain. - .. py:method:: dimension(self) + .. py:method:: dimension - Returns the number of variables in a set. + Returns the number of variables that exist in a domain. - .. py:method:: disjoint(self) + .. py:method:: disjoint - Returns a set as disjoint. + Returns a domain as disjoint. - .. py:method:: num_parameters(self) + .. py:method:: num_parameters - Returns the total number of parameters, input, output or set dimensions. + Returns the total number of parameters, input, output or dimensions in a domain. .. py:method:: involves_dims(self, dims) - Returns true if set depends on given dimensions. + Returns ``True`` if a domain depends on the given dimensions. Unary Properties ---------------- .. py:method:: isempty(self) - Return true is set is an Empty set. + Return ``True`` is a domain is empty. .. py:method:: isuniverse(self) - Return true if set is the Universe set. + Return ``True`` if a domain is the Universe set. .. py:method:: isbounded(self) - Return true if set is bounded + Return ``True`` if a domain is bounded .. py:method:: disjoint(self) - Returns this set as a disjoint set. + Returns a domain as disjoint. Binary Properties ----------------- .. py:method:: isdisjoint(self, other) - Return true if the intersection of two sets results in an Empty set. + Return ``True`` if the intersection of *self* and *other* results in an empty set. .. py:method:: issubset(self, other) - Returns true if one set contains the other set. + Test whether every element in a domain is in *other*. .. py:method:: __eq__(self, other) - - Return true if self == other. + self == other + + Test whether a domain is equal to *other*. .. py:method:: __lt__(self, other) - - Return true if self < other. + self < other + + Test whether a domain is a strict subset of *other*. .. py:method:: __le__(self, other) - - Return true if self <= other. + self <= other + + Test whether every element in a domain is in *other*. .. py:method:: __gt__(self, other) - - Return true if self > other. + self > other + + Test whether a domain is a strict superset of *other*. .. py:method:: __ge__(self, other) + self >= other - Return true if self >= other. + Test whether every element in *other* is in a domain. -Unary Operations ----------------- + The following methods implement unary operations on a domain. .. py:method:: complement(self) + ¬self - Return the complement of a set. + Return the complement of a domain. .. py:method:: simplify(self) - Removes redundant constraints from a set. + Return a new domain without any redundant constraints. .. py:method:: project(self, dims) - Return a new set with the given dimensions removed. + Return a new domain with the given dimensions removed. .. py:method:: aspolyhedron(self) - Return polyhedral hull of a set. + Return polyhedral hull of a domain. - .. py:method:: asdomain(self) - - Return - .. py:method:: sample(self) - Return a single sample subset of a set. + Return a single sample subset of a domain. -Binary Operations ------------------ + The following methods implement binary operations on two domains. - .. py:method:: intersection(self) + .. py:method:: intersection(self, other) + self | other - Return the intersection of two sets as a new set. + Return a new domain with the elements that are common between *self* and *other*. - .. py:method:: union(self) + .. py:method:: union(self, other) + self & other - Return the union of two sets as a new set. - - .. py:method:: __and__(self, other) - - Return the union of two sets as a new set. - - .. py:method:: __or__(self, other) + Return a new domain with all the elements from *self* and *other*. + + .. py:method:: difference(self, other) + self - other - Return the intersection of two sets as a new set. - + Return a new domain with the elements in a domain that are not in *other* . + .. py:method:: __add__(self, other) + self + other - Return the sum of two sets. - - .. py:method:: difference(self, other) - - Return the difference of two sets. - -Lexiographic Operations ------------------------ + Return the sum of two domains. + + The following methods use lexicographical ordering to find the maximum or minimum element in a domain. .. py:method:: lexmin(self) @@ -144,24 +139,24 @@ Lexiographic Operations Return a new set containing the lexicographic maximum of the elements in the set. -Plot Properties ---------------- + + A 2D or 3D domain can be plotted using the :meth:`plot` function. The points, verticies, and faces of a domain can be inspected using the following functions. .. py:method:: points(self) - Return a list of the points contained in a set. + Return a list of the points contained in a domain. .. py:method:: vertices(self) - Return a list of the verticies of this set. + Return a list of the verticies of a domain. .. py:method:: faces(self) - Return a list of the vertices for each face of a set. + Return a list of the vertices for each face of a domain. .. py:method:: plot(self, plot=None, **kwargs) - Return a plot of the given set. + Return a plot of the given domain. diff --git a/doc/domain.rst~ b/doc/domain.rst~ index 217acba..91b96f8 100644 --- a/doc/domain.rst~ +++ b/doc/domain.rst~ @@ -9,132 +9,127 @@ Domains Module Domain Properties ----------------- - .. py:method:: symbols(self) + .. py:method:: symbols - Returns a list of the symbols used in a set. + Returns a tuple of the symbols that exsist in a domain. - .. py:method:: dimension(self) + .. py:method:: dimension - Returns the number of variables in a set. + Returns the number of variables that exist in a domain. - .. py:method:: disjoint(self) + .. py:method:: disjoint - Returns a set as disjoint. + Returns a domain as disjoint. - .. py:method:: num_parameters(self) + .. py:method:: num_parameters - Returns the total number of parameters, input, output or set dimensions. + Returns the total number of parameters, input, output or dimensions in a domain. .. py:method:: involves_dims(self, dims) - Returns true if set depends on given dimensions. + Returns ``True`` if a domain depends on the given dimensions. Unary Properties ---------------- .. py:method:: isempty(self) - Return true is set is an Empty set. + Return ``True`` is a domain is empty. .. py:method:: isuniverse(self) - Return true if set is the Universe set. + Return ``True`` if a domain is the Universe set. .. py:method:: isbounded(self) - Return true if set is bounded + Return ``True`` if a domain is bounded .. py:method:: disjoint(self) - Returns this set as a disjoint set. + Returns a domain as disjoint. Binary Properties ----------------- .. py:method:: isdisjoint(self, other) - Return true if the intersection of two sets results in an Empty set. + Return ``True`` if the intersection of *self* and *other* results in an empty set. .. py:method:: issubset(self, other) - Returns true if one set contains the other set. + Test whether every element in a domain is in *other*. .. py:method:: __eq__(self, other) - - Return true if self == other. + self == other + + Test whether a domain is equal to *other*. .. py:method:: __lt__(self, other) - - Return true if self < other. + self < other + + Test whether a domain is a strict subset of *other*. .. py:method:: __le__(self, other) - - Return true if self <= other. + self <= other + + Test whether every element in a domain is in *other*. .. py:method:: __gt__(self, other) - - Return true if self > other. + self > other + + Test whether a domain is a strict superset of *other*. .. py:method:: __ge__(self, other) + self >= other - Return true if self >= other. + Test whether every element in *other* is in a domain. -Unary Operations ----------------- + The following methods implement unary operations on a domain. .. py:method:: complement(self) + ¬self - Return the complement of a set. + Return the complement of a domain. .. py:method:: simplify(self) - Removes redundant constraints from a set. + Return a new domain without any redundant constraints. .. py:method:: project(self, dims) - Return a new set with the given dimensions removed. + Return a new domain with the given dimensions removed. .. py:method:: aspolyhedron(self) - Return polyhedral hull of a set. + Return polyhedral hull of a domain. - .. py:method:: asdomain(self) - - Return - .. py:method:: sample(self) - Return a single sample subset of a set. + Return a single sample subset of a domain. -Binary Operations ------------------ + The following methods implement binary operations on two domains. - .. py:method:: intersection(self) + .. py:method:: intersection(self, other) + self | other - Return the intersection of two sets as a new set. + Return a new domain with the elements that are common between *self* and *other*. - .. py:method:: union(self) + .. py:method:: union(self, other) + self & other - Return the union of two sets as a new set. - - .. py:method:: __and__(self, other) - - Return the union of two sets as a new set. - - .. py:method:: __or__(self, other) + Return a new domain with all the elements from *self* and *other*. + + .. py:method:: difference(self, other) + self - other - Return the intersection of two sets as a new set. - + Return a new domain with the elements in a domain that are not in *other* . + .. py:method:: __add__(self, other) + self + other - Return the sum of two sets. - - .. py:method:: difference(self, other) - - Return the difference of two sets. - -Lexiographic Operations ------------------------ + Return the sum of two domains. + + The following methods use lexicographical ordering to find the maximum or minimum element in a domain. .. py:method:: lexmin(self) @@ -144,24 +139,24 @@ Lexiographic Operations Return a new set containing the lexicographic maximum of the elements in the set. -Plot Properties ---------------- + + A 2D or 3D domain can be plotted using the :meth:`plot` function. The points, verticies, and faces of a domain can be inspected using the following functions. .. py:method:: points(self) - Return a list of the points contained in a set. + Return a list of the points contained in a domain. .. py:method:: vertices(self) - Return a list of the verticies of this set. + Return a list of the verticies of a domain. .. py:method:: faces(self) - Return a list of the vertices for each face of a set. + Return a list of the vertices for each face of a domain. .. py:method:: plot(self, plot=None, **kwargs) - Return a plot of the given set. + Return a plot of the given domain. diff --git a/doc/examples.rst b/doc/examples.rst index e69de29..793ecbe 100644 --- a/doc/examples.rst +++ b/doc/examples.rst @@ -0,0 +1,22 @@ +Pypol Examples +============== + +Creating a Square +----------------- + To create any polyhedron, first define the symbols used. Then use the polyhedron functions to define the constraints for the polyhedron. This example creates a square:: + + >>> x, y = symbols('x y') + >>> # define the constraints of the polyhedron + >>> square = Le(0, x) & Le(x, 2) & Le(0, y) & Le(y, 2) + >>> print(square) + >>> And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0)) + + Several unary operations can be performed on a polyhedron. For example: :: + + >>> ¬square + + +Plot Examples +------------- + + diff --git a/doc/examples.rst~ b/doc/examples.rst~ new file mode 100644 index 0000000..18a2e83 --- /dev/null +++ b/doc/examples.rst~ @@ -0,0 +1,22 @@ +Pypol Examples +============== + +Creating a Square +----------------- + To create any polyhedron, first define the symbols used. Then use the polyhedron functions to define the constraints for the polyhedron. This example creates a square:: + + >>> x, y = symbols('x y') + >>> # define the constraints of the polyhedron + >>> square = Le(0, x) & Le(x, 2) & Le(0, y) & Le(y, 2) + >>> print(square) + >>> And(Ge(x, 0), Ge(-x + 2, 0), Ge(y, 0), Ge(-y + 2, 0)) + + Several unary operations can be performed on a polyhedron. For example: :: + + >>> square2 = + + +Plot Examples +------------- + + diff --git a/doc/geometry.rst b/doc/geometry.rst index 224fb3a..0058ee9 100644 --- a/doc/geometry.rst +++ b/doc/geometry.rst @@ -9,18 +9,60 @@ This class represents points in space. .. py:method:: isorigin(self) - Return true is given point is the origin. + Return ``True`` if a point is the origin. - .. py:method:: + .. py:method:: __eq__(self, other) + + Compares two Points for equality. + + .. py:method:: __add__(self, other) + + Adds a Point to a Vector and returns the result as a Point. + + .. py:method:: __sub__(self, other) + + Returns the difference between two Points as a Vector. + .. py:method:: aspolyhedon(self) + + Returns a Point as a polyhedron. + + .. py:class:: Vector -This class represents displacements in space. +This class represents displacements in space. + .. py:method:: __eq__(self, other) + + Compares two Vectors for equality. + + .. py:method:: __add__(self, other) + + Adds either a Point or Vector to a Vector. The resulting sum is returned as the same structure *other* is. + + .. py:method:: __sub__(self, other) + + Subtract a Point or Vector from a Vector. The resulting difference is returned in the same form as *other*. + + .. py:method:: __mul__(self, other) + + Multiples a Vector by a scalar value and returns the result as a Vector. + + .. py:method:: __neg__(self) + + Negates a Vector. + + .. py:method:: norm(self) + + Normalizes a Vector. + + .. py:method:: isnull(self) + + Tests whether a Vector is null. + .. py:method:: angle(self, other) - Retrieve the angle required to rotate the vector into the vector passed - in argument. The result is an angle in radians, ranging between -pi and + Retrieve the angle required to rotate the vector into the vector passed in argument. The result is an angle in radians, ranging between -pi and pi. .. py:method:: cross(self, other) @@ -33,6 +75,5 @@ This class represents displacements in space. .. py:method:: __trudiv__(self, other) - Divide the vector by the specified scalar and returns the result as a - vector. + Divide the vector by the specified scalar and returns the result as a vector. diff --git a/doc/geometry.rst~ b/doc/geometry.rst~ index d96cd6f..1a36921 100644 --- a/doc/geometry.rst~ +++ b/doc/geometry.rst~ @@ -1,4 +1,3 @@ - Geometry Module =============== @@ -10,18 +9,61 @@ This class represents points in space. .. py:method:: isorigin(self) - Return true is given point is the origin. + Return ``True`` if a point is the origin. + + .. py:method:: __eq__(self, other) + + Compares two Points for equality. - .. py:method:: + .. py:method:: __add__(self, other) + + Adds a Point to a Vector and returns the result as a Point. + + .. py:method:: __sub__(self, other) + + Returns the difference between two Points as a Vector. + .. py:method:: aspolyhedon(self) + + Returns a Point as a polyhedron. + + .. py:class:: Vector -This class represents displacements in space. +This class represents displacements in space. + .. py:method:: __eq__(self, other) + + Compares two Vectors for equality. + + .. py:method:: __add__(self, other) + + Adds either a Point or Vector to a Vector. The resulting sum is returned as the same structure *other* is. + + .. py:method:: __sub__(self, other) + + Subtract a Point or Vector from a Vector. The resulting difference is returned in the same form as *other*. + + .. py:method:: __mul__(self, other) + + Multiples a Vector by a scalar value and returns the result as a Vector. + + .. py:method:: __neg__(self) + + Negates a Vector. + + .. py:method:: norm(self) + + Normalizes a Vector. + + + .. py:method:: isnull(self) + + Tests whether a Vector is null. + .. py:method:: angle(self, other) - Retrieve the angle required to rotate the vector into the vector passed - in argument. The result is an angle in radians, ranging between -pi and + Retrieve the angle required to rotate the vector into the vector passed in argument. The result is an angle in radians, ranging between -pi and pi. .. py:method:: cross(self, other) @@ -34,6 +76,5 @@ This class represents displacements in space. .. py:method:: __trudiv__(self, other) - Divide the vector by the specified scalar and returns the result as a - vector. + Divide the vector by the specified scalar and returns the result as a vector. diff --git a/doc/index.rst b/doc/index.rst index 12f6f4e..b75e85e 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -9,7 +9,7 @@ Welcome to pypol's documentation! Pypol is a Python library for symbolic mathematics. If you are new to Pypol, start with the Tutorial. -This is the central page for all of SymPy's documentation. +This is the central page for all of Pypol's documentation. Contents: diff --git a/doc/index.rst~ b/doc/index.rst~ index cbe9460..12f6f4e 100644 --- a/doc/index.rst~ +++ b/doc/index.rst~ @@ -18,7 +18,7 @@ Contents: :maxdepth: 2 install.rst - example.rst + examples.rst modules.rst diff --git a/doc/install.rst b/doc/install.rst index 35cd056..545e773 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -6,14 +6,18 @@ Installation Dependencies ============ -Users will first need to install Integer Set Library (isl). The source files of isl are available as a tarball or a git repository. Both -are available `here`_ . +Pypol requires at least Python3.4. Users will first need to install Integer Set Library (isl). The source files of isl are available as a tarball or a git repository. Both are available `here`_ . + Source ====== +add link to pypi pypol documentation. + Git === +add link to git repo + .. _here: http://freshmeat.net/projects/isl/ diff --git a/doc/install.rst~ b/doc/install.rst~ index 8e0224a..35cd056 100644 --- a/doc/install.rst~ +++ b/doc/install.rst~ @@ -9,6 +9,11 @@ Dependencies Users will first need to install Integer Set Library (isl). The source files of isl are available as a tarball or a git repository. Both are available `here`_ . +Source +====== + +Git +=== .. _here: http://freshmeat.net/projects/isl/ diff --git a/doc/linexpr.rst b/doc/linexpr.rst index 3771d5f..4101252 100644 --- a/doc/linexpr.rst +++ b/doc/linexpr.rst @@ -1,7 +1,6 @@ Linear Expression Module ======================== - This class implements linear expressions. .. py:method:: coefficient(self, symbol) diff --git a/doc/linexpr.rst~ b/doc/linexpr.rst~ index 6a017bf..3771d5f 100644 --- a/doc/linexpr.rst~ +++ b/doc/linexpr.rst~ @@ -42,13 +42,4 @@ This class implements linear expressions. .. py:class:: Dummy(Symbol) -This class returns a dummy symbol to ensure that each no variables are repeated in an expression - - - - - - - - - +This class returns a dummy symbol to ensure that each no variables are repeated in an expression diff --git a/doc/polyhedra.rst b/doc/polyhedra.rst index fd09b90..779be46 100644 --- a/doc/polyhedra.rst +++ b/doc/polyhedra.rst @@ -3,59 +3,56 @@ Polyhedra Module .. py:class:: Polyhedron -Polyhedra Properties --------------------- + Polyhedron class allows users to build and inspect polyherons. The following methods provide the properties of a polyhedron. .. py:method:: equalities(self) - Return a list of the equalities in a set. + Return a list of the equalities in a polyhedron. .. py:method:: inequalities(self) - Return a list of the inequalities in a set. + Return a list of the inequalities in a polyhedron. .. py:method:: constraints(self) - Return ta list of the constraints of a set. + Return ta list of the constraints of a polyhedron. -Unary Operations ----------------- + The following unary operations can be used to inspect a polyhedron. + .. py:method:: disjoint(self) - Returns this set as a disjoint set. + Returns a polyhedron as a disjoint. .. py:method:: isuniverse(self) - Return true if this set is the Universe set. - - .. py:method:: aspolyhedron(self) - - Return polyhedral hull of this set. + Return ``True`` if a polyhedron is the Universe set. .. py:method:: subs(self, symbol, expression=None) - Subsitute expression into given set and returns the result. - - .. py:method:: Lt(left, right) - - Assert first set is less than the second set. - - .. py:method:: Le(left, right) - - Assert first set is less than or equal to the second set. + Subsitutes an expression into a polyhedron and returns the result. + +To create a polyhedron, the user must use the folloing functions to define the equalities and inequalities which are the contraints of a polyhedron. + +.. py:function:: Eq(left, right) + + Create a constraint by setting *left* equal to *right*. - .. py:method:: Eq(left, right) +.. py:function:: Ne(left, right) + + Create a constraint by setting *left* not equal to *right*. + +.. py:function:: Lt(left, right) - Assert first set is equal to the second set. + Create a constraint by setting *left* less than *right*. - .. py:method:: Ne(left, right) +.. py:function:: Le(left, right) - Assert first set is not equal to the second set. + Create a constraint by setting *left* less than or equal to *right*. - .. py:method:: Gt(left, right) +.. py:function:: Gt(left, right) - Assert first set is greater than the second set. + Create a constraint by setting *left* greater than *right*. - .. py:method:: Ge(left, right) +.. py:function:: Ge(left, right) - Assert first set is greater than or equal to the second set. + Create a constraint by setting *left* greater than or equal to *right*. diff --git a/doc/polyhedra.rst~ b/doc/polyhedra.rst~ index fd09b90..67cb251 100644 --- a/doc/polyhedra.rst~ +++ b/doc/polyhedra.rst~ @@ -3,59 +3,56 @@ Polyhedra Module .. py:class:: Polyhedron -Polyhedra Properties --------------------- + Polyhedron class allows users to build and inspect polyherons. The following methods provide the properties of a polyhedron. .. py:method:: equalities(self) - Return a list of the equalities in a set. + Return a list of the equalities in a polyhedron. .. py:method:: inequalities(self) - Return a list of the inequalities in a set. + Return a list of the inequalities in a polyhedron. .. py:method:: constraints(self) - Return ta list of the constraints of a set. + Return ta list of the constraints of a polyhedron. -Unary Operations ----------------- + The following unary operations can be used to inspect a polyhedron. + .. py:method:: disjoint(self) - Returns this set as a disjoint set. + Returns a polyhedron as a disjoint. .. py:method:: isuniverse(self) - Return true if this set is the Universe set. - - .. py:method:: aspolyhedron(self) - - Return polyhedral hull of this set. + Return ``True`` if a polyhedron is the Universe set. .. py:method:: subs(self, symbol, expression=None) - Subsitute expression into given set and returns the result. + Subsitutes an expression into a polyhedron and returns the result. + +To create a polyhedron, the user must use the folloing functions to define the equalities and inequalities which are the contraints of a polyhedron. - .. py:method:: Lt(left, right) +.. py:function:: Lt(left, right) - Assert first set is less than the second set. + Assert first set is less than the second set. - .. py:method:: Le(left, right) +.. py:function:: Le(left, right) - Assert first set is less than or equal to the second set. + Assert first set is less than or equal to the second set. - .. py:method:: Eq(left, right) +.. py:function:: Eq(left, right) - Assert first set is equal to the second set. + Assert first set is equal to the second set. - .. py:method:: Ne(left, right) +.. py:function:: Ne(left, right) - Assert first set is not equal to the second set. + Assert first set is not equal to the second set. - .. py:method:: Gt(left, right) +.. py:function:: Gt(left, right) - Assert first set is greater than the second set. + Assert first set is greater than the second set. - .. py:method:: Ge(left, right) +.. py:function:: Ge(left, right) Assert first set is greater than or equal to the second set. diff --git a/pypol/geometry.py b/pypol/geometry.py index 1dc50eb..520a1ec 100644 --- a/pypol/geometry.py +++ b/pypol/geometry.py @@ -107,18 +107,27 @@ class Point(Coordinates, GeometricObject): """ def isorigin(self): + """ + Return True if a Point is the origin. + """ return not bool(self) def __hash__(self): return super().__hash__() def __add__(self, other): + """ + Adds a Point to a Vector and returns the result as a Point. + """ if not isinstance(other, Vector): return NotImplemented coordinates = self._map2(other, operator.add) return Point(coordinates) def __sub__(self, other): + """ + Returns the difference between two Points as a Vector. + """ coordinates = [] if isinstance(other, Point): coordinates = self._map2(other, operator.sub) @@ -130,10 +139,16 @@ class Point(Coordinates, GeometricObject): return NotImplemented def __eq__(self, other): + """ + Compares two Points for equality. + """ return isinstance(other, Point) and \ self._coordinates == other._coordinates def aspolyhedron(self): + """ + Return a Point as a polyhedron. + """ from .polyhedra import Polyhedron equalities = [] for symbol, coordinate in self.coordinates(): @@ -158,12 +173,18 @@ class Vector(Coordinates): return super().__new__(cls, coordinates) def isnull(self): + """ + Returns true if a Vector is null. + """ return not bool(self) def __hash__(self): return super().__hash__() def __add__(self, other): + """ + Adds either a Point or Vector to a Vector. + """ if isinstance(other, (Point, Vector)): coordinates = self._map2(other, operator.add) return other.__class__(coordinates) @@ -171,9 +192,7 @@ class Vector(Coordinates): def angle(self, other): """ - Retrieve the angle required to rotate the vector into the vector passed - in argument. The result is an angle in radians, ranging between -pi and - pi. + Retrieve the angle required to rotate the vector into the vector passed in argument. The result is an angle in radians, ranging between -pi and pi. """ if not isinstance(other, Vector): raise TypeError('argument must be a Vector instance') @@ -219,6 +238,9 @@ class Vector(Coordinates): return result def __eq__(self, other): + """ + Compares two Vectors for equality. + """ return isinstance(other, Vector) and \ self._coordinates == other._coordinates @@ -226,6 +248,9 @@ class Vector(Coordinates): return hash(tuple(self.coordinates())) def __mul__(self, other): + """ + Multiplies a Vector by a scalar value. + """ if not isinstance(other, numbers.Real): return NotImplemented coordinates = self._map(lambda coordinate: other * coordinate) @@ -234,10 +259,16 @@ class Vector(Coordinates): __rmul__ = __mul__ def __neg__(self): + """ + Returns the negated form of a Vector. + """ coordinates = self._map(operator.neg) return Vector(coordinates) def norm(self): + """ + Normalizes a Vector. + """ return math.sqrt(self.norm2()) def norm2(self): @@ -250,6 +281,9 @@ class Vector(Coordinates): return self / self.norm() def __sub__(self, other): + """ + Subtract a Point or Vector from a Vector. + """ if isinstance(other, (Point, Vector)): coordinates = self._map2(other, operator.sub) return other.__class__(coordinates) diff --git a/pypol/geometry.py~ b/pypol/geometry.py~ new file mode 100644 index 0000000..8473c87 --- /dev/null +++ b/pypol/geometry.py~ @@ -0,0 +1,284 @@ +import math +import numbers +import operator + +from abc import ABC, abstractproperty, abstractmethod +from collections import OrderedDict, Mapping + +from .linexprs import Symbol + + +__all__ = [ + 'GeometricObject', + 'Point', + 'Vector', +] + + +class GeometricObject(ABC): + + @abstractproperty + def symbols(self): + pass + + @property + def dimension(self): + return len(self.symbols) + + @abstractmethod + def aspolyhedron(self): + pass + + def asdomain(self): + return self.aspolyhedron() + + +class Coordinates: + + __slots__ = ( + '_coordinates', + ) + + def __new__(cls, coordinates): + if isinstance(coordinates, Mapping): + coordinates = coordinates.items() + self = object().__new__(cls) + self._coordinates = OrderedDict() + for symbol, coordinate in sorted(coordinates, + key=lambda item: item[0].sortkey()): + if not isinstance(symbol, Symbol): + raise TypeError('symbols must be Symbol instances') + if not isinstance(coordinate, numbers.Real): + raise TypeError('coordinates must be real numbers') + self._coordinates[symbol] = coordinate + return self + + @property + def symbols(self): + return tuple(self._coordinates) + + @property + def dimension(self): + return len(self.symbols) + + def coordinates(self): + yield from self._coordinates.items() + + def coordinate(self, symbol): + if not isinstance(symbol, Symbol): + raise TypeError('symbol must be a Symbol instance') + return self._coordinates[symbol] + + __getitem__ = coordinate + + def values(self): + yield from self._coordinates.values() + + def __bool__(self): + return any(self._coordinates.values()) + + def __hash__(self): + return hash(tuple(self.coordinates())) + + def __repr__(self): + string = ', '.join(['{!r}: {!r}'.format(symbol, coordinate) + for symbol, coordinate in self.coordinates()]) + return '{}({{{}}})'.format(self.__class__.__name__, string) + + def _map(self, func): + for symbol, coordinate in self.coordinates(): + yield symbol, func(coordinate) + + def _iter2(self, other): + if self.symbols != other.symbols: + raise ValueError('arguments must belong to the same space') + coordinates1 = self._coordinates.values() + coordinates2 = other._coordinates.values() + yield from zip(self.symbols, coordinates1, coordinates2) + + def _map2(self, other, func): + for symbol, coordinate1, coordinate2 in self._iter2(other): + yield symbol, func(coordinate1, coordinate2) + + +class Point(Coordinates, GeometricObject): + """ + This class represents points in space. + """ + + def isorigin(self): + """ + Return True if a Point is the origin. + """ + return not bool(self) + + def __hash__(self): + return super().__hash__() + + def __add__(self, other): + if not isinstance(other, Vector): + return NotImplemented + coordinates = self._map2(other, operator.add) + return Point(coordinates) + + def __sub__(self, other): + coordinates = [] + if isinstance(other, Point): + coordinates = self._map2(other, operator.sub) + return Vector(coordinates) + elif isinstance(other, Vector): + coordinates = self._map2(other, operator.sub) + return Point(coordinates) + else: + return NotImplemented + + def __eq__(self, other): + """ + Compares two Points for equality. + """ + return isinstance(other, Point) and \ + self._coordinates == other._coordinates + + def aspolyhedron(self): + """ + Return a Point as a polyhedron. + """ + from .polyhedra import Polyhedron + equalities = [] + for symbol, coordinate in self.coordinates(): + equalities.append(symbol - coordinate) + return Polyhedron(equalities) + + +class Vector(Coordinates): + """ + This class represents displacements in space. + """ + + def __new__(cls, initial, terminal=None): + if not isinstance(initial, Point): + initial = Point(initial) + if terminal is None: + coordinates = initial._coordinates + else: + if not isinstance(terminal, Point): + terminal = Point(terminal) + coordinates = terminal._map2(initial, operator.sub) + return super().__new__(cls, coordinates) + + def isnull(self): + """ + Returns true if a Vector is null. + """ + return not bool(self) + + def __hash__(self): + return super().__hash__() + + def __add__(self, other): + """ + Adds either a Point or Vector to a Vector. + """ + if isinstance(other, (Point, Vector)): + coordinates = self._map2(other, operator.add) + return other.__class__(coordinates) + return NotImplemented + + def angle(self, other): + """ + Retrieve the angle required to rotate the vector into the vector passed in argument. The result is an angle in radians, ranging between -pi and pi. + """ + if not isinstance(other, Vector): + raise TypeError('argument must be a Vector instance') + cosinus = self.dot(other) / (self.norm()*other.norm()) + return math.acos(cosinus) + + def cross(self, other): + """ + Calculate the cross product of two Vector3D structures. + """ + if not isinstance(other, Vector): + raise TypeError('other must be a Vector instance') + if self.dimension != 3 or other.dimension != 3: + raise ValueError('arguments must be three-dimensional vectors') + if self.symbols != other.symbols: + raise ValueError('arguments must belong to the same space') + x, y, z = self.symbols + coordinates = [] + coordinates.append((x, self[y]*other[z] - self[z]*other[y])) + coordinates.append((y, self[z]*other[x] - self[x]*other[z])) + coordinates.append((z, self[x]*other[y] - self[y]*other[x])) + return Vector(coordinates) + + def __truediv__(self, other): + """ + Divide the vector by the specified scalar and returns the result as a + vector. + """ + if not isinstance(other, numbers.Real): + return NotImplemented + coordinates = self._map(lambda coordinate: coordinate / other) + return Vector(coordinates) + + def dot(self, other): + """ + Calculate the dot product of two vectors. + """ + if not isinstance(other, Vector): + raise TypeError('argument must be a Vector instance') + result = 0 + for symbol, coordinate1, coordinate2 in self._iter2(other): + result += coordinate1 * coordinate2 + return result + + def __eq__(self, other): + """ + Compares two Vectors for equality. + """ + return isinstance(other, Vector) and \ + self._coordinates == other._coordinates + + def __hash__(self): + return hash(tuple(self.coordinates())) + + def __mul__(self, other): + """ + Multiplies a Vector by a scalar value. + """ + if not isinstance(other, numbers.Real): + return NotImplemented + coordinates = self._map(lambda coordinate: other * coordinate) + return Vector(coordinates) + + __rmul__ = __mul__ + + def __neg__(self): + """ + Returns the negated form of a Vector. + """ + coordinates = self._map(operator.neg) + return Vector(coordinates) + + def norm(self): + """ + Normalizes a Vector. + """ + return math.sqrt(self.norm2()) + + def norm2(self): + result = 0 + for coordinate in self._coordinates.values(): + result += coordinate ** 2 + return result + + def asunit(self): + return self / self.norm() + + def __sub__(self, other): + """ + Subtract a Point or Vector from a Vector. + """ + if isinstance(other, (Point, Vector)): + coordinates = self._map2(other, operator.sub) + return other.__class__(coordinates) + return NotImplemented -- 2.20.1