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)
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.
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)
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.
+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
+-------------
+
+
--- /dev/null
+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
+-------------
+
+
.. 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)
.. 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.
-
Geometry Module
===============
.. 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)
.. 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.
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:
:maxdepth: 2
install.rst
- example.rst
+ examples.rst
modules.rst
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/
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/
Linear Expression Module
========================
-
This class implements linear expressions.
.. py:method:: coefficient(self, symbol)
.. 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
.. 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*.
.. 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.
"""
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)
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():
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)
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')
return result
def __eq__(self, other):
+ """
+ Compares two Vectors for equality.
+ """
return isinstance(other, Vector) and \
self._coordinates == other._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)
__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):
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)
--- /dev/null
+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