Example #1
0
    def intersection(self, other):
        r"""
        The intersection of ``self`` with ``other``.

        INPUT:

        - ``other`` -- a hyperplane, a polyhedron, or something that
          defines a polyhedron

        OUTPUT:

        A polyhedron.

        EXAMPLES::

            sage: H.<x,y,z> = HyperplaneArrangements(QQ)
            sage: h = x + y + z - 1
            sage: h.intersection(x - y)
            A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line
            sage: h.intersection(polytopes.cube())
            A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices
        """
        from sage.geometry.polyhedron.base import is_Polyhedron
        from sage.geometry.polyhedron.constructor import Polyhedron
        if not is_Polyhedron(other):
            try:
                other = other.polyhedron()
            except AttributeError:
                other = Polyhedron(other)
        return self.polyhedron().intersection(other)
Example #2
0
    def intersection(self, other):
        r"""
        The intersection of ``self`` with ``other``.

        INPUT:

        - ``other`` -- a hyperplane, a polyhedron, or something that
          defines a polyhedron

        OUTPUT:

        A polyhedron.

        EXAMPLES::

            sage: H.<x,y,z> = HyperplaneArrangements(QQ)
            sage: h = x + y + z - 1
            sage: h.intersection(x - y)
            A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line
            sage: h.intersection(polytopes.n_cube(3))
            A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices
        """
        from sage.geometry.polyhedron.base import is_Polyhedron
        from sage.geometry.polyhedron.constructor import Polyhedron
        if not is_Polyhedron(other):
            try:
                other = other.polyhedron()
            except AttributeError:
                other = Polyhedron(other)
        return self.polyhedron().intersection(other)
Example #3
0
    def _element_constructor_(self, *args, **kwds):
        """
        The element (polyhedron) constructor.

        INPUT:

        - ``Vrep`` -- a list `[vertices, rays, lines]`` or ``None``.

        - ``Hrep`` -- a list `[ieqs, eqns]`` or ``None``.

        - ``convert`` -- boolean keyword argument (default:
          ``True``). Whether to convert the cooordinates into the base
          ring.

        - ``**kwds`` -- optional remaining keywords that are passed to the
          polyhedron constructor.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.parent import Polyhedra
            sage: P = Polyhedra(QQ, 3)
            sage: P._element_constructor_([[(0,0,0),(1,0,0),(0,1,0),(0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P([[(0,0,0),(1,0,0),(0,1,0),(0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P(0)
            A 0-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex
        """
        nargs = len(args)
        convert = kwds.pop('convert', True)
        if nargs == 2:
            Vrep, Hrep = args

            def convert_base_ring(lstlst):
                return [[self.base_ring()(x) for x in lst] for lst in lstlst]

            if convert and Hrep:
                Hrep = [convert_base_ring(_) for _ in Hrep]
            if convert and Vrep:
                Vrep = [convert_base_ring(_) for _ in Vrep]
            return self.element_class(self, Vrep, Hrep, **kwds)
        if nargs == 1 and is_Polyhedron(args[0]):
            polyhedron = args[0]
            Hrep = [
                polyhedron.inequality_generator(),
                polyhedron.equation_generator()
            ]
            return self.element_class(self, None, Hrep, **kwds)
        if nargs == 1 and args[0] == 0:
            return self.zero()
        raise ValueError('Cannot convert to polyhedron object.')
Example #4
0
    def _element_constructor_(self, *args, **kwds):
        """
        The element (polyhedron) constructor.

        INPUT:

        - ``Vrep`` -- a list `[vertices, rays, lines]`` or ``None``.

        - ``Hrep`` -- a list `[ieqs, eqns]`` or ``None``.

        - ``convert`` -- boolean keyword argument (default:
          ``True``). Whether to convert the cooordinates into the base
          ring.

        - ``**kwds`` -- optional remaining keywords that are passed to the
          polyhedron constructor.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.parent import Polyhedra
            sage: P = Polyhedra(QQ, 3)
            sage: P._element_constructor_([[(0,0,0),(1,0,0),(0,1,0),(0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P([[(0,0,0),(1,0,0),(0,1,0),(0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P(0)
            A 0-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex
        """
        nargs = len(args)
        convert = kwds.pop("convert", True)
        if nargs == 2:
            Vrep, Hrep = args

            def convert_base_ring(lstlst):
                return [[self.base_ring()(x) for x in lst] for lst in lstlst]

            if convert and Hrep:
                Hrep = map(convert_base_ring, Hrep)
            if convert and Vrep:
                Vrep = map(convert_base_ring, Vrep)
            return self.element_class(self, Vrep, Hrep, **kwds)
        if nargs == 1 and is_Polyhedron(args[0]):
            polyhedron = args[0]
            Hrep = [polyhedron.inequality_generator(), polyhedron.equation_generator()]
            return self.element_class(self, None, Hrep, **kwds)
        if nargs == 1 and args[0] == 0:
            return self.zero_element()
        raise ValueError("Cannot convert to polyhedron object.")
    def _element_constructor_(self,
                              arg,
                              sort_slopes=True,
                              last_slope=Infinity):
        """
        INPUT:

        - ``arg`` -- an argument describing the Newton polygon

        - ``sort_slopes`` -- boolean (default: ``True``). Specifying
          whether slopes must be first sorted

        - ``last_slope`` -- rational or infinity (default:
          ``Infinity``). The last slope of the Newton polygon

        The first argument ``arg`` can be either:

        - a polyhedron in `\QQ^2`

        - the element ``0`` (corresponding to the empty Newton polygon)

        - the element ``1`` (corresponding to the Newton polygon of the
          constant polynomial equal to 1)

        - a list/tuple/iterable of vertices

        - a list/tuple/iterable of slopes

        OUTPUT:

        The corresponding Newton polygon.

        For more informations, see :class:`ParentNewtonPolygon`.

        TESTS:

            sage: from sage.geometry.newton_polygon import NewtonPolygon
            sage: NewtonPolygon(0)
            Empty Newton polygon
            sage: NewtonPolygon(1)
            Finite Newton polygon with 1 vertex: (0, 0)
        """
        if is_Polyhedron(arg):
            return self.element_class(arg, parent=self)
        if arg == 0:
            polyhedron = Polyhedron(base_ring=self.base_ring(), ambient_dim=2)
            return self.element_class(polyhedron, parent=self)
        if arg == 1:
            polyhedron = Polyhedron(base_ring=self.base_ring(),
                                    vertices=[(0, 0)],
                                    rays=[(0, 1)])
            return self.element_class(polyhedron, parent=self)
        if not isinstance(arg, list):
            try:
                arg = list(arg)
            except TypeError:
                raise TypeError(
                    "argument must be a list of coordinates or a list of (rational) slopes"
                )
        if len(arg) > 0 and arg[0] in self.base_ring():
            if sort_slopes: arg.sort()
            x = y = 0
            vertices = [(x, y)]
            for slope in arg:
                if not slope in self.base_ring():
                    raise TypeError(
                        "argument must be a list of coordinates or a list of (rational) slopes"
                    )
                x += 1
                y += slope
                vertices.append((x, y))
        else:
            vertices = [(x, y) for (x, y) in arg if y is not Infinity]
        if len(vertices) == 0:
            polyhedron = Polyhedron(base_ring=self.base_ring(), ambient_dim=2)
        else:
            rays = [(0, 1)]
            if last_slope is not Infinity:
                rays.append((1, last_slope))
            polyhedron = Polyhedron(base_ring=self.base_ring(),
                                    vertices=vertices,
                                    rays=rays)
        return self.element_class(polyhedron, parent=self)
Example #6
0
    def _element_constructor_(self, *args, **kwds):
        """
        The element (polyhedron) constructor.

        INPUT:

        - ``Vrep`` -- a list `[vertices, rays, lines]`` or ``None``.

        - ``Hrep`` -- a list `[ieqs, eqns]`` or ``None``.

        - ``convert`` -- boolean keyword argument (default:
          ``True``). Whether to convert the coordinates into the base
          ring.

        - ``**kwds`` -- optional remaining keywords that are passed to the
          polyhedron constructor.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.parent import Polyhedra
            sage: P = Polyhedra(QQ, 3)
            sage: P._element_constructor_([[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P([[(0,0,0),(1,0,0),(0,1,0),(0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P(0)
            A 0-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex

        Check that :trac:`21270` is fixed::

            sage: poly = polytopes.regular_polygon(7)
            sage: lp, x = poly.to_linear_program(solver='InteractiveLP', return_variable=True)
            sage: lp.set_objective(x[0] + x[1])
            sage: b = lp.get_backend()
            sage: P = b.interactive_lp_problem()
            sage: p = P.plot()

            sage: Q = Polyhedron(ieqs=[[-499999, 1000000], [1499999, -1000000]])
            sage: P = Polyhedron(ieqs=[[0, 1.0], [1.0, -1.0]], base_ring=RDF)
            sage: Q.intersection(P)
            A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices
            sage: P.intersection(Q)
            A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices
        """
        nargs = len(args)
        convert = kwds.pop('convert', True)

        def convert_base_ring(lstlst):
            return [[self.base_ring()(x) for x in lst] for lst in lstlst]

        # renormalize before converting when going from QQ to RDF, see trac 21270
        def convert_base_ring_Hrep(lstlst):
            newlstlst = []
            for lst in lstlst:
                if all(c in QQ for c in lst):
                    m = max(abs(w) for w in lst)
                    if m == 0:
                        newlstlst.append(lst)
                    else:
                        newlstlst.append([q/m for q in lst])
                else:
                    newlstlst.append(lst)
            return convert_base_ring(newlstlst)
        if nargs == 2:
            Vrep, Hrep = args
            if convert and Hrep:
                if self.base_ring == RDF:
                    Hrep = [convert_base_ring_Hrep(_) for _ in Hrep]
                else:
                    Hrep = [convert_base_ring(_) for _ in Hrep]
            if convert and Vrep:
                Vrep = [convert_base_ring(_) for _ in Vrep]
            return self.element_class(self, Vrep, Hrep, **kwds)
        if nargs == 1 and is_Polyhedron(args[0]):
            polyhedron = args[0]
            return self._element_constructor_polyhedron(polyhedron, **kwds)
        if nargs == 1 and args[0] == 0:
            return self.zero()
        raise ValueError('Cannot convert to polyhedron object.')
Example #7
0
    def _element_constructor_(self, arg, sort_slopes=True, last_slope=Infinity):
        """
        INPUT:

        - ``arg`` -- an argument describing the Newton polygon

        - ``sort_slopes`` -- boolean (default: ``True``). Specifying
          whether slopes must be first sorted

        - ``last_slope`` -- rational or infinity (default:
          ``Infinity``). The last slope of the Newton polygon

        The first argument ``arg`` can be either:

        - a polyhedron in `\QQ^2`

        - the element ``0`` (corresponding to the empty Newton polygon)

        - the element ``1`` (corresponding to the Newton polygon of the
          constant polynomial equal to 1)

        - a list/tuple/iterable of vertices

        - a list/tuple/iterable of slopes

        OUTPUT:

        The corresponding Newton polygon.

        For more informations, see :class:`ParentNewtonPolygon`.

        TESTS:

            sage: from sage.geometry.newton_polygon import NewtonPolygon
            sage: NewtonPolygon(0)
            Empty Newton polygon
            sage: NewtonPolygon(1)
            Finite Newton polygon with 1 vertex: (0, 0)
        """
        if is_Polyhedron(arg):
            return self.element_class(arg, parent=self)
        if arg == 0:
            polyhedron = Polyhedron(base_ring=self.base_ring(), ambient_dim=2)
            return self.element_class(polyhedron, parent=self)
        if arg == 1:
            polyhedron = Polyhedron(base_ring=self.base_ring(),
                                    vertices=[(0,0)], rays=[(0,1)])
            return self.element_class(polyhedron, parent=self)
        if not isinstance(arg, list):
            try:
                arg = list(arg)
            except TypeError:
                raise TypeError("argument must be a list of coordinates or a list of (rational) slopes")
        if len(arg) > 0 and arg[0] in self.base_ring():
            if sort_slopes: arg.sort()
            x = y = 0
            vertices = [(x, y)]
            for slope in arg:
                if not slope in self.base_ring():
                    raise TypeError("argument must be a list of coordinates or a list of (rational) slopes")
                x += 1
                y += slope
                vertices.append((x,y))
        else:
            vertices = [(x, y) for (x, y) in arg if y is not Infinity]
        if len(vertices) == 0:
            polyhedron = Polyhedron(base_ring=self.base_ring(), ambient_dim=2)
        else:
            rays = [(0, 1)]
            if last_slope is not Infinity:
                rays.append((1, last_slope))
            polyhedron = Polyhedron(base_ring=self.base_ring(), vertices=vertices, rays=rays)
        return self.element_class(polyhedron, parent=self)
Example #8
0
    def _element_constructor_(self, *args, **kwds):
        """
        The element (polyhedron) constructor.

        INPUT:

        - ``Vrep`` -- a list `[vertices, rays, lines]`` or ``None``.

        - ``Hrep`` -- a list `[ieqs, eqns]`` or ``None``.

        - ``convert`` -- boolean keyword argument (default:
          ``True``). Whether to convert the coordinates into the base
          ring.

        - ``**kwds`` -- optional remaining keywords that are passed to the
          polyhedron constructor.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.parent import Polyhedra
            sage: P = Polyhedra(QQ, 3)
            sage: P._element_constructor_([[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P([[(0,0,0),(1,0,0),(0,1,0),(0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P(0)
            A 0-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex

        Check that :trac:`21270` is fixed::

            sage: poly = polytopes.regular_polygon(7)
            sage: lp, x = poly.to_linear_program(solver='InteractiveLP', return_variable=True)
            sage: lp.set_objective(x[0] + x[1])
            sage: b = lp.get_backend()
            sage: P = b.interactive_lp_problem()
            sage: p = P.plot()

            sage: Q = Polyhedron(ieqs=[[-499999, 1000000], [1499999, -1000000]])
            sage: P = Polyhedron(ieqs=[[0, 1.0], [1.0, -1.0]], base_ring=RDF)
            sage: Q.intersection(P)
            A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices
            sage: P.intersection(Q)
            A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices
        """
        nargs = len(args)
        convert = kwds.pop('convert', True)

        def convert_base_ring(lstlst):
            return [[self.base_ring()(x) for x in lst] for lst in lstlst]

        # renormalize before converting when going from QQ to RDF, see trac 21270
        def convert_base_ring_Hrep(lstlst):
            newlstlst = []
            for lst in lstlst:
                if all(c in QQ for c in lst):
                    m = max(abs(w) for w in lst)
                    if m == 0:
                        newlstlst.append(lst)
                    else:
                        newlstlst.append([q/m for q in lst])
                else:
                    newlstlst.append(lst)
            return convert_base_ring(newlstlst)
        if nargs == 2:
            Vrep, Hrep = args
            if convert and Hrep:
                if self.base_ring == RDF:
                    Hrep = [convert_base_ring_Hrep(_) for _ in Hrep]
                else:
                    Hrep = [convert_base_ring(_) for _ in Hrep]
            if convert and Vrep:
                Vrep = [convert_base_ring(_) for _ in Vrep]
            return self.element_class(self, Vrep, Hrep, **kwds)
        if nargs == 1 and is_Polyhedron(args[0]):
            polyhedron = args[0]
            return self._element_constructor_polyhedron(polyhedron, **kwds)
        if nargs == 1 and args[0] == 0:
            return self.zero()
        raise ValueError('Cannot convert to polyhedron object.')
Example #9
0
    def _element_constructor_(self, *args, **kwds):
        """
        The element (polyhedron) constructor.

        INPUT:

        - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``.

        - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``.

        - ``convert`` -- boolean keyword argument (default:
          ``True``). Whether to convert the coordinates into the base
          ring.

        - ``**kwds`` -- optional remaining keywords that are passed to the
          polyhedron constructor.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.parent import Polyhedra
            sage: P = Polyhedra(QQ, 3)
            sage: P._element_constructor_([[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P([[(0,0,0),(1,0,0),(0,1,0),(0,0,1)], [], []], None)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices
            sage: P(0)
            A 0-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex

        Check that :trac:`21270` is fixed::

            sage: poly = polytopes.regular_polygon(7)
            sage: lp, x = poly.to_linear_program(solver='InteractiveLP', return_variable=True)
            sage: lp.set_objective(x[0] + x[1])
            sage: b = lp.get_backend()
            sage: P = b.interactive_lp_problem()
            sage: p = P.plot()  # optional - sage.plot

            sage: Q = Polyhedron(ieqs=[[-499999, 1000000], [1499999, -1000000]])
            sage: P = Polyhedron(ieqs=[[0, 1.0], [1.0, -1.0]], base_ring=RDF)
            sage: Q.intersection(P)
            A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices
            sage: P.intersection(Q)
            A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices

        The default is not to copy an object if the parent is ``self``::

            sage: p = polytopes.cube(backend='field')
            sage: P = p.parent()
            sage: q = P._element_constructor_(p)
            sage: q is p
            True
            sage: r = P._element_constructor_(p, copy=True)
            sage: r is p
            False

        When the parent of the object is not ``self``, the default is not to copy::

            sage: Q = P.base_extend(AA)
            sage: q = Q._element_constructor_(p)
            sage: q is p
            False
            sage: q = Q._element_constructor_(p, copy=False)
            Traceback (most recent call last):
            ...
            ValueError: you need to make a copy when changing the parent

        For mutable polyhedra either ``copy`` or ``mutable`` must be specified::

            sage: p = Polyhedron(vertices=[[0, 1], [1, 0]], mutable=True)
            sage: P = p.parent()
            sage: q = P._element_constructor_(p)
            Traceback (most recent call last):
            ...
            ValueError: must make a copy to obtain immutable object from mutable input
            sage: q = P._element_constructor_(p, mutable=True)
            sage: q is p
            True
            sage: r = P._element_constructor_(p, copy=True)
            sage: r.is_mutable()
            False
            sage: r is p
            False
        """
        nargs = len(args)
        convert = kwds.pop('convert', True)

        def convert_base_ring(lstlst):
            return [[self.base_ring()(x) for x in lst] for lst in lstlst]

        # renormalize before converting when going from QQ to RDF, see trac 21270
        def convert_base_ring_Hrep(lstlst):
            newlstlst = []
            for lst in lstlst:
                if all(c in QQ for c in lst):
                    m = max(abs(w) for w in lst)
                    if m == 0:
                        newlstlst.append(lst)
                    else:
                        newlstlst.append([q / m for q in lst])
                else:
                    newlstlst.append(lst)
            return convert_base_ring(newlstlst)

        if nargs == 2:
            Vrep, Hrep = args
            if convert and Hrep:
                if self.base_ring == RDF:
                    Hrep = [convert_base_ring_Hrep(_) for _ in Hrep]
                else:
                    Hrep = [convert_base_ring(_) for _ in Hrep]
            if convert and Vrep:
                Vrep = [convert_base_ring(_) for _ in Vrep]
            return self.element_class(self, Vrep, Hrep, **kwds)
        if nargs == 1 and is_Polyhedron(args[0]):
            copy = kwds.pop('copy', args[0].parent() is not self)
            mutable = kwds.pop('mutable', False)

            if not copy and args[0].parent() is not self:
                raise ValueError(
                    "you need to make a copy when changing the parent")
            if args[0].is_mutable() and not copy and not mutable:
                raise ValueError(
                    "must make a copy to obtain immutable object from mutable input"
                )
            if not copy and mutable is args[0].is_mutable():
                return args[0]

            polyhedron = args[0]
            return self._element_constructor_polyhedron(polyhedron,
                                                        mutable=mutable,
                                                        **kwds)
        if nargs == 1 and args[0] == 0:
            return self.zero()
        raise ValueError('Cannot convert to polyhedron object.')
Example #10
0
    def __call__(self, v):
        """
        Apply the affine transformation to ``v``.

        INPUT:

        - ``v`` -- a polynomial, a multivariate polynomial, a polyhedron, a
          vector, or anything that can be converted into a vector.

        OUTPUT:

        The image of ``v`` under the affine group element.

        EXAMPLES::

            sage: G = AffineGroup(2, QQ)
            sage: g = G([0,1,-1,0],[2,3]);  g
                  [ 0  1]     [2]
            x |-> [-1  0] x + [3]
            sage: v = vector([4,5])
            sage: g(v)
            (7, -1)

            sage: R.<x,y> = QQ[]
            sage: g(x), g(y)
            (y + 2, -x + 3)
            sage: p = x^2 + 2*x*y + y + 1
            sage: g(p)
            -2*x*y + y^2 - 5*x + 10*y + 20

        The action on polynomials is such that it intertwines with
        evaluation. That is::

            sage: p(*g(v)) == g(p)(*v)
            True

        Test that the univariate polynomial ring is covered::

            sage: H = AffineGroup(1, QQ)
            sage: h = H([2],[3]);  h
            x |-> [2] x + [3]
            sage: R.<z> = QQ[]
            sage: h(z+1)
            3*z + 2

        The action on a polyhedron is defined (see :trac:`30327`)::

            sage: F = AffineGroup(3, QQ)
            sage: M = matrix(3, [-1, -2, 0, 0, 0, 1, -2, 1, -1])
            sage: v = vector(QQ,(1,2,3))
            sage: f = F(M, v)
            sage: cube = polytopes.cube()
            sage: f(cube)
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices

        """
        parent = self.parent()

        # start with the most probable case, i.e., v is in the vector space
        if v in parent.vector_space():
            return self._A*v + self._b

        from sage.rings.polynomial.polynomial_element import is_Polynomial
        if is_Polynomial(v) and parent.degree() == 1:
            ring = v.parent()
            return ring([self._A[0,0], self._b[0]])

        from sage.rings.polynomial.multi_polynomial import is_MPolynomial
        if is_MPolynomial(v) and parent.degree() == v.parent().ngens():
            ring = v.parent()
            from sage.modules.all import vector
            image_coords = self._A * vector(ring, ring.gens()) + self._b
            return v(*image_coords)

        from sage.geometry.polyhedron.base import is_Polyhedron
        if is_Polyhedron(v):
            return self._A*v + self._b

        # otherwise, coerce v into the vector space
        v = parent.vector_space()(v)
        return self._A*v + self._b