@@ -2039,7 +2039,7 @@ def facets_of_simplex(simplex):
20392039 pushing_triangulation = placing_triangulation
20402040
20412041 @cached_method
2042- def Gale_transform (self , points = None ):
2042+ def Gale_transform (self , points = None , homogenize = True ):
20432043 r"""
20442044 Return the Gale transform of ``self``.
20452045
@@ -2049,6 +2049,9 @@ def Gale_transform(self, points=None):
20492049 (default). A subset of points for which to compute the Gale
20502050 transform. By default, all points are used.
20512051
2052+ - ``homogenize`` -- boolean (default: ``True``); whether to add a row
2053+ of 1's before taking the transform.
2054+
20522055 OUTPUT: a matrix over :meth:`base_ring`
20532056
20542057 EXAMPLES::
@@ -2064,6 +2067,50 @@ def Gale_transform(self, points=None):
20642067 sage: points = (pc.point(0), pc.point(1), pc.point(3), pc.point(4))
20652068 sage: pc.Gale_transform(points)
20662069 [ 1 -1 1 -1]
2070+
2071+ It is possible to take the inverse of the Gale transform, by specifying
2072+ whether to homogenize or not::
2073+
2074+ sage: pc2 = PointConfiguration([[0,0],[3,0],[0,3],[3,3],[1,1]])
2075+ sage: pc2.Gale_transform(homogenize=False)
2076+ [-1 0 0 0 0]
2077+ [ 0 1 1 -1 0]
2078+ [ 0 1 1 0 -3]
2079+ sage: pc2.Gale_transform(homogenize=True)
2080+ [ 1 1 1 0 -3]
2081+ [ 0 2 2 -1 -3]
2082+
2083+ It might not affect the dimension of the result::
2084+
2085+ sage: PC = PointConfiguration([[4,0,0],[0,4,0],[0,0,4],[2,1,1],[1,2,1],[1,1,2]])
2086+ sage: GT = PC.Gale_transform(homogenize=False);GT
2087+ [ 2 1 1 -4 0 0]
2088+ [ 1 2 1 0 -4 0]
2089+ [-2 -2 -1 3 3 -1]
2090+ sage: GT = PC.Gale_transform(homogenize=True);GT
2091+ [ 1 0 0 -3 1 1]
2092+ [ 0 1 0 1 -3 1]
2093+ [ 0 0 1 1 1 -3]
2094+
2095+ The following point configuration is totally cyclic (the cone spanned
2096+ by the vectors is equal to the vector space spanned by the points),
2097+ hence its Gale dual is acyclic (there is a linear functional that is
2098+ positive in all the points of the configuration) when not homogenized::
2099+
2100+ sage: pc3 = PointConfiguration([[-1, -1, -1], [-1, 0, 0], [0, -1, 0], [0, 0, -1], [1, 0, 0], [0, 0, 1], [0, 1, 0]])
2101+ sage: g_hom = pc3.Gale_transform(homogenize=True);g_hom
2102+ [ 1 0 0 -2 1 -1 1]
2103+ [ 0 1 0 -1 1 -1 0]
2104+ [ 0 0 1 -1 0 -1 1]
2105+ sage: g_inhom = pc3.Gale_transform(homogenize=False);g_inhom
2106+ [-1 1 1 1 0 0 0]
2107+ [ 0 1 0 0 1 0 0]
2108+ [ 1 -1 -1 0 0 1 0]
2109+ [ 0 0 1 0 0 0 1]
2110+ sage: Polyhedron(rays=g_hom.columns())
2111+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 1 vertex and 3 lines
2112+ sage: Polyhedron(rays=g_inhom.columns())
2113+ A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 1 vertex and 4 rays
20672114 """
20682115 self ._assert_is_affine ()
20692116 if points is None :
@@ -2073,9 +2120,73 @@ def Gale_transform(self, points=None):
20732120 points = [ self .point (ZZ (i )) for i in points ]
20742121 except TypeError :
20752122 pass
2076- m = matrix ([ (1 ,) + p .affine () for p in points ])
2123+ if homogenize :
2124+ m = matrix ([ (1 ,) + p .affine () for p in points ])
2125+ else :
2126+ m = matrix ([p .affine () for p in points ])
20772127 return m .left_kernel ().matrix ()
20782128
2129+ def deformation_cone (self , collection ):
2130+ r"""
2131+ Return the deformation cone for the ``collection`` of subconfigurations
2132+ of ``self``.
2133+
2134+ INPUT:
2135+
2136+ - ``collection`` -- a collection of subconfigurations of ``self``.
2137+ Subconfigurations are given as indices
2138+
2139+ OUTPUT: a polyhedron. It contains the liftings of the point configuration
2140+ making the collection a regular (or coherent, or projective)
2141+ subdivision.
2142+
2143+ EXAMPLES::
2144+
2145+ sage: PC = PointConfiguration([(-1, -1), (-1, 0), (0, -1), (1, 0), (0, 1)])
2146+ sage: coll = [(1, 4), (0, 2), (0, 1), (2, 3), (3, 4)]
2147+ sage: dc = PC.deformation_cone(coll);dc
2148+ A 5-dimensional polyhedron in QQ^5 defined as the convex hull of 1 vertex, 3 rays, 2 lines
2149+ sage: dc.rays()
2150+ (A ray in the direction (1, 0, 1, 0, 0),
2151+ A ray in the direction (1, 1, 0, 0, 0),
2152+ A ray in the direction (1, 1, 1, 0, 0))
2153+ sage: dc.lines()
2154+ (A line in the direction (1, 0, 1, 0, -1),
2155+ A line in the direction (1, 1, 0, -1, 0))
2156+ sage: dc.an_element()
2157+ (3, 2, 2, 0, 0)
2158+
2159+ We add to the interior element the first line and we verify that the
2160+ given rays are defining rays of the lower hull::
2161+
2162+ sage: P = Polyhedron(rays=[(-1, -1, 4), (-1, 0, 3), (0, -1, 2), (1, 0, -1), (0, 1, 0)])
2163+ sage: P.rays()
2164+ (A ray in the direction (-1, -1, 4),
2165+ A ray in the direction (-1, 0, 3),
2166+ A ray in the direction (0, -1, 2),
2167+ A ray in the direction (0, 1, 0),
2168+ A ray in the direction (1, 0, -1))
2169+
2170+ .. SEEALSO::
2171+
2172+ :meth:`~sage.schemes.toric.variety.Kaehler_cone`
2173+
2174+ REFERENCES:
2175+
2176+ For more information, see Section 5.4 of [DLRS2010]_ and Section
2177+ 2.2 of [ACEP2020].
2178+ """
2179+ from sage .geometry .polyhedron .constructor import Polyhedron
2180+ gale = self .Gale_transform (homogenize = False )
2181+ dual_rays = gale .columns ()
2182+ n = self .n_points ()
2183+ K = None
2184+ for cone_indices in collection :
2185+ dual_cone = Polyhedron (rays = [dual_rays [i ] for i in range (n ) if i not in cone_indices ])
2186+ K = K .intersection (dual_cone ) if K is not None else dual_cone
2187+ preimages = [gale .solve_right (r .vector ()) for r in K .rays ()]
2188+ return Polyhedron (lines = matrix (self .points ()).transpose ().rows (),rays = preimages )
2189+
20792190 def plot (self , ** kwds ):
20802191 r"""
20812192 Produce a graphical representation of the point configuration.
0 commit comments