# HG changeset patch
# User Andrey Novoseltsev
# Date 1287093111 21600
# Node ID 241bda86abc36028e5ad52efaa80e771944a1854
# Parent 52545114f01fa96880097a9e04ddd7297827ac7f
Trac 9972: Add embedding of cones and keep ray order for fans generated by a single cone.
diff -r 52545114f01f -r 241bda86abc3 sage/geometry/cone.py
--- a/sage/geometry/cone.py Wed Jun 16 10:38:59 2010 +0200
+++ b/sage/geometry/cone.py Thu Oct 14 15:51:51 2010 -0600
@@ -1549,6 +1549,111 @@
self._dual._dual = self
return self._dual
+ def embed(self, cone):
+ r"""
+ Return the cone equivalent to the given one, but sitting in ``self`` as
+ a face.
+
+ You may need to use this method before calling methods of ``cone`` that
+ depend on the ambient structure, such as
+ :meth:`~sage.geometry.cone.ConvexRationalPolyhedralCone.ambient_ray_indices`
+ or
+ :meth:`~sage.geometry.cone.ConvexRationalPolyhedralCone.facet_of`. The
+ cone returned by this method will have ``self`` as ambient. If ``cone``
+ does not represent a valid cone of ``self``, ``ValueError`` exception
+ is raised.
+
+ .. NOTE::
+
+ This method is very quick if ``self`` is already the ambient
+ structure of ``cone``, so you can use without extra checks and
+ performance hit even if ``cone`` is likely to sit in ``self`` but
+ in principle may not.
+
+ INPUT:
+
+ - ``cone`` -- a :class:`cone
+ `.
+
+ OUTPUT:
+
+ - a :class:`cone `,
+ equivalent to ``cone`` but sitting inside ``self``.
+
+ EXAMPLES:
+
+ Let's take a 3-d cone on 4 rays::
+
+ sage: c = Cone([(1,0,1), (0,1,1), (-1,0,1), (0,-1,1)])
+
+ Then any ray generates a 1-d face of this cone, but if you construct
+ such a face directly, it will not "sit" inside the cone::
+
+ sage: ray = Cone([(0,-1,1)])
+ sage: ray
+ 1-d cone in 3-d lattice N
+ sage: ray.ambient_ray_indices()
+ (0,)
+ sage: ray.adjacent()
+ ()
+ sage: ray.ambient()
+ 1-d cone in 3-d lattice N
+
+ If we want to operate with this ray as a face of the cone, we need to
+ embed it first::
+
+ sage: e_ray = c.embed(ray)
+ sage: e_ray
+ 1-d face of 3-d cone in 3-d lattice N
+ sage: e_ray.rays()
+ (N(0, -1, 1),)
+ sage: e_ray is ray
+ False
+ sage: e_ray.is_equivalent(ray)
+ True
+ sage: e_ray.ambient_ray_indices()
+ (3,)
+ sage: e_ray.adjacent()
+ (1-d face of 3-d cone in 3-d lattice N,
+ 1-d face of 3-d cone in 3-d lattice N)
+ sage: e_ray.ambient()
+ 3-d cone in 3-d lattice N
+
+ Not every cone can be embedded into a fixed ambient cone::
+
+ sage: c.embed(Cone([(0,0,1)]))
+ Traceback (most recent call last):
+ ...
+ ValueError: 1-d cone in 3-d lattice N is not a face
+ of 3-d cone in 3-d lattice N!
+ sage: c.embed(Cone([(1,0,1), (-1,0,1)]))
+ Traceback (most recent call last):
+ ...
+ ValueError: 2-d cone in 3-d lattice N is not a face
+ of 3-d cone in 3-d lattice N!
+ """
+ assert is_Cone(cone)
+ if cone.ambient() is self:
+ return cone
+ if self.is_strictly_convex():
+ rays = self.rays()
+ try:
+ ray_indices = tuple(sorted(rays.index(ray)
+ for ray in cone.rays()))
+ for face in self.faces(cone.dim()):
+ if face.ambient_ray_indices() == ray_indices:
+ return face
+ except ValueError:
+ pass
+ else:
+ # We cannot use the trick with indices since rays are not unique.
+ for face in self.faces(cone.dim()):
+ if cone.is_equivalent(face):
+ return face
+ # If we are here, then either ValueError was raised or we went through
+ # all faces and didn't find the matching one.
+ raise ValueError("%s is not a face of %s!" % (cone, self))
+
def face_lattice(self):
r"""
Return the face lattice of ``self``.
@@ -2063,6 +2168,11 @@
sage: cone1.is_equivalent(cone2)
True
"""
+ if self is other:
+ return True
+ # TODO: Next check is pointless if cones and fans are made to be unique
+ if self.ambient() is other.ambient() and self.is_strictly_convex():
+ return self.ambient_ray_indices() == other.ambient_ray_indices()
if self.lattice() != other.lattice():
return False
if self.ray_set() == other.ray_set():
diff -r 52545114f01f -r 241bda86abc3 sage/geometry/fan.py
--- a/sage/geometry/fan.py Wed Jun 16 10:38:59 2010 +0200
+++ b/sage/geometry/fan.py Thu Oct 14 15:51:51 2010 -0600
@@ -425,11 +425,22 @@
(), (), rays[0].parent() if rays else lattice)
if is_Cone(cones[0]):
# Construct the fan from Cone objects
+ if lattice is None:
+ lattice = cones[0].lattice()
if check:
for cone in cones:
if not cone.is_strictly_convex():
raise ValueError(
"cones of a fan must be strictly convex!")
+ if cone.lattice() != lattice:
+ raise ValueError("all cones of a fan must be in %s, but "
+ "%s is not!" % (lattice, cone))
+ # Optimization for fans generated by a single cone
+ if len(cones) == 1:
+ cone = cones[0]
+ return RationalPolyhedralFan((tuple(range(cone.nrays())), ),
+ cone.rays(), lattice,
+ is_complete=lattice.dimension() == 0)
ray_set = set([])
for cone in cones:
ray_set.update(cone.rays())
@@ -1239,11 +1250,11 @@
sage: new_fan = fan._subdivide_palp(new_rays, True)
R:1/1 C:2 T:...(ms) T/new:...(ms) T/all:...(ms)
sage: new_fan.ray_matrix()
+ [1 0 1]
[0 1 1]
- [1 0 1]
sage: for cone in new_fan: print cone.ambient_ray_indices()
+ (1, 2)
(0, 2)
- (1, 2)
We make sure that this function constructs cones with ordered ambient
ray indices (see Trac 9812)::
@@ -1251,7 +1262,7 @@
sage: C = Cone([(1,0,0), (0,1,0), (1,0,1), (0,1,1)])
sage: F = Fan([C]).make_simplicial()
sage: [cone.ambient_ray_indices() for cone in F]
- [(0, 1, 3), (0, 1, 2)]
+ [(0, 2, 3), (0, 1, 3)]
"""
dim = self.lattice_dim()
for cone in self:
@@ -1676,6 +1687,104 @@
data = data[0]
return self._contains(data)
+ def embed(self, cone):
+ r"""
+ Return the cone equivalent to the given one, but sitting in ``self``.
+
+ You may need to use this method before calling methods of ``cone`` that
+ depend on the ambient structure, such as
+ :meth:`~sage.geometry.cone.ConvexRationalPolyhedralCone.ambient_ray_indices`
+ or
+ :meth:`~sage.geometry.cone.ConvexRationalPolyhedralCone.facet_of`. The
+ cone returned by this method will have ``self`` as ambient. If ``cone``
+ does not represent a valid cone of ``self``, ``ValueError`` exception
+ is raised.
+
+ .. NOTE::
+
+ This method is very quick if ``self`` is already the ambient
+ structure of ``cone``, so you can use without extra checks and
+ performance hit even if ``cone`` is likely to sit in ``self`` but
+ in principle may not.
+
+ INPUT:
+
+ - ``cone`` -- a :class:`cone
+ `.
+
+ OUTPUT:
+
+ - a :class:`cone of fan `, equivalent to ``cone`` but
+ sitting inside ``self``.
+
+ EXAMPLES:
+
+ Let's take a 3-d fan generated by a cone on 4 rays::
+
+ sage: f = Fan([Cone([(1,0,1), (0,1,1), (-1,0,1), (0,-1,1)])])
+
+ Then any ray generates a 1-d cone of this fan, but if you construct
+ such a cone directly, it will not "sit" inside the fan::
+
+ sage: ray = Cone([(0,-1,1)])
+ sage: ray
+ 1-d cone in 3-d lattice N
+ sage: ray.ambient_ray_indices()
+ (0,)
+ sage: ray.adjacent()
+ ()
+ sage: ray.ambient()
+ 1-d cone in 3-d lattice N
+
+ If we want to operate with this ray as a part of the fan, we need to
+ embed it first::
+
+ sage: e_ray = f.embed(ray)
+ sage: e_ray
+ 1-d cone of Rational polyhedral fan in 3-d lattice N
+ sage: e_ray.rays()
+ (N(0, -1, 1),)
+ sage: e_ray is ray
+ False
+ sage: e_ray.is_equivalent(ray)
+ True
+ sage: e_ray.ambient_ray_indices()
+ (3,)
+ sage: e_ray.adjacent()
+ (1-d cone of Rational polyhedral fan in 3-d lattice N,
+ 1-d cone of Rational polyhedral fan in 3-d lattice N)
+ sage: e_ray.ambient()
+ Rational polyhedral fan in 3-d lattice N
+
+ Not every cone can be embedded into a fixed fan::
+
+ sage: f.embed(Cone([(0,0,1)]))
+ Traceback (most recent call last):
+ ...
+ ValueError: 1-d cone in 3-d lattice N does not belong
+ to Rational polyhedral fan in 3-d lattice N!
+ sage: f.embed(Cone([(1,0,1), (-1,0,1)]))
+ Traceback (most recent call last):
+ ...
+ ValueError: 2-d cone in 3-d lattice N does not belong
+ to Rational polyhedral fan in 3-d lattice N!
+ """
+ assert is_Cone(cone)
+ if cone.ambient() is self:
+ return cone
+ rays = self.rays()
+ try:
+ # Compute ray indices
+ ray_indices = [rays.index(ray) for ray in cone.rays()]
+ # Get the smallest cone containing them
+ result = self.cone_containing(*ray_indices)
+ # It should be equivalent to the original one
+ if not result.is_equivalent(cone):
+ raise ValueError
+ except ValueError:
+ raise ValueError("%s does not belong to %s!" % (cone, self))
+ return result
+
def Gale_transform(self):
r"""
Return the Gale transform of ``self``.
diff -r 52545114f01f -r 241bda86abc3 sage/schemes/generic/toric_variety.py
--- a/sage/schemes/generic/toric_variety.py Wed Jun 16 10:38:59 2010 +0200
+++ b/sage/schemes/generic/toric_variety.py Thu Oct 14 15:51:51 2010 -0600
@@ -1545,10 +1545,10 @@
sage: TV_res.is_smooth()
True
sage: TV_res.fan().ray_matrix()
- [-1 1 0]
+ [ 1 -1 0]
[ 1 1 1]
sage: [cone.ambient_ray_indices() for cone in TV_res.fan()]
- [(1, 2), (0, 2)]
+ [(0, 2), (1, 2)]
Now let's "automatically" partially resolve a more complicated fan::