Path: blob/master/src/sage/geometry/hyperplane_arrangement/arrangement.py
8817 views
r"""1Hyperplane Arrangements23Before talking about hyperplane arrangements, let us start with4individual hyperplanes. This package uses certain linear expressions5to represent hyperplanes, that is, a linear expression `3x + 3y - 5z - 7`6stands for the hyperplane with the equation `x + 3y - 5z = 7`. To create it7in Sage, you first have to create a :class:`HyperplaneArrangements`8object to define the variables `x`, `y`, `z`::910sage: H.<x,y,z> = HyperplaneArrangements(QQ)11sage: h = 3*x + 2*y - 5*z - 7; h12Hyperplane 3*x + 2*y - 5*z - 713sage: h.normal()14(3, 2, -5)15sage: h.constant_term()16-71718The individual hyperplanes behave like the linear expression with19regard to addition and scalar multiplication, which is why you can do20linear combinations of the coordinates::2122sage: -2*h23Hyperplane -6*x - 4*y + 10*z + 1424sage: x, y, z25(Hyperplane x + 0*y + 0*z + 0, Hyperplane 0*x + y + 0*z + 0, Hyperplane 0*x + 0*y + z + 0)2627See :mod:`sage.geometry.hyperplane_arrangement.hyperplane` for more28functionality of the individual hyperplanes.2930Arrangements31------------3233There are several ways to create hyperplane arrangements:3435Notation (i): by passing individual hyperplanes to the36:class:`HyperplaneArrangements` object::3738sage: H.<x,y> = HyperplaneArrangements(QQ)39sage: box = x | y | x-1 | y-1; box40Arrangement <y - 1 | y | x - 1 | x>41sage: box == H(x, y, x-1, y-1) # alternative syntax42True4344Notation (ii): by passing anything that defines a hyperplane, for45example a coefficient vector and constant term::4647sage: H = HyperplaneArrangements(QQ, ('x', 'y'))48sage: triangle = H([(1, 0), 0], [(0, 1), 0], [(1,1), -1]); triangle49Arrangement <y | x | x + y - 1>5051sage: H.inject_variables()52Defining x, y53sage: triangle == x | y | x+y-154True5556The default base field is `\QQ`, the rational numbers. Finite fields are also57supported::5859sage: H.<x,y,z> = HyperplaneArrangements(GF(5))60sage: a = H([(1,2,3), 4], [(5,6,7), 8]); a61Arrangement <y + 2*z + 3 | x + 2*y + 3*z + 4>6263Notation (iii): a list or tuple of hyperplanes::6465sage: H.<x,y,z> = HyperplaneArrangements(GF(5))66sage: k = [x+i for i in range(4)]; k67[Hyperplane x + 0*y + 0*z + 0, Hyperplane x + 0*y + 0*z + 1,68Hyperplane x + 0*y + 0*z + 2, Hyperplane x + 0*y + 0*z + 3]69sage: H(k)70Arrangement <x | x + 1 | x + 2 | x + 3>7172Notation (iv): using the library of arrangements::7374sage: hyperplane_arrangements.braid(4)75Arrangement of 6 hyperplanes of dimension 4 and rank 376sage: hyperplane_arrangements.semiorder(3)77Arrangement of 6 hyperplanes of dimension 3 and rank 278sage: hyperplane_arrangements.graphical(graphs.PetersenGraph())79Arrangement of 15 hyperplanes of dimension 10 and rank 980sage: hyperplane_arrangements.Ish(5)81Arrangement of 20 hyperplanes of dimension 5 and rank 48283Notation (v): from the bounding hyperplanes of a polyhedron::8485sage: a = polytopes.n_cube(3).hyperplane_arrangement(); a86Arrangement of 6 hyperplanes of dimension 3 and rank 387sage: a.n_regions()88278990New arrangements from old::9192sage: a = hyperplane_arrangements.braid(3)93sage: b = a.add_hyperplane([4, 1, 2, 3])94sage: b95Arrangement <t1 - t2 | t0 - t1 | t0 - t2 | t0 + 2*t1 + 3*t2 + 4>96sage: c = b.deletion([4, 1, 2, 3])97sage: a == c98True99100sage: a = hyperplane_arrangements.braid(3)101sage: b = a.union(hyperplane_arrangements.semiorder(3))102sage: b == a | hyperplane_arrangements.semiorder(3) # alternate syntax103True104sage: b == hyperplane_arrangements.Catalan(3)105True106107sage: a108Arrangement <t1 - t2 | t0 - t1 | t0 - t2>109sage: a = hyperplane_arrangements.coordinate(4)110sage: h = a.hyperplanes()[0]111sage: b = a.restriction(h)112sage: b == hyperplane_arrangements.coordinate(3)113True114115A hyperplane arrangement is *essential* is the normals to its116hyperplane span the ambient space. Otherwise, it is *inessential*.117The essentialization is formed by intersecting the hyperplanes by this118normal space (actually, it is a bit more complicated over finite119fields)::120121sage: a = hyperplane_arrangements.braid(4); a122Arrangement of 6 hyperplanes of dimension 4 and rank 3123sage: a.is_essential()124False125sage: a.rank() < a.dimension() # double-check126True127sage: a.essentialization()128Arrangement of 6 hyperplanes of dimension 3 and rank 3129130The connected components of the complement of the hyperplanes of an arrangement131in `\RR^n` are called the *regions* of the arrangement::132133sage: a = hyperplane_arrangements.semiorder(3)134sage: b = a.essentialization(); b135Arrangement of 6 hyperplanes of dimension 2 and rank 2136sage: b.n_regions()13719138sage: b.regions()139(A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 6 vertices,140A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,141A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,142A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,143A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,144A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,145A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,146A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,147A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,148A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,149A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,150A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,151A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,152A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,153A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,154A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,155A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,156A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,157A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays)158sage: b.bounded_regions()159(A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 6 vertices,160A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,161A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,162A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,163A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,164A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices,165A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices)166sage: b.n_bounded_regions()1677168sage: a.unbounded_regions()169(A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line,170A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line,171A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line,172A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line,173A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line,174A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line,175A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line,176A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line,177A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line,178A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line,179A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line,180A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line)181182The distance between regions is defined as the number of hyperplanes183separating them. For example::184185sage: r1 = b.regions()[0]186sage: r2 = b.regions()[1]187sage: b.distance_between_regions(r1, r2)1881189sage: [hyp for hyp in b if b.is_separating_hyperplane(r1, r2, hyp)]190[Hyperplane 2*t1 + t2 + 1]191sage: b.distance_enumerator(r1) # generating function for distances from r11926*x^3 + 6*x^2 + 6*x + 1193194.. NOTE::195196*bounded region* really mean *relatively bounded* here. A region is197relatively bounded if its intersection with space spanned by the normals198of the hyperplanes in the arrangement is bounded.199200The intersection poset of a hyperplane arrangement is the collection201of all nonempty intersections of hyperplanes in the arrangement,202ordered by reverse inclusion. It includes the ambient space of the203arrangement (as the intersection over the empty set)::204205sage: a = hyperplane_arrangements.braid(3)206sage: p = a.intersection_poset()207sage: p.is_ranked()208True209sage: p.order_polytope()210A 5-dimensional polyhedron in QQ^5 defined as the convex hull of 10 vertices211212The characteristic polynomial is a basic invariant of a hyperplane213arrangement. It is defined as214215.. MATH::216217\chi(x) := \sum_{w\in P} \mu(w) x^{dim(w)}218219where the sum is `P` is the220:meth:`~HyperplaneArrangementElement.intersection_poset` of the221arrangement and `\mu` is the Moebius function of `P`::222223sage: a = hyperplane_arrangements.semiorder(5)224sage: a.characteristic_polynomial() # long time (about a second on Core i7)225x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x226sage: a.poincare_polynomial() # long time2271380*x^4 + 790*x^3 + 180*x^2 + 20*x + 1228sage: a.n_regions() # long time2292371230sage: charpoly = a.characteristic_polynomial() # long time231sage: charpoly(-1) # long time232-2371233sage: a.n_bounded_regions() # long time234751235sage: charpoly(1) # long time236751237238For finer invariants derived from the intersection poset, see239:meth:`~HyperplaneArrangementElement.whitney_number` and240:meth:`~HyperplaneArrangementElement.doubly_indexed_whitney_number`.241242Miscellaneous methods (see documentation for an explanation)::243244sage: a = hyperplane_arrangements.semiorder(3)245sage: a.has_good_reduction(5)246True247sage: b = a.change_ring(GF(5))248sage: pa = a.intersection_poset()249sage: pb = b.intersection_poset()250sage: pa.is_isomorphic(pb)251True252sage: a.face_vector()253(0, 12, 30, 19)254sage: a.face_vector()255(0, 12, 30, 19)256sage: a.is_central()257False258sage: a.is_linear()259False260sage: a.sign_vector((1,1,1))261(-1, 1, -1, 1, -1, 1)262sage: a.varchenko_matrix()263[ 1 h2 h2*h4 h2*h3 h2*h3*h4 h2*h3*h4*h5]264[ h2 1 h4 h3 h3*h4 h3*h4*h5]265[ h2*h4 h4 1 h3*h4 h3 h3*h5]266[ h2*h3 h3 h3*h4 1 h4 h4*h5]267[ h2*h3*h4 h3*h4 h3 h4 1 h5]268[h2*h3*h4*h5 h3*h4*h5 h3*h5 h4*h5 h5 1]269270There are extensive methods for visualizing hyperplane arrangements in271low dimensions. See :meth:`~HyperplaneArrangementElement.plot` for272details.273274TESTS::275276sage: H.<x,y> = HyperplaneArrangements(QQ)277sage: h = H([(1, 106), 106266], [(83, 101), 157866], [(111, 110), 186150], [(453, 221), 532686],278....: [(407, 237), 516882], [(55, 32), 75620], [(221, 114), 289346], [(452, 115), 474217],279....: [(406, 131), 453521], [(28, 9), 32446], [(287, 19), 271774], [(241, 35), 244022],280....: [(231, 1), 210984], [(185, 17), 181508], [(23, -8), 16609])281sage: h.n_regions()28285283284sage: H()285Empty hyperplane arrangement of dimension 2286287sage: Zero = HyperplaneArrangements(QQ)288sage: Zero289Hyperplane arrangements in 0-dimensional linear space over Rational Field with coordinate290sage: Zero()291Empty hyperplane arrangement of dimension 0292sage: Zero.an_element()293Empty hyperplane arrangement of dimension 0294295AUTHORS:296297- David Perkinson (2013-06): initial version298299- Qiaoyu Yang (2013-07)300301- Kuai Yu (2013-07)302303- Volker Braun (2013-10): Better Sage integration, major code refactoring.304305This module implements hyperplane arrangements defined over the306rationals or over finite fields. The original motivation was to make307a companion to Richard Stanley's notes [RS]_ on hyperplane308arrangements.309310REFERENCES:311312.. [RS]313Stanley, Richard: *Hyperplane Arrangements*,314Geometric Combinatorics (E. Miller, V. Reiner, and B. Sturmfels, eds.),315IAS/Park City Mathematics Series, vol. 13, American Mathematical Society,316Providence, RI, 2007, pp. 389-496.317"""318319#*****************************************************************************320# Copyright (C) 2013 David Perkinson <[email protected]>321# Volker Braun <[email protected]>322#323# Distributed under the terms of the GNU General Public License (GPL)324# as published by the Free Software Foundation; either version 2 of325# the License, or (at your option) any later version.326# http://www.gnu.org/licenses/327#*****************************************************************************328329# Possible extensions for hyperplane_arrangement.py:330# - the big face lattice331# - Orlik-Solomon algebras332# - create ties with the Sage matroid methods333# - hyperplane arrangements over other fields334335from sage.structure.parent import Parent336from sage.structure.element import Element337from sage.structure.unique_representation import UniqueRepresentation338from sage.rings.all import QQ, ZZ339from sage.misc.cachefunc import cached_method340from sage.misc.misc import uniq341from sage.matrix.constructor import matrix, vector342343from sage.geometry.hyperplane_arrangement.hyperplane import AmbientVectorSpace, Hyperplane344345346347class HyperplaneArrangementElement(Element):348"""349An element in a hyperplane arrangement.350351.. WARNING::352353You should never create354:class:`HyperplaneArrangementElement` instances directly,355always use the parent.356"""357def __init__(self, parent, hyperplanes, check=True):358"""359Construct a hyperplane arrangement.360361INPUT:362363- ``parent`` -- the parent :class:`HyperplaneArrangements`364365- ``hyperplanes`` -- a tuple of hyperplanes366367- ``check`` -- boolean (optional; default ``True``); whether368to check input369370EXAMPLES::371372sage: H.<x,y> = HyperplaneArrangements(QQ)373sage: elt = H(x, y); elt374Arrangement <y | x>375sage: TestSuite(elt).run()376"""377super(HyperplaneArrangementElement, self).__init__(parent)378self._hyperplanes = hyperplanes379if check:380if not isinstance(hyperplanes, tuple):381raise ValueError("the hyperplanes must be given as a tuple")382if not all(isinstance(h, Hyperplane) for h in hyperplanes):383raise ValueError("not all elements are hyperplanes")384if not all(h.parent() is self.parent().ambient_space() for h in hyperplanes):385raise ValueError("not all hyperplanes are in the ambient space")386387def _first_ngens(self, n):388"""389Workaround to support the construction with names.390391INPUT/OUTPUT:392393See :meth:`HyperplaneArrangements._first_ngens`.394395EXAMPLES::396397sage: a.<x,y,z> = hyperplane_arrangements.braid(3) # indirect doctest398sage: (x, y) == a._first_ngens(2)399True400"""401return self.parent()._first_ngens(n)402403def __getitem__(self, i):404"""405Return the `i`-th hyperplane.406407INPUT:408409- ``i`` -- integer410411OUTPUT:412413The `i`-th hyperplane.414415EXAMPLES::416417sage: H.<x,y> = HyperplaneArrangements(QQ)418sage: h = x|y; h419Arrangement <y | x>420sage: h[0]421Hyperplane 0*x + y + 0422sage: h[1]423Hyperplane x + 0*y + 0424"""425return self._hyperplanes[i]426427def n_hyperplanes(self):428r"""429Return the number of hyperplanes in the arrangement.430431OUTPUT:432433An integer.434435EXAMPLES::436437sage: H.<x,y> = HyperplaneArrangements(QQ)438sage: A = H([1,1,0], [2,3,-1], [4,5,3])439sage: A.n_hyperplanes()4403441sage: len(A) # equivalent4423443"""444return len(self._hyperplanes)445446__len__ = n_hyperplanes447448def hyperplanes(self):449r"""450Return the number of hyperplanes in the arrangement.451452OUTPUT:453454An integer.455456EXAMPLES::457458sage: H.<x,y> = HyperplaneArrangements(QQ)459sage: A = H([1,1,0], [2,3,-1], [4,5,3])460sage: A.hyperplanes()461(Hyperplane x + 0*y + 1, Hyperplane 3*x - y + 2, Hyperplane 5*x + 3*y + 4)462463Note that the hyperplanes can be indexed as if they were a list::464465sage: A[0]466Hyperplane x + 0*y + 1467"""468return self._hyperplanes469470def _repr_(self):471r"""472String representation for a hyperplane arrangement.473474OUTPUT:475476A string.477478EXAMPLES::479480sage: H.<x,y> = HyperplaneArrangements(QQ)481sage: H(x, y, x-1, y-1)482Arrangement <y - 1 | y | x - 1 | x>483sage: x | y | x - 1 | y - 1 | x + y | x - y484Arrangement of 6 hyperplanes of dimension 2 and rank 2485sage: H()486Empty hyperplane arrangement of dimension 2487"""488if len(self) == 0:489return 'Empty hyperplane arrangement of dimension {0}'.format(self.dimension())490elif len(self) < 5:491hyperplanes = ' | '.join(h._repr_linear(include_zero=False) for h in self._hyperplanes)492return 'Arrangement <{0}>'.format(hyperplanes)493return 'Arrangement of {0} hyperplanes of dimension {1} and rank {2}'.format(494len(self), self.dimension(), self.rank())495496def dimension(self):497"""498Return the ambient space dimension of the arrangement.499500OUTPUT:501502An integer.503504EXAMPLES::505506sage: H.<x,y> = HyperplaneArrangements(QQ)507sage: (x | x-1 | x+1).dimension()5082509sage: H(x).dimension()5102511"""512return self.parent().ngens()513514def rank(self):515"""516Return the rank.517518OUTPUT:519520The dimension of the span of the normals to the521hyperplanes in the arrangement.522523EXAMPLES::524525sage: H.<x,y,z> = HyperplaneArrangements(QQ)526sage: A = H([[0, 1, 2, 3],[-3, 4, 5, 6]])527sage: A.dimension()5283529sage: A.rank()5302531532sage: B = hyperplane_arrangements.braid(3)533sage: B.hyperplanes()534(Hyperplane 0*t0 + t1 - t2 + 0,535Hyperplane t0 - t1 + 0*t2 + 0,536Hyperplane t0 + 0*t1 - t2 + 0)537sage: B.dimension()5383539sage: B.rank()5402541542sage: p = polytopes.n_simplex(5)543sage: H = p.hyperplane_arrangement()544sage: H.rank()5455546"""547R = self.parent().base_ring()548normals = [h.normal() for h in self]549return matrix(R, normals).rank()550551def __cmp__(self, other):552"""553Compare two hyperplane arrangements.554555EXAMPLES::556557sage: H.<x,y,z> = HyperplaneArrangements(QQ)558sage: H(x) == H(y)559False560sage: H(x) == 0561False562"""563assert (type(self) is type(other)) and (self.parent() is other.parent()) # guaranteed by framework564return cmp(self._hyperplanes, other._hyperplanes)565566def union(self, other):567r"""568The union of ``self`` with ``other``.569570INPUT:571572- ``other`` -- a hyperplane arrangement or something that can573be converted into a hyperplane arrangement574575OUTPUT:576577A new hyperplane arrangement.578579EXAMPLES::580581sage: H.<x,y> = HyperplaneArrangements(QQ)582sage: A = H([1,2,3], [0,1,1], [0,1,-1], [1,-1,0], [1,1,0])583sage: B = H([1,1,1], [1,-1,1], [1,0,-1])584sage: A.union(B)585Arrangement of 8 hyperplanes of dimension 2 and rank 2586sage: A | B # syntactic sugar587Arrangement of 8 hyperplanes of dimension 2 and rank 2588589A single hyperplane is coerced into a hyperplane arrangement590if necessary::591592sage: A.union(x+y-1)593Arrangement of 6 hyperplanes of dimension 2 and rank 2594sage: A.add_hyperplane(x+y-1) # alias595Arrangement of 6 hyperplanes of dimension 2 and rank 2596597sage: P.<x,y> = HyperplaneArrangements(RR)598sage: C = P(2*x + 4*y + 5)599sage: C.union(A)600Arrangement of 6 hyperplanes of dimension 2 and rank 2601"""602P = self.parent()603other = P(other)604hyperplanes = self._hyperplanes + other._hyperplanes605return P(*hyperplanes)606607add_hyperplane = union608609__or__ = union610611def plot(self, **kwds):612"""613Plot the hyperplane arrangement.614615OUTPUT:616617A graphics object.618619EXAMPLES::620621sage: L.<x, y> = HyperplaneArrangements(QQ)622sage: L(x, y, x+y-2).plot()623"""624from sage.geometry.hyperplane_arrangement.plot import plot625return plot(self, **kwds)626627def cone(self, variable='t'):628r"""629Return the cone over the hyperplane arrangement.630631INPUT:632633- ``variable`` -- string; the name of the additional variable634635OUTPUT:636637A new yperplane arrangement. Its equations consist of638`[0, -d, a_1, \ldots, a_n]` for each `[d, a_1, \ldots, a_n]` in the639original arrangement and the equation `[0, 1, 0, \ldots, 0]`.640641EXAMPLES::642643sage: a.<x,y,z> = hyperplane_arrangements.semiorder(3)644sage: b = a.cone()645sage: a.characteristic_polynomial().factor()646x * (x^2 - 6*x + 12)647sage: b.characteristic_polynomial().factor()648(x - 1) * x * (x^2 - 6*x + 12)649sage: a.hyperplanes()650(Hyperplane 0*x + y - z - 1,651Hyperplane 0*x + y - z + 1,652Hyperplane x - y + 0*z - 1,653Hyperplane x - y + 0*z + 1,654Hyperplane x + 0*y - z - 1,655Hyperplane x + 0*y - z + 1)656sage: b.hyperplanes()657(Hyperplane -t + 0*x + y - z + 0,658Hyperplane -t + x - y + 0*z + 0,659Hyperplane -t + x + 0*y - z + 0,660Hyperplane t + 0*x + 0*y + 0*z + 0,661Hyperplane t + 0*x + y - z + 0,662Hyperplane t + x - y + 0*z + 0,663Hyperplane t + x + 0*y - z + 0)664"""665hyperplanes = []666for h in self.hyperplanes():667new_h = [0] + [h.b()] + list(h.A())668hyperplanes.append(new_h)669hyperplanes.append([0, 1] + [0] * self.dimension())670P = self.parent()671names = (variable,) + P._names672H = HyperplaneArrangements(self.parent().base_ring(), names=names)673return H(*hyperplanes)674675@cached_method676def intersection_poset(self):677r"""678Return the intersection poset of the hyperplane arrangement.679680OUTPUT:681682The poset of non-empty intersections of hyperplanes.683684EXAMPLES::685686sage: a = hyperplane_arrangements.coordinate(2)687sage: a.intersection_poset()688Finite poset containing 4 elements689690sage: A = hyperplane_arrangements.semiorder(3)691sage: A.intersection_poset()692Finite poset containing 19 elements693"""694K = self.base_ring()695from sage.geometry.hyperplane_arrangement.affine_subspace import AffineSubspace696from sage.modules.all import VectorSpace697whole_space = AffineSubspace(0, VectorSpace(K, self.dimension()))698L = [[whole_space]]699active = True700codim = 0701while active:702active = False703new_level = []704for T in L[codim]:705for H in self:706I = H._affine_subspace().intersection(T)707if I is not None and I != T and I not in new_level:708new_level.append(I)709active = True710if active:711L.append(new_level)712codim += 1713from sage.misc.flatten import flatten714L = flatten(L)715t = {}716for i in range(len(L)):717t[i] = L[i]718cmp_fn = lambda p, q: t[q] < t[p]719from sage.combinat.posets.posets import Poset720return Poset((t, cmp_fn))721722def _slow_characteristic_polynomial(self):723"""724Return the characteristic polynomial of the hyperplane arrangement.725726This is the slow computation directly from the definition. For727educational use only.728729EXAMPLES::730731sage: a = hyperplane_arrangements.coordinate(2)732sage: a._slow_characteristic_polynomial()733x^2 - 2*x + 1734"""735from sage.rings.polynomial.polynomial_ring import polygen736x = polygen(QQ, 'x')737P = self.intersection_poset()738n = self.dimension()739return sum([P.mobius_function(0, p) * x**(n - P.rank(p)) for p in P])740741@cached_method742def characteristic_polynomial(self):743r"""744Return the characteristic polynomial of the hyperplane arrangement.745746OUTPUT:747748The characteristic polynomial in `\QQ[x]`.749750EXAMPLES::751752sage: a = hyperplane_arrangements.coordinate(2)753sage: a.characteristic_polynomial()754x^2 - 2*x + 1755756TESTS::757758sage: H.<s,t,u,v> = HyperplaneArrangements(QQ)759sage: m = matrix([(0, -1, 0, 1, -1), (0, -1, 1, -1, 0), (0, -1, 1, 0, -1),760....: (0, 1, 0, 0, 0), (0, 1, 0, 1, -1), (0, 1, 1, -1, 0), (0, 1, 1, 0, -1)])761sage: R.<x> = QQ[]762sage: expected_charpoly = (x - 1) * x * (x^2 - 6*x + 12)763sage: for s in SymmetricGroup(4): # long time (about a second on a Core i7)764....: m_perm = [m.column(i) for i in [0, s(1), s(2), s(3), s(4)]]765....: m_perm = matrix(m_perm).transpose()766....: charpoly = H(m_perm.rows()).characteristic_polynomial()767....: assert charpoly == expected_charpoly768"""769from sage.rings.polynomial.polynomial_ring import polygen770x = polygen(QQ, 'x')771if self.rank() == 1:772return x**(self.dimension() - 1) * (x - len(self))773774H = self[0]775R = self.restriction(H)776charpoly_R = R.characteristic_polynomial()777D = self.deletion(H)778charpoly_D = D.characteristic_polynomial()779return charpoly_D - charpoly_R780781@cached_method782def poincare_polynomial(self):783r"""784Return the Poincare polynomial of the hyperplane arrangement.785786OUTPUT:787788The Poincare polynomial in `\QQ[x]`.789790EXAMPLES::791792sage: a = hyperplane_arrangements.coordinate(2)793sage: a.poincare_polynomial()794x^2 + 2*x + 1795"""796charpoly = self.characteristic_polynomial()797R = charpoly.parent()798x = R.gen(0)799poincare = (-x)**self.dimension() * charpoly(-QQ(1)/x)800return R(poincare)801802def deletion(self, hyperplanes):803r"""804Return the hyperplane arrangement obtained by removing ``h``.805806INPUT:807808- ``h`` -- a hyperplane or hyperplane arrangement809810OUTPUT:811812A new hyperplane arrangement with the given hyperplane(s)813``h`` removed.814815.. SEEALSO::816817:meth:`restriction`818819EXAMPLES::820821sage: H.<x,y> = HyperplaneArrangements(QQ)822sage: A = H([0,1,0], [1,0,1], [-1,0,1], [0,1,-1], [0,1,1]); A823Arrangement of 5 hyperplanes of dimension 2 and rank 2824sage: A.deletion(x)825Arrangement <y - 1 | y + 1 | x - y | x + y>826sage: h = H([0,1,0], [0,1,1])827sage: A.deletion(h)828Arrangement <y - 1 | y + 1 | x - y>829830TESTS::831832sage: H.<x,y> = HyperplaneArrangements(QQ)833sage: A = H([0,1,0], [1,0,1], [-1,0,1], [0,1,-1], [0,1,1])834sage: h = H([0,4,0])835sage: A.deletion(h)836Arrangement <y - 1 | y + 1 | x - y | x + y>837sage: l = H([1,2,3])838sage: A.deletion(l)839Traceback (most recent call last):840...841ValueError: hyperplane is not in the arrangement842"""843parent = self.parent()844hyperplanes = parent(hyperplanes)845planes = list(self)846for hyperplane in hyperplanes:847try:848planes.remove(hyperplane)849except ValueError:850raise ValueError('hyperplane is not in the arrangement')851return parent(*planes)852853def restriction(self, hyperplane):854r"""855Return the restriction to a hyperplane.856857INPUT:858859- ``hyperplane`` -- a hyperplane of the hyperplane arrangement860861OUTPUT:862863The restriction of the hyperplane arrangement to the given864``hyperplane``.865866EXAMPLES::867868sage: A.<u,x,y,z> = hyperplane_arrangements.braid(4); A869Arrangement of 6 hyperplanes of dimension 4 and rank 3870sage: H = A[0]; H871Hyperplane 0*u + 0*x + y - z + 0872sage: R = A.restriction(H); R873Arrangement <x - z | u - x | u - z>874sage: D = A.deletion(H); D875Arrangement of 5 hyperplanes of dimension 4 and rank 3876sage: ca = A.characteristic_polynomial()877sage: cr = R.characteristic_polynomial()878sage: cd = D.characteristic_polynomial()879sage: ca880x^4 - 6*x^3 + 11*x^2 - 6*x881sage: cd - cr882x^4 - 6*x^3 + 11*x^2 - 6*x883884.. SEEALSO::885886:meth:`deletion`887"""888parent = self.parent()889hyperplane = parent(hyperplane)[0]890if hyperplane not in self.hyperplanes():891raise ValueError('hyperplane not in arrangement')892pivot = hyperplane._normal_pivot()893hyperplanes = []894for h in self:895rescale = h.A()[pivot] / hyperplane.A()[pivot]896h = h - rescale * hyperplane897A = list(h.A())898A_pivot = A.pop(pivot)899assert A_pivot == 0900if all(a == 0 for a in A):901continue902b = h.b()903hyperplanes.append([A, b])904names = list(parent._names)905names.pop(pivot)906H = HyperplaneArrangements(parent.base_ring(), names=tuple(names))907return H(*hyperplanes, signed=False)908909def change_ring(self, base_ring):910"""911Return hyperplane arrangement over the new base ring.912913INPUT:914915- ``base_ring`` -- the new base ring; must be a field for916hyperplane arrangements917918OUTPUT:919920The hyperplane arrangement obtained by changing the base921field, as a new hyperplane arrangement.922923EXAMPLES::924925sage: H.<x,y> = HyperplaneArrangements(QQ)926sage: A = H([(1,1), 0], [(2,3), -1])927sage: A.change_ring(FiniteField(2))928Arrangement <y + 1 | x + y>929"""930parent = self.parent().change_ring(base_ring)931return parent(self)932933@cached_method934def n_regions(self):935r"""936The number of regions of the hyperplane arrangement.937938OUTPUT:939940An integer.941942EXAMPLES::943944sage: A = hyperplane_arrangements.semiorder(3)945sage: A.n_regions()94619947948TESTS::949950sage: H.<x,y> = HyperplaneArrangements(QQ)951sage: A = H([(1,1), 0], [(2,3), -1], [(4,5), 3])952sage: B = A.change_ring(FiniteField(7))953sage: B.n_regions()954Traceback (most recent call last):955...956TypeError: base field must have characteristic zero957"""958if self.base_ring().characteristic() != 0:959raise TypeError('base field must have characteristic zero')960charpoly = self.characteristic_polynomial()961return (-1)**self.dimension() * charpoly(-1)962963@cached_method964def n_bounded_regions(self):965r"""966Return the number of (relatively) bounded regions.967968OUTPUT:969970An integer. The number of relatively bounded regions of the971hyperplane arrangement.972973EXAMPLES::974975sage: A = hyperplane_arrangements.semiorder(3)976sage: A.n_bounded_regions()9777978979TESTS::980981sage: H.<x,y> = HyperplaneArrangements(QQ)982sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3])983sage: B = A.change_ring(FiniteField(7))984sage: B.n_bounded_regions()985Traceback (most recent call last):986...987TypeError: base field must have characteristic zero988"""989if self.base_ring().characteristic() != 0:990raise TypeError('base field must have characteristic zero')991charpoly = self.characteristic_polynomial()992return (-1)**self.rank() * charpoly(1)993994def has_good_reduction(self, p):995r"""996Return whether the hyperplane arrangement has good reduction mod `p`.997998Let `A` be a hyperplane arrangement with equations defined999over the integers, and let `B` be the hyperplane arrangement1000defined by reducing these equations modulo a prime `p`. Then1001`A` has good reduction modulo `p` if the intersection posets1002of `A` and `B` are isomorphic.10031004INPUT:10051006- ``p`` -- prime number10071008OUTPUT:10091010A boolean.10111012EXAMPLES::10131014sage: a = hyperplane_arrangements.semiorder(3)1015sage: a.has_good_reduction(5)1016True1017sage: a.has_good_reduction(3)1018False1019sage: b = a.change_ring(GF(3))1020sage: a.characteristic_polynomial()1021x^3 - 6*x^2 + 12*x1022sage: b.characteristic_polynomial() # not equal to that for a1023x^3 - 6*x^2 + 10*x1024"""1025if self.base_ring() != QQ:1026raise TypeError('arrangement must be defined over QQ')1027if not p.is_prime():1028raise TypeError('must reduce modulo a prime number')1029from sage.rings.all import GF1030a = self.change_ring(GF(p))1031p = self.intersection_poset()1032q = a.intersection_poset()1033return p.is_isomorphic(q)10341035def is_linear(self):1036r"""1037Test whether all hyperplanes pass through the origin.10381039OUTPUT:10401041A boolean. Whether all the hyperplanes pass through the origin.10421043EXAMPLES::10441045sage: a = hyperplane_arrangements.semiorder(3)1046sage: a.is_linear()1047False1048sage: b = hyperplane_arrangements.braid(3)1049sage: b.is_linear()1050True10511052sage: H.<x,y> = HyperplaneArrangements(QQ)1053sage: c = H(x+1, y+1)1054sage: c.is_linear()1055False1056sage: c.is_central()1057True1058"""1059return all(hyperplane.b() == 0 for hyperplane in self)10601061def is_essential(self):1062r"""1063Test whether the hyperplane arrangement is essential.10641065A hyperplane arrangement is essential if the span of the normals1066of its hyperplanes spans the ambient space.10671068.. SEEALSO::10691070:meth:`essentialization`10711072OUTPUT:10731074A boolean indicating whether the hyperplane arrangement is essential.10751076EXAMPLES::10771078sage: H.<x,y> = HyperplaneArrangements(QQ)1079sage: H(x, x+1).is_essential()1080False1081sage: H(x, y).is_essential()1082True1083"""1084return self.rank() == self.dimension()10851086@cached_method1087def is_central(self):1088r"""1089Test whether the intersection of all the hyperplanes is nonempty.10901091OUTPUT:10921093A boolean whether the hyperplane arrangement is such that the1094intersection of all the hyperplanes in the arrangement is1095nonempty.10961097EXAMPLES::10981099sage: a = hyperplane_arrangements.braid(2)1100sage: a.is_central()1101True1102"""1103R = self.base_ring()1104m = matrix(R, [h.normal() for h in self])1105b = vector(R, [h.b() for h in self])1106try:1107m.solve_right(b)1108return True1109except ValueError:1110return False11111112@cached_method1113def essentialization(self):1114r"""1115Return the essentialization of the hyperplane arrangement.11161117The essentialization of a hyperplane arrangement whose base field1118has characteristic 0 is obtained by intersecting the hyperplanes by1119the space spanned by their normal vectors.11201121OUTPUT:11221123The essentialization as a new hyperplane arrangement.11241125EXAMPLES::11261127sage: a = hyperplane_arrangements.braid(3)1128sage: a.is_essential()1129False1130sage: a.essentialization()1131Arrangement <t1 - t2 | t1 + 2*t2 | 2*t1 + t2>11321133sage: H.<x,y> = HyperplaneArrangements(QQ)1134sage: B = H([(1,0),1], [(1,0),-1])1135sage: B.is_essential()1136False1137sage: B.essentialization()1138Arrangement <-x + 1 | x + 1>1139sage: B.essentialization().parent()1140Hyperplane arrangements in 1-dimensional linear space over1141Rational Field with coordinate x11421143sage: H.<x,y> = HyperplaneArrangements(GF(2))1144sage: C = H([(1,1),1], [(1,1),0])1145sage: C.essentialization()1146Arrangement <y | y + 1>11471148sage: h = hyperplane_arrangements.semiorder(4)1149sage: h.essentialization()1150Arrangement of 12 hyperplanes of dimension 3 and rank 311511152TESTS::11531154sage: b = hyperplane_arrangements.coordinate(2)1155sage: b.is_essential()1156True1157sage: b.essentialization() is b1158True1159"""1160def echelon_col_iter(row_iter):1161"""helper to iterat over the echelon pivot column indices"""1162for row in row_iter:1163if row == 0:1164raise StopIteration1165for pivot in range(self.dimension()):1166if row[pivot] != 0:1167break1168assert row[pivot] == 11169yield pivot, row11701171if self.is_essential():1172return self1173parent = self.parent()1174H = parent.ambient_space()1175R = parent.base_ring()1176hyperplanes = self.hyperplanes()1177normals = matrix(R, [h.normal() for h in self]).transpose()1178# find a (any) complement to the normals1179if R.characteristic() == 0:1180complement_basis = normals.kernel().echelonized_basis()1181else:1182# we don't necessarily have an orthogonal complement, pick any complement1183complement_basis = []1184for pivot, row in echelon_col_iter(normals.echelon_form().rows()):1185v = [0] * self.dimension()1186v[pivot] = 11187complement_basis.append(vector(R, v))1188# reduce the hyperplane equations1189echelon_pivots = [] # the column indices where N has 1's from the echelonization1190for pivot, row in echelon_col_iter(complement_basis):1191assert row[pivot] == 11192echelon_pivots.append(pivot)1193hyperplanes = [h - h.A()[pivot] * H(row, 0) for h in hyperplanes]1194# eliminate the pivot'ed coodinates1195restricted = []1196for h in hyperplanes:1197A = h.A()1198if A == 0:1199continue1200A = [A[i] for i in range(self.dimension()) if i not in echelon_pivots]1201b = h.b()1202restricted.append([A, b])1203names = tuple(name for i, name in enumerate(parent._names) if i not in echelon_pivots)1204# Construct the result1205restricted_parent = HyperplaneArrangements(R, names=names)1206return restricted_parent(*restricted, signed=False)12071208def sign_vector(self, p):1209r"""1210Indicates on which side of each hyperplane the given1211point `p` lies.12121213The base field must have characteristic zero.12141215INPUT:12161217- ``p`` -- point as a list/tuple/iterable12181219OUTPUT:12201221A vector whose entries are in `[-1, 0, +1]`.12221223EXAMPLES::12241225sage: H.<x,y> = HyperplaneArrangements(QQ)1226sage: A = H([(1,0), 0], [(0,1), 1]); A1227Arrangement <y + 1 | x>1228sage: A.sign_vector([2, -2])1229(-1, 1)1230sage: A.sign_vector((-1, -1))1231(0, -1)12321233TESTS::12341235sage: H.<x,y> = HyperplaneArrangements(GF(3))1236sage: A = H(x, y)1237sage: A.sign_vector([1, 2])1238Traceback (most recent call last):1239...1240ValueError: characteristic must be zero1241"""1242if self.base_ring().characteristic() != 0:1243raise ValueError('characteristic must be zero')1244from sage.functions.generalized import sign1245values = [hyperplane(p) for hyperplane in self]1246signs = vector(ZZ, map(sign, values))1247signs.set_immutable()1248return signs12491250def face_vector(self):1251r"""1252Return the face vector.12531254OUTPUT:12551256A vector of integers.12571258The `d`-th entry is the number of faces of dimension `d`. A1259*face* is is the intersection of a region with a hyperplane of1260the arrangehment.12611262EXAMPLES::12631264sage: A = hyperplane_arrangements.Shi(3)1265sage: A.face_vector()1266(0, 6, 21, 16)1267"""1268m = self.whitney_data()[0]1269v = list(sum(m.transpose().apply_map(abs)))1270v.reverse()1271v = vector(ZZ, [0]*(self.dimension() - self.rank()) + v)1272v.set_immutable()1273return v12741275@cached_method1276def _parallel_hyperplanes(self):1277"""1278Return the hyperplanes grouped into parallel sets.12791280OUTPUT:12811282A tuple with one entry per set of parallel hyperplanes. Each1283entry is a tuple of triples, one for each parallel hyperplane1284in the parallel set. The triple consists of the hyperplane,1285the normal vector `A`, and the constant `b` of the hyperplane1286equation `Ax+b`. The normalization is such that `A` is the1287same for each hyperplane of the parallel set, and the order is1288in increasing order of the `b` values.12891290In other words, each parallel set of hyperplanes is also1291ordered by the order with which a common normal passes through1292them.12931294EXAMPLES::12951296sage: H.<x,y> = HyperplaneArrangements(QQ)1297sage: h = (x + 2*y | 2*x + 4*y + 1 | -x/4 - y/2 + 1); h1298Arrangement <-x - 2*y + 4 | x + 2*y | 2*x + 4*y + 1>1299sage: h._parallel_hyperplanes()[0]1300((Hyperplane -x - 2*y + 4, (1, 2), -4),1301(Hyperplane x + 2*y + 0, (1, 2), 0),1302(Hyperplane 2*x + 4*y + 1, (1, 2), 1/2))13031304sage: hyperplane_arrangements.Shi(3)._parallel_hyperplanes()1305(((Hyperplane 0*t0 + t1 - t2 - 1, (0, 1, -1), -1),1306(Hyperplane 0*t0 + t1 - t2 + 0, (0, 1, -1), 0)),1307((Hyperplane t0 - t1 + 0*t2 - 1, (1, -1, 0), -1),1308(Hyperplane t0 - t1 + 0*t2 + 0, (1, -1, 0), 0)),1309((Hyperplane t0 + 0*t1 - t2 - 1, (1, 0, -1), -1),1310(Hyperplane t0 + 0*t1 - t2 + 0, (1, 0, -1), 0)))1311"""1312V = self.parent().ambient_space()1313parallels = dict()1314for hyperplane in self:1315through_origin = V([list(hyperplane.A()), 0]).primitive(signed=False)1316parallel_planes = parallels.get(through_origin, [])1317A = through_origin.A()1318b = hyperplane.b() * (A / hyperplane.A())1319parallel_planes.append([b, (hyperplane, A, b)])1320parallels[through_origin] = parallel_planes1321parallels = [tuple(tuple(hyperplane[1]1322for hyperplane in sorted(parallels[key])))1323for key in parallels.keys()]1324return tuple(sorted(parallels))13251326def vertices(self, exclude_sandwiched=False):1327"""1328Return the vertices.13291330The vertices are the zero-dimensional faces, see1331:meth:`face_vector`.13321333INPUT:13341335- ``exclude_sandwiched`` -- boolean (default:1336``False``). Whether to exclude hyperplanes that are1337sandwiched between parallel hyperplanes. Useful if you only1338need the convex hull.13391340OUTPUT:13411342The vertices in a sorted tuple. Each vertex is returned as a1343vector in the ambient vector space.13441345EXAMPLES::13461347sage: A = hyperplane_arrangements.Shi(3).essentialization()1348sage: A.dimension()134921350sage: A.face_vector()1351(6, 21, 16)1352sage: A.vertices()1353((-2/3, 1/3), (-1/3, -1/3), (0, -1), (0, 0), (1/3, -2/3), (2/3, -1/3))1354sage: point2d(A.vertices(), size=20) + A.plot()13551356sage: H.<x,y> = HyperplaneArrangements(QQ)1357sage: chessboard = []1358sage: N = 81359sage: for x0, y0 in CartesianProduct(range(N+1), range(N+1)):1360....: chessboard.extend([x-x0, y-y0])1361sage: chessboard = H(chessboard)1362sage: len(chessboard.vertices())1363811364sage: chessboard.vertices(exclude_sandwiched=True)1365((0, 0), (0, 8), (8, 0), (8, 8))1366"""1367from sage.matroids.all import Matroid1368from sage.combinat.cartesian_product import CartesianProduct1369R = self.parent().base_ring()1370parallels = self._parallel_hyperplanes()1371A_list = [parallel[0][1] for parallel in parallels]1372b_list_list = [[-hyperplane[2] for hyperplane in parallel]1373for parallel in parallels]1374if exclude_sandwiched:1375def skip(b_list):1376if len(b_list) == 1:1377return b_list1378return [b_list[0], b_list[-1]]1379b_list_list = map(skip, b_list_list)1380M = Matroid(groundset=range(len(parallels)), matrix=matrix(A_list).transpose())1381d = self.dimension()1382# vertices are solutions v * lhs = rhs1383lhs = matrix(R, d, d)1384rhs = vector(R, d)1385vertices = set()1386for indices in M.independent_r_sets(d):1387for row, i in enumerate(indices):1388lhs[row] = A_list[i]1389b_list = [b_list_list[i] for i in indices]1390for b in CartesianProduct(*b_list):1391for i in range(d):1392rhs[i] = b[i]1393vertex = lhs.solve_right(rhs)1394vertex.set_immutable()1395vertices.add(vertex)1396return tuple(sorted(vertices))13971398def _make_region(self, hyperplanes):1399"""1400Helper method to construct a region.14011402INPUT:14031404- ``hyperplanes`` -- a list/tuple/iterable of hyperplanes14051406OUTPUT:14071408The polyhedron constructed from taking the linear expressions1409as inequalities.14101411EXAMPLES::14121413sage: H.<x,y> = HyperplaneArrangements(QQ)1414sage: h = H(x)1415sage: h._make_region([x, 1-x, y, 1-y])1416A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices1417"""1418ieqs = [h.coefficients() for h in hyperplanes]1419from sage.geometry.polyhedron.constructor import Polyhedron1420return Polyhedron(ieqs=ieqs, ambient_dim=self.dimension(),1421base_ring=self.parent().base_ring())14221423@cached_method1424def regions(self):1425r"""1426Return the regions of the hyperplane arrangement.14271428The base field must have characteristic zero.14291430OUTPUT:14311432A tuple containing the regions as polyhedra.14331434The regions are the connected components of the complement of1435the union of the hyperplanes as a subset of `\RR^n`.14361437EXAMPLES::14381439sage: a = hyperplane_arrangements.braid(2)1440sage: a.regions()1441(A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line,1442A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line)14431444sage: H.<x,y> = HyperplaneArrangements(QQ)1445sage: A = H(x, y+1)1446sage: A.regions()1447(A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1448A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1449A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1450A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays)14511452sage: chessboard = []1453sage: N = 81454sage: for x0, y0 in CartesianProduct(range(N+1), range(N+1)):1455....: chessboard.extend([x-x0, y-y0])1456sage: chessboard = H(chessboard)1457sage: len(chessboard.bounded_regions()) # long time, 359 ms on a Core i71458641459"""1460if self.base_ring().characteristic() != 0:1461raise ValueError('base field must have characteristic zero')1462from sage.geometry.polyhedron.constructor import Polyhedron1463R = self.base_ring()1464dim = self.dimension()1465universe = Polyhedron(eqns=[[0] + [0] * dim], base_ring=R)1466regions = [universe]1467for hyperplane in self:1468ieq = vector(R, hyperplane.coefficients())1469pos_half = Polyhedron(ieqs=[ ieq], base_ring=R)1470neg_half = Polyhedron(ieqs=[-ieq], base_ring=R)1471subdivided = []1472for region in regions:1473for half_space in pos_half, neg_half:1474part = region.intersection(half_space)1475if part.dim() == dim:1476subdivided.append(part)1477regions = subdivided1478return tuple(regions)14791480def region_containing_point(self, p):1481r"""1482The region in the hyperplane arrangement containing a given point.14831484The base field must have characteristic zero.14851486INPUT:14871488- ``p`` -- point14891490OUTPUT:14911492A polyhedron. A ``ValueError`` is raised if the point is not1493interior to a region, that is, sits on a hyperplane.14941495EXAMPLES::14961497sage: H.<x,y> = HyperplaneArrangements(QQ)1498sage: A = H([(1,0), 0], [(0,1), 1], [(0,1), -1], [(1,-1), 0], [(1,1), 0])1499sage: A.region_containing_point([1,2])1500A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays15011502TESTS::15031504sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3])1505sage: B = A.change_ring(FiniteField(7))1506sage: B.region_containing_point((1,2))1507Traceback (most recent call last):1508...1509ValueError: base field must have characteristic zero15101511sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3])1512sage: A.region_containing_point((1,-1))1513Traceback (most recent call last):1514...1515ValueError: point sits on a hyperplane1516"""1517if self.base_ring().characteristic() != 0:1518raise ValueError('base field must have characteristic zero')1519sign_vector = self.sign_vector(p)1520ieqs = []1521for i, hyperplane in enumerate(self):1522sign = sign_vector[i]1523if sign == 1:1524ieqs.append(hyperplane)1525elif sign == -1:1526ieqs.append(-hyperplane)1527else:1528assert sign == 01529raise ValueError('point sits on a hyperplane')1530return self._make_region(ieqs)15311532@cached_method1533def _bounded_region_indices(self):1534r"""1535Return the relatively bounded regions.15361537OUTPUT:15381539Tuple of integers. The positions of the relatively bounded1540regions in :meth:`regions`.15411542EXAMPLES::15431544sage: a = hyperplane_arrangements.semiorder(3)1545sage: a._bounded_region_indices()1546(2, 7, 8, 9, 10, 11, 16)1547"""1548from sage.geometry.polyhedron.constructor import Polyhedron1549normal = Polyhedron(vertices=[[0]*self.dimension()],1550lines=[hyperplane.normal() for hyperplane in self])1551if normal.dim() == 0:1552transverse = lambda poly: poly1553else:1554transverse = lambda poly: poly.intersection(normal)1555return tuple(i for i, region in enumerate(self.regions())1556if transverse(region).is_compact())15571558def bounded_regions(self):1559r"""1560Return the relatively bounded regions of the arrangement.15611562A region is relatively bounded if its intersection with the space1563spanned by the normals to the hyperplanes is bounded. This is the1564same as being bounded in the case that the hyperplane arrangement1565is essential. It is assumed that the arrangement is defined over1566the rationals.15671568OUTPUT:15691570Tuple of polyhedra. The relatively bounded regions of the1571arrangement.15721573.. SEEALSO::15741575:meth:`unbounded_regions`15761577EXAMPLES::15781579sage: A = hyperplane_arrangements.semiorder(3)1580sage: A.bounded_regions()1581(A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line,1582A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line,1583A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line,1584A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices and 1 line,1585A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line,1586A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line,1587A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line)1588sage: A.bounded_regions()[0].is_compact() # the regions are only *relatively* bounded1589False1590sage: A.is_essential()1591False1592"""1593return tuple(self.regions()[i] for i in self._bounded_region_indices())15941595def unbounded_regions(self):1596r"""1597Return the relatively bounded regions of the arrangement.15981599OUTPUT:16001601Tuple of polyhedra. The regions of the arrangement that are not1602relatively bounded. It is assumed that the arrangement is1603defined over the rationals.16041605.. SEEALSO::16061607:meth:`bounded_regions`16081609EXAMPLES::16101611sage: A = hyperplane_arrangements.semiorder(3)1612sage: B = A.essentialization()1613sage: B.n_regions() - B.n_bounded_regions()1614121615sage: B.unbounded_regions()1616(A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,1617A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,1618A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1619A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,1620A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1621A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,1622A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1623A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,1624A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1625A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray,1626A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays,1627A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays)1628"""1629s = set(range(self.n_regions())).difference(set(self._bounded_region_indices()))1630return tuple(self.regions()[i] for i in s)16311632@cached_method1633def whitney_data(self):1634r"""1635Return the Whitney numbers.16361637.. SEEALSO::16381639:meth:`whitney_number`,1640:meth:`doubly_indexed_whitney_number`16411642OUTPUT:16431644A pair of integer matrices. The two matrices are the1645doubly-indexed Whitney numbers of the first or second kind,1646respectively. The `i,j`-th entry is the `i,j`-th1647doubly-indexed Whitney number.16481649EXAMPLES::16501651sage: A = hyperplane_arrangements.Shi(3)1652sage: A.whitney_data()1653(1654[ 1 -6 9] [ 1 6 6]1655[ 0 6 -15] [ 0 6 15]1656[ 0 0 6], [ 0 0 6]1657)1658"""1659p = self.intersection_poset()1660r = p.rank_function()1661top = r(p.maximal_elements()[0])1662from sage.matrix.constructor import zero_matrix1663m1 = zero_matrix(ZZ, top+1, top+1)1664m2 = zero_matrix(ZZ, top+1, top+1)1665for i, j in p.relations_iterator():1666m1[r(i), r(j)] += p.mobius_function(i, j)1667m2[r(i), r(j)] += 11668m1.set_immutable()1669m2.set_immutable()1670return (m1, m2)16711672def doubly_indexed_whitney_number(self, i, j, kind=1):1673r"""1674Return the `i,j`-th doubly-indexed Whitney number.16751676If ``kind=1``, this number is obtained by adding the Moebius function1677values `mu(x,y)` over all `x, y` in the intersection poset with1678`\mathrm{rank}(x) = i` and `\mathrm{rank}(y) = j`.16791680If `kind=2`, this number is the number of elements `x,y` in the1681intersection poset such that `x \leq y` with ranks `i` and `j`,1682respectively.16831684INPUT:16851686- ``i``, ``j`` -- integers16871688- ``kind`` -- (default: 1) 1 or 216891690OUTPUT:16911692Integer. The `(i,j)`-th entry of the ``kind`` Whitney number.16931694.. SEEALSO::16951696:meth:`whitney_number`,1697:meth:`whitney_data`16981699EXAMPLES::17001701sage: A = hyperplane_arrangements.Shi(3)1702sage: A.doubly_indexed_whitney_number(0, 2)170391704sage: A.whitney_number(2)170591706sage: A.doubly_indexed_whitney_number(1, 2)1707-1517081709REFERENCES:17101711.. [GZ] Greene; Zaslavsky1712"On the Interpretation of Whitney Numbers Through Arrangements of1713Hyperplanes, Zonotopes, Non-Radon Partitions, and Orientations of1714Graphs"1715Transactions of the American Mathematical Society, Vol. 280, No. 1.1716(Nov., 1983), pp. 97-126.1717"""1718if 0 <= i and j <= self.dimension():1719if kind == 1:1720return self.whitney_data()[0][i, j]1721elif kind == 2:1722return self.whitney_data()[1][i, j]1723raise ValueError('argument out of range')17241725def whitney_number(self, k, kind=1):1726r"""1727Return the ``k``-th Whitney number.17281729If ``kind=1``, this number is obtained by summing the Moebius function1730values `mu(0, x)` over all `x` in the intersection poset with1731`\mathrm{rank}(x) = k`.17321733If ``kind=2``, this number is the number of elements `x, y` in the1734intersection poset such that `x \leq y` with ranks `i` and `j`,1735respectively.17361737See [GZ]_ for more details.17381739INPUT:17401741- ``k`` -- integer17421743- ``kind`` -- 1 or 2 (default: 1)17441745OUTPUT:17461747Integer. The ``k``-th Whitney number.17481749.. SEEALSO::17501751:meth:`doubly_indexed_whitney_number`1752:meth:`whitney_data`17531754EXAMPLES::17551756sage: A = hyperplane_arrangements.Shi(3)1757sage: A.whitney_number(0)175811759sage: A.whitney_number(1)1760-61761sage: A.whitney_number(2)176291763sage: A.characteristic_polynomial()1764x^3 - 6*x^2 + 9*x1765sage: A.whitney_number(1,kind=2)176661767sage: p = A.intersection_poset()1768sage: r = p.rank_function()1769sage: len([i for i in p if r(i) == 1])177061771"""1772if k >= 0 and k <= self.dimension():1773if kind == 1:1774return self.whitney_data()[0][0, k]1775elif kind == 2:1776return self.whitney_data()[1][0, k]1777raise ValueError('argument out of range')17781779def is_separating_hyperplane(self, region1, region2, hyperplane):1780r"""1781Test whether the ``hyperplane`` separates the given regions.17821783INPUT:17841785- ``region1``, ``region2`` -- polyhedra or list/tuple/iterable1786of coordinates which are regions of the arrangement or an interior1787point of a region17881789- ``hyperplane`` -- a hyperplane17901791OUTPUT:17921793A boolean. Whether the hyperplane ``hyperplane`` separate the given1794regions.17951796EXAMPLES::17971798sage: A.<x,y> = hyperplane_arrangements.coordinate(2)1799sage: A.is_separating_hyperplane([1,1], [2,1], y)1800False1801sage: A.is_separating_hyperplane([1,1], [-1,1], x)1802True1803sage: r = A.region_containing_point([1,1])1804sage: s = A.region_containing_point([-1,1])1805sage: A.is_separating_hyperplane(r, s, x)1806True1807"""1808if self.base_ring().characteristic() != 0:1809raise ValueError('requires characteristic zero')1810try:1811p1 = region1.representative_point()1812except AttributeError:1813p1 = list(region1)1814try:1815p2 = region2.representative_point()1816except AttributeError:1817p2 = list(region2)1818from sage.functions.generalized import sign1819s = sign(hyperplane(p1)) * sign(hyperplane(p2))1820if s < 0:1821return True1822if s > 0:1823return False1824raise ValueError('point lies on hyperplane')18251826def distance_between_regions(self, region1, region2):1827r"""1828Return the number of hyperplanes separating the two regions.18291830INPUT:18311832- ``region1``, ``region2`` -- regions of the arrangement or1833representative points of regions18341835OUTPUT:18361837An integer. The number of hyperplanes separating the two regions.18381839EXAMPLES::18401841sage: c = hyperplane_arrangements.coordinate(2)1842sage: r = c.region_containing_point([-1, -1])1843sage: s = c.region_containing_point([1, 1])1844sage: c.distance_between_regions(r, s)184521846sage: c.distance_between_regions(s, s)184701848"""1849count = sum(1 for hyperplane in self1850if self.is_separating_hyperplane(region1, region2, hyperplane))1851return ZZ(count)18521853def distance_enumerator(self, base_region):1854r"""1855Return the generating function for the number of hyperplanes1856at given distance.18571858INPUT:18591860- ``base_region`` -- region of arrangement or point in region18611862OUTPUT:18631864A polynomial `f(x)` for which the coefficient of `x^i` is the1865number of hyperplanes of distance `i` from ``base_region``,1866i.e., the number of hyperplanes separated by `i` hyperplanes1867from ``base_region``.18681869EXAMPLES::18701871sage: c = hyperplane_arrangements.coordinate(3)1872sage: c.distance_enumerator(c.region_containing_point([1,1,1]))1873x^3 + 3*x^2 + 3*x + 11874"""1875d = [self.distance_between_regions(r,base_region) for r in self.regions()]1876d = [d.count(i) for i in range(max(d)+1)]1877from sage.rings.polynomial.polynomial_ring import polygen1878x = polygen(QQ, 'x')1879return sum([d[i]*x**i for i in range(len(d))])18801881@cached_method1882def varchenko_matrix(self, names='h'):1883r"""1884Return the Varchenko matrix of the arrangement.18851886Let `H_1, \ldots, H_s` and `R_1, \ldots, R_t` denote the hyperplanes1887and regions, respectively, of the arrangement. Let `S =1888\QQ[h_1, \ldots, h_s]`, a polynomial ring with indeterminate `h_i`1889corresponding to hyperplane `H_i`. The Varchenko matrix is1890the `t \times t` matrix with `i,j`-th entry the product of1891those `h_k` such that `H_k` separates `R_i` and `R_j`.18921893INPUT:18941895- ``names`` -- string or list/tuple/iterable of strings. The1896variable names for the polynomial ring `S`.18971898OUTPUT:18991900The Varchenko matrix.19011902EXAMPLES::19031904sage: a = hyperplane_arrangements.coordinate(3)1905sage: v = a.varchenko_matrix(); v1906[ 1 h2 h1]1907[ h2 1 h1*h2]1908[ h1 h1*h2 1]1909sage: factor(det(v))1910(h2 - 1) * (h2 + 1) * (h1 - 1) * (h1 + 1)1911"""1912from sage.rings.all import PolynomialRing1913from sage.matrix.constructor import identity_matrix1914from sage.misc.misc import prod1915k = len(self)1916R = PolynomialRing(QQ, names, k)1917h = R.gens()1918region = self.regions()1919v = identity_matrix(R, k, k)1920for i in range(k):1921for j in range(i+1, k):1922t = prod(h[p] for p in range(k) if1923self.is_separating_hyperplane(region[i], region[j], self[p]))1924v[i,j] = v[j,i] = t1925v.set_immutable()1926return v1927192819291930class HyperplaneArrangements(Parent, UniqueRepresentation):1931"""1932Hyperplane arrangements.19331934For more information on hyperplane arrangements, see1935:mod:`sage.geometry.hyperplane_arrangements.arrangement`.19361937INPUT:19381939- ``base_ring`` -- ring; the base ring19401941- ``names`` -- tuple of strings; the variable names19421943EXAMPLES::19441945sage: H.<x,y> = HyperplaneArrangements(QQ)1946sage: x1947Hyperplane x + 0*y + 01948sage: x + y1949Hyperplane x + y + 01950sage: H(x, y, x-1, y-1)1951Arrangement <y - 1 | y | x - 1 | x>1952"""1953Element = HyperplaneArrangementElement19541955def __init__(self, base_ring, names=tuple()):1956"""1957Initialize ``self``.19581959TESTS::19601961sage: H.<x,y> = HyperplaneArrangements(QQ)1962sage: K = HyperplaneArrangements(QQ, names=('x', 'y'))1963sage: H is K1964True1965sage: type(K)1966<class 'sage.geometry.hyperplane_arrangement.arrangement.HyperplaneArrangements_with_category'>1967sage: K.change_ring(RR).gen(0)1968Hyperplane 1.00000000000000*x + 0.000000000000000*y + 0.00000000000000019691970TESTS::19711972sage: H.<x,y> = HyperplaneArrangements(QQ)1973sage: TestSuite(H).run()1974sage: K = HyperplaneArrangements(QQ)1975sage: TestSuite(K).run()1976"""1977from sage.categories.all import Fields, Sets1978if not base_ring in Fields:1979raise ValueError('base ring must be a field')1980super(HyperplaneArrangements, self).__init__(category=Sets())1981self._base_ring = base_ring1982self._names = names19831984def base_ring(self):1985"""1986Return the base ring.19871988OUTPUT:19891990The base ring of the hyperplane arrangement.19911992EXAMPLES::19931994sage: L.<x,y> = HyperplaneArrangements(QQ)1995sage: L.base_ring()1996Rational Field1997"""1998return self._base_ring19992000def change_ring(self, base_ring):2001"""2002Return hyperplane arrangements over a different base ring.20032004INPUT:20052006- ``base_ring`` -- a ring; the new base ring.20072008OUTPUT:20092010A new :class:`HyperplaneArrangements` instance over the new2011base ring.20122013EXAMPLES::20142015sage: L.<x,y> = HyperplaneArrangements(QQ)2016sage: L.gen(0)2017Hyperplane x + 0*y + 02018sage: L.change_ring(RR).gen(0)2019Hyperplane 1.00000000000000*x + 0.000000000000000*y + 0.00000000000000020202021TESTS::20222023sage: L.change_ring(QQ) is L2024True2025"""2026return HyperplaneArrangements(base_ring, names=self._names)20272028@cached_method2029def ambient_space(self):2030"""2031Return the ambient space.20322033The ambient space is the parent of hyperplanes. That is, new2034hyperplanes are always constructed internally from the ambient2035space instance.20362037EXAMPLES::20382039sage: L.<x, y> = HyperplaneArrangements(QQ)2040sage: L.ambient_space()([(1,0), 0])2041Hyperplane x + 0*y + 02042sage: L.ambient_space()([(1,0), 0]) == x2043True2044"""2045return AmbientVectorSpace(self.base_ring(), self._names)20462047def _repr_(self):2048"""2049Return a string representation.20502051OUTPUT:20522053A string.20542055EXAMPLES::20562057sage: L.<x, y> = HyperplaneArrangements(QQ); L2058Hyperplane arrangements in 2-dimensional linear space over Rational Field with coordinates x, y2059"""2060return 'Hyperplane arrangements in {0}'.format(self.ambient_space())20612062def _element_constructor_(self, *args, **kwds):2063"""2064Construct an element of ``self``.20652066INPUT:20672068- ``*args`` -- positional arguments, each defining a2069hyperplane; alternatively, a single polytope or a single2070hyperplane arrangement20712072- ``signed`` -- boolean (optional, default: ``True``); whether to2073preserve signs of hyperplane equations20742075- ``warn_duplicates`` -- boolean (optional, default: ``False``);2076whether to issue a warning if duplicate hyperplanes were2077passed -- note that duplicate hyperplanes are always removed,2078whether or not there is a warning shown20792080- ``check`` -- boolean (optional, default: ``True``); whether to2081perform argument checking.20822083EXAMPLES::20842085sage: L.<x, y> = HyperplaneArrangements(QQ)2086sage: L._element_constructor_(x, y)2087Arrangement <y | x>2088sage: L._element_constructor_([x, y])2089Arrangement <y | x>2090sage: L._element_constructor_([0, 1, 0], [0, 0, 1])2091Arrangement <y | x>2092sage: L._element_constructor_([[0, 1, 0], [0, 0, 1]])2093Arrangement <y | x>20942095sage: L._element_constructor(polytopes.n_cube(2))2096Arrangement <-x + 1 | -y + 1 | y + 1 | x + 1>20972098sage: L(x, x, warn_duplicates=True)2099doctest:...: UserWarning: Input contained 2 hyperplanes, but only 1 are distinct.2100Arrangement <x>2101sage: L(-x, x + y - 1, signed=False)2102Arrangement <-x - y + 1 | x>21032104TESTS::21052106sage: L()2107Empty hyperplane arrangement of dimension 22108sage: L(0) # zero is equivalent to no argument, Trac #86482109Empty hyperplane arrangement of dimension 22110sage: L(0*x) # degenerate hyperplane is NOT allowed2111Traceback (most recent call last):2112...2113ValueError: linear expression must be non-constant to define a hyperplane2114sage: L(0*x, y) # ditto2115Traceback (most recent call last):2116...2117ValueError: linear expression must be non-constant to define a hyperplane2118"""2119if len(args) == 1:2120arg = args[0]2121if isinstance(arg, HyperplaneArrangementElement) and args[0].parent() is self:2122# optimization if argument is already a hyperplane arrangement2123return arg2124if arg == 0 and not isinstance(arg, Hyperplane):2125# zero = neutral element under addition = the empty hyperplane arrangement2126args = []2127# process keyword arguments2128not_char2 = (self.base_ring().characteristic() != 2)2129signed = kwds.pop('signed', not_char2)2130warn_duplicates = kwds.pop('warn_duplicates', False)2131check = kwds.pop('check', True)2132if len(kwds) > 0:2133raise ValueError('unknown keyword argument')2134# process positional arguments2135AA = self.ambient_space()2136try:2137hyperplanes = map(AA, args)2138except (TypeError, ValueError, AttributeError):2139if len(args) > 1:2140raise2141arg = args[0]2142if hasattr(arg, 'Hrepresentation'):2143hyperplanes = [AA(h) for h in arg.Hrepresentation()]2144else:2145hyperplanes = map(AA, arg)2146hyperplanes = [h.primitive(signed) for h in hyperplanes]2147n = len(hyperplanes)2148hyperplanes = tuple(uniq(hyperplanes))2149if warn_duplicates and n != len(hyperplanes):2150from warnings import warn2151warn('Input contained {0} hyperplanes, but only {1} are distinct.'.format(n, len(hyperplanes)))2152# argument checking (optional but recommended)2153if check:2154if signed and not not_char2:2155raise ValueError('cannot be signed in characteristic 2')2156hyperplane_set = set(hyperplanes)2157for h in hyperplanes:2158if h.A() == 0:2159raise ValueError('linear expression must be non-constant to define a hyperplane')2160if not_char2 and -h in hyperplane_set:2161raise ValueError('arrangement cannot simultaneouly have h and -h as hyperplane')2162return self.element_class(self, hyperplanes)21632164@cached_method2165def ngens(self):2166"""2167Return the number of linear variables.21682169OUTPUT:21702171An integer.21722173EXAMPLES::21742175sage: L.<x, y, z> = HyperplaneArrangements(QQ); L2176Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z2177sage: L.ngens()217832179"""2180return len(self._names)21812182@cached_method2183def gens(self):2184"""2185Return the coordinate hyperplanes.21862187OUTPUT:21882189A tuple of linear expressions, one for each linear variable.21902191EXAMPLES::21922193sage: L = HyperplaneArrangements(QQ, ('x', 'y', 'z'))2194sage: L.gens()2195(Hyperplane x + 0*y + 0*z + 0,2196Hyperplane 0*x + y + 0*z + 0,2197Hyperplane 0*x + 0*y + z + 0)2198"""2199return self.ambient_space().gens()22002201def gen(self, i):2202"""2203Return the `i`-th coordinate hyperplane.22042205INPUT:22062207- ``i`` -- integer22082209OUTPUT:22102211A linear expression.22122213EXAMPLES::22142215sage: L.<x, y, z> = HyperplaneArrangements(QQ); L2216Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z2217sage: L.gen(0)2218Hyperplane x + 0*y + 0*z + 02219"""2220return self.gens()[i]22212222def _coerce_map_from_(self, P):2223"""2224Return whether there is a coercion.22252226TESTS::22272228sage: L.<x> = HyperplaneArrangements(QQ); L2229Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x2230sage: M.<y> = HyperplaneArrangements(RR); M2231Hyperplane arrangements in 1-dimensional linear space over Real Field with 53 bits of precision with coordinate y22322233sage: L.coerce_map_from(ZZ)2234Conversion map:2235From: Integer Ring2236To: Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x2237sage: M.coerce_map_from(L)2238Conversion map:2239From: Hyperplane arrangements in 1-dimensional linear space over2240Rational Field with coordinate x2241To: Hyperplane arrangements in 1-dimensional linear space over2242Real Field with 53 bits of precision with coordinate y2243sage: L.coerce_map_from(M)2244"""2245if self.ambient_space().has_coerce_map_from(P):2246return True2247if isinstance(P, HyperplaneArrangements):2248return self.base_ring().has_coerce_map_from(P.base_ring())2249return super(HyperplaneArrangements, self)._coerce_map_from_(P)2250225122522253