Skip to content

Commit

Permalink
Trac #28724: Polyhedron._acted_upon_ should handle left multiplicatio…
Browse files Browse the repository at this point in the history
…n by matrices, linear transformations

{{{
sage: b3 = polytopes.Birkhoff_polytope(3)
sage: b3.ambient_dim()
9
sage: proj_mat=matrix([[0,1,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0],[0,0,0,0,
0,1,0,0,0],[0,0,0,0,0,0,0,1,0]])
b3_proj = proj_mat * b3
Traceback (most recent call last)
.....
.... sage/geometry/polyhedron/base.pyc in _acted_upon_(self, actor,
self_on_left)
   3687             return self.translation(actor)
   3688         else:
-> 3689             return self.dilation(actor)
   3690
   3691     def __neg__(self):
.....
ValueError: V-representation data requires a list of length ambient_dim
}}}

URL: https://trac.sagemath.org/28724
Reported by: mkoeppe
Ticket author(s): Jean-Philippe Labbé, Jonathan Kliem
Reviewer(s): Jonathan Kliem, Jean-Philippe Labbé
  • Loading branch information
Release Manager committed Feb 9, 2020
2 parents 8870d6b + a1072ee commit 52644d4
Showing 1 changed file with 122 additions and 9 deletions.
131 changes: 122 additions & 9 deletions src/sage/geometry/polyhedron/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import itertools
import six
from sage.structure.element import Element, coerce_binop, is_Vector
from sage.structure.element import Element, coerce_binop, is_Vector, is_Matrix
from sage.structure.richcmp import rich_to_bool, op_NE
from sage.cpython.string import bytes_to_str

Expand Down Expand Up @@ -4270,37 +4270,150 @@ def dilation(self, scalar):
parent = self.parent().base_extend(scalar)
return parent.element_class(parent, [new_vertices, new_rays, new_lines], None)

def _acted_upon_(self, actor, self_on_left):
def linear_transformation(self, linear_transf):
"""
Implement the multiplicative action by scalars or other polyhedra.
Return the linear transformation of ``self``.
INPUT:
- ``actor`` -- A scalar, not necessarily in :meth:`base_ring`,
or a :class:`Polyhedron`
- ``linear_transf`` -- a matrix, not necessarily in :meth:`base_ring`
OUTPUT:
Multiplication by another polyhedron returns the product
polytope. Multiplication by a scalar returns the polytope
dilated by that scalar, possibly coerced to the bigger base ring.
The polyhedron transformed by that matrix, possibly coerced to a
bigger base ring.
EXAMPLES::
sage: b3 = polytopes.Birkhoff_polytope(3)
sage: proj_mat=matrix([[0,1,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0],[0,0,0,0,0,1,0,0,0],[0,0,0,0,0,0,0,1,0]])
sage: b3_proj = proj_mat * b3; b3_proj
A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices
sage: square = polytopes.regular_polygon(4)
sage: square.vertices_list()
[[0, -1], [1, 0], [-1, 0], [0, 1]]
sage: transf = matrix([[1,1],[0,1]])
sage: sheared = transf * square
sage: sheared.vertices_list()
[[-1, 0], [-1, -1], [1, 1], [1, 0]]
sage: sheared == square.linear_transformation(transf)
True
TESTS:
Linear transformation respects backend::
sage: P = polytopes.simplex(backend='field')
sage: t = matrix([[1,1,1,1],[0,1,1,1],[0,0,1,1],[0,0,0,1]])
sage: P.linear_transformation(t).backend()
'field'
Check that coercion works::
sage: (1.0 * proj_mat) * b3
A 3-dimensional polyhedron in RDF^4 defined as the convex hull of 5 vertices
sage: (1/1 * proj_mat) * b3
A 3-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices
sage: (AA(2).sqrt() * proj_mat) * b3
A 3-dimensional polyhedron in AA^4 defined as the convex hull of 5 vertices
Check that zero-matrices act correctly::
sage: Matrix([]) * b3
A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex
sage: Matrix([[0 for _ in range(9)]]) * b3
A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex
sage: Matrix([[0 for _ in range(9)] for _ in range(4)]) * b3
A 0-dimensional polyhedron in ZZ^4 defined as the convex hull of 1 vertex
sage: Matrix([[0 for _ in range(8)]]) * b3
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 1 by 8 dense matrices over Integer Ring' and 'Ambient free module of rank 9 over the principal ideal domain Integer Ring'
sage: Matrix(ZZ, []) * b3
A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex
sage: Matrix(ZZ, [[],[]]) * b3
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 0 dense matrices over Integer Ring' and 'Ambient free module of rank 9 over the principal ideal domain Integer Ring'
"""
if linear_transf.nrows() != 0:
new_vertices = [ list(linear_transf*v.vector()) for v in self.vertex_generator() ]
new_rays = [ list(linear_transf*r.vector()) for r in self.ray_generator() ]
new_lines = [ list(linear_transf*l.vector()) for l in self.line_generator() ]
else:
new_vertices = [[] for v in self.vertex_generator() ]
new_rays = []
new_lines = []

new_dim = linear_transf.nrows()
par = self.parent()
new_parent = par.base_extend(linear_transf.base_ring(), ambient_dim=new_dim)

return new_parent.element_class(new_parent, [new_vertices, new_rays, new_lines], None)

def _acted_upon_(self, actor, self_on_left):
"""
Implement the action by scalars, vectors, matrices or other polyhedra.
INPUT:
- ``actor`` -- one of the following:
- a scalar, not necessarily in :meth:`base_ring`,
- a :class:`Polyhedron`,
- a :class:`sage.modules.free_module_element.vector`,
- a :class:`sage.matrix.constructor.matrix`,
- ``self_on_right`` -- must be ``False`` for actor a matrix;
ignored otherwise
OUTPUT:
- Dilation for a scalar
- Product for a polyhedron
- Translation for a vector
- Linear transformation for a matrix
EXAMPLES:
``actor`` is a scalar::
sage: p = Polyhedron(vertices = [[t,t^2,t^3] for t in srange(2,6)])
sage: p._acted_upon_(2, True) == p.dilation(2)
True
sage: p*2 == p.dilation(2)
True
``actor`` is a polyhedron::
sage: p*p == p.product(p)
True
``actor`` is a vector::
sage: p + vector(ZZ,[1,2,3]) == p.translation([1,2,3])
True
``actor`` is a matrix::
sage: matrix(ZZ,[[1,2,3]]) * p
A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices
A matrix must act from the left::
sage: p * matrix(ZZ, [[1,2,3]]*3)
Traceback (most recent call last):
...
ValueError: matrices should act on the left
"""
if is_Polyhedron(actor):
return self.product(actor)
if is_Vector(actor):
elif is_Vector(actor):
return self.translation(actor)
elif is_Matrix(actor):
if self_on_left:
raise ValueError("matrices should act on the left")
else:
return self.linear_transformation(actor)
else:
return self.dilation(actor)

Expand Down

0 comments on commit 52644d4

Please sign in to comment.