Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- Hyperplane Arrangements
Before talking about hyperplane arrangements, let us start with individual hyperplanes. This package uses certain linear expressions to represent hyperplanes, that is, a linear expression `3x + 3y - 5z - 7` stands for the hyperplane with the equation `x + 3y - 5z = 7`. To create it in Sage, you first have to create a :class:`HyperplaneArrangements` object to define the variables `x`, `y`, `z`::
sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: h = 3*x + 2*y - 5*z - 7; h Hyperplane 3*x + 2*y - 5*z - 7 sage: h.normal() (3, 2, -5) sage: h.constant_term() -7
The individual hyperplanes behave like the linear expression with regard to addition and scalar multiplication, which is why you can do linear combinations of the coordinates::
sage: -2*h Hyperplane -6*x - 4*y + 10*z + 14 sage: x, y, z (Hyperplane x + 0*y + 0*z + 0, Hyperplane 0*x + y + 0*z + 0, Hyperplane 0*x + 0*y + z + 0)
See :mod:`sage.geometry.hyperplane_arrangement.hyperplane` for more functionality of the individual hyperplanes.
Arrangements ------------
There are several ways to create hyperplane arrangements:
Notation (i): by passing individual hyperplanes to the :class:`HyperplaneArrangements` object::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: box = x | y | x-1 | y-1; box Arrangement <y - 1 | y | x - 1 | x> sage: box == H(x, y, x-1, y-1) # alternative syntax True
Notation (ii): by passing anything that defines a hyperplane, for example a coefficient vector and constant term::
sage: H = HyperplaneArrangements(QQ, ('x', 'y')) sage: triangle = H([(1, 0), 0], [(0, 1), 0], [(1,1), -1]); triangle Arrangement <y | x | x + y - 1>
sage: H.inject_variables() Defining x, y sage: triangle == x | y | x+y-1 True
The default base field is `\QQ`, the rational numbers. Finite fields are also supported::
sage: H.<x,y,z> = HyperplaneArrangements(GF(5)) sage: a = H([(1,2,3), 4], [(5,6,7), 8]); a Arrangement <y + 2*z + 3 | x + 2*y + 3*z + 4>
Notation (iii): a list or tuple of hyperplanes::
sage: H.<x,y,z> = HyperplaneArrangements(GF(5)) sage: k = [x+i for i in range(4)]; k [Hyperplane x + 0*y + 0*z + 0, Hyperplane x + 0*y + 0*z + 1, Hyperplane x + 0*y + 0*z + 2, Hyperplane x + 0*y + 0*z + 3] sage: H(k) Arrangement <x | x + 1 | x + 2 | x + 3>
Notation (iv): using the library of arrangements::
sage: hyperplane_arrangements.braid(4) Arrangement of 6 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.semiorder(3) Arrangement of 6 hyperplanes of dimension 3 and rank 2 sage: hyperplane_arrangements.graphical(graphs.PetersenGraph()) Arrangement of 15 hyperplanes of dimension 10 and rank 9 sage: hyperplane_arrangements.Ish(5) Arrangement of 20 hyperplanes of dimension 5 and rank 4
Notation (v): from the bounding hyperplanes of a polyhedron::
sage: a = polytopes.cube().hyperplane_arrangement(); a Arrangement of 6 hyperplanes of dimension 3 and rank 3 sage: a.n_regions() 27
New arrangements from old::
sage: a = hyperplane_arrangements.braid(3) sage: b = a.add_hyperplane([4, 1, 2, 3]) sage: b Arrangement <t1 - t2 | t0 - t1 | t0 - t2 | t0 + 2*t1 + 3*t2 + 4> sage: c = b.deletion([4, 1, 2, 3]) sage: a == c True
sage: a = hyperplane_arrangements.braid(3) sage: b = a.union(hyperplane_arrangements.semiorder(3)) sage: b == a | hyperplane_arrangements.semiorder(3) # alternate syntax True sage: b == hyperplane_arrangements.Catalan(3) True
sage: a Arrangement <t1 - t2 | t0 - t1 | t0 - t2> sage: a = hyperplane_arrangements.coordinate(4) sage: h = a.hyperplanes()[0] sage: b = a.restriction(h) sage: b == hyperplane_arrangements.coordinate(3) True
A hyperplane arrangement is *essential* is the normals to its hyperplane span the ambient space. Otherwise, it is *inessential*. The essentialization is formed by intersecting the hyperplanes by this normal space (actually, it is a bit more complicated over finite fields)::
sage: a = hyperplane_arrangements.braid(4); a Arrangement of 6 hyperplanes of dimension 4 and rank 3 sage: a.is_essential() False sage: a.rank() < a.dimension() # double-check True sage: a.essentialization() Arrangement of 6 hyperplanes of dimension 3 and rank 3
The connected components of the complement of the hyperplanes of an arrangement in `\RR^n` are called the *regions* of the arrangement::
sage: a = hyperplane_arrangements.semiorder(3) sage: b = a.essentialization(); b Arrangement of 6 hyperplanes of dimension 2 and rank 2 sage: b.n_regions() 19 sage: b.regions() (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 6 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays) sage: b.bounded_regions() (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 6 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices) sage: b.n_bounded_regions() 7 sage: a.unbounded_regions() (A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices, 1 ray, 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line)
The distance between regions is defined as the number of hyperplanes separating them. For example::
sage: r1 = b.regions()[0] sage: r2 = b.regions()[1] sage: b.distance_between_regions(r1, r2) 1 sage: [hyp for hyp in b if b.is_separating_hyperplane(r1, r2, hyp)] [Hyperplane 2*t1 + t2 + 1] sage: b.distance_enumerator(r1) # generating function for distances from r1 6*x^3 + 6*x^2 + 6*x + 1
.. NOTE::
*bounded region* really mean *relatively bounded* here. A region is relatively bounded if its intersection with space spanned by the normals of the hyperplanes in the arrangement is bounded.
The intersection poset of a hyperplane arrangement is the collection of all nonempty intersections of hyperplanes in the arrangement, ordered by reverse inclusion. It includes the ambient space of the arrangement (as the intersection over the empty set)::
sage: a = hyperplane_arrangements.braid(3) sage: p = a.intersection_poset() sage: p.is_ranked() True sage: p.order_polytope() A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 10 vertices
The characteristic polynomial is a basic invariant of a hyperplane arrangement. It is defined as
.. MATH::
\chi(x) := \sum_{w\in P} \mu(w) x^{dim(w)}
where the sum is `P` is the :meth:`~HyperplaneArrangementElement.intersection_poset` of the arrangement and `\mu` is the Möbius function of `P`::
sage: a = hyperplane_arrangements.semiorder(5) sage: a.characteristic_polynomial() # long time (about a second on Core i7) x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x sage: a.poincare_polynomial() # long time 1380*x^4 + 790*x^3 + 180*x^2 + 20*x + 1 sage: a.n_regions() # long time 2371 sage: charpoly = a.characteristic_polynomial() # long time sage: charpoly(-1) # long time -2371 sage: a.n_bounded_regions() # long time 751 sage: charpoly(1) # long time 751
For finer invariants derived from the intersection poset, see :meth:`~HyperplaneArrangementElement.whitney_number` and :meth:`~HyperplaneArrangementElement.doubly_indexed_whitney_number`.
Miscellaneous methods (see documentation for an explanation)::
sage: a = hyperplane_arrangements.semiorder(3) sage: a.has_good_reduction(5) True sage: b = a.change_ring(GF(5)) sage: pa = a.intersection_poset() sage: pb = b.intersection_poset() sage: pa.is_isomorphic(pb) True sage: a.face_vector() (0, 12, 30, 19) sage: a.face_vector() (0, 12, 30, 19) sage: a.is_central() False sage: a.is_linear() False sage: a.sign_vector((1,1,1)) (-1, 1, -1, 1, -1, 1) sage: a.varchenko_matrix() [ 1 h2 h2*h4 h2*h3 h2*h3*h4 h2*h3*h4*h5] [ h2 1 h4 h3 h3*h4 h3*h4*h5] [ h2*h4 h4 1 h3*h4 h3 h3*h5] [ h2*h3 h3 h3*h4 1 h4 h4*h5] [ h2*h3*h4 h3*h4 h3 h4 1 h5] [h2*h3*h4*h5 h3*h4*h5 h3*h5 h4*h5 h5 1]
There are extensive methods for visualizing hyperplane arrangements in low dimensions. See :meth:`~HyperplaneArrangementElement.plot` for details.
TESTS::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: h = H([(1, 106), 106266], [(83, 101), 157866], [(111, 110), 186150], [(453, 221), 532686], ....: [(407, 237), 516882], [(55, 32), 75620], [(221, 114), 289346], [(452, 115), 474217], ....: [(406, 131), 453521], [(28, 9), 32446], [(287, 19), 271774], [(241, 35), 244022], ....: [(231, 1), 210984], [(185, 17), 181508], [(23, -8), 16609]) sage: h.n_regions() 85
sage: H() Empty hyperplane arrangement of dimension 2
sage: Zero = HyperplaneArrangements(QQ) sage: Zero Hyperplane arrangements in 0-dimensional linear space over Rational Field with coordinate sage: Zero() Empty hyperplane arrangement of dimension 0 sage: Zero.an_element() Empty hyperplane arrangement of dimension 0
AUTHORS:
- David Perkinson (2013-06): initial version
- Qiaoyu Yang (2013-07)
- Kuai Yu (2013-07)
- Volker Braun (2013-10): Better Sage integration, major code refactoring.
This module implements hyperplane arrangements defined over the rationals or over finite fields. The original motivation was to make a companion to Richard Stanley's notes [Sta2007]_ on hyperplane arrangements. """
#***************************************************************************** # Copyright (C) 2013 David Perkinson <davidp@reed.edu> # Volker Braun <vbraun.name@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
# Possible extensions for hyperplane_arrangement.py: # - the big face lattice # - create ties with the Sage matroid methods # - hyperplane arrangements over other fields
""" A hyperplane arrangement.
.. WARNING::
You should never create :class:`HyperplaneArrangementElement` instances directly, always use the parent. """ """ Construct a hyperplane arrangement.
INPUT:
- ``parent`` -- the parent :class:`HyperplaneArrangements`
- ``hyperplanes`` -- a tuple of hyperplanes
- ``check`` -- boolean (optional; default ``True``); whether to check input
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: elt = H(x, y); elt Arrangement <y | x> sage: TestSuite(elt).run() """ raise ValueError("the hyperplanes must be given as a tuple") raise ValueError("not all elements are hyperplanes") raise ValueError("not all hyperplanes are in the ambient space")
""" Workaround to support the construction with names.
INPUT/OUTPUT:
See :meth:`HyperplaneArrangements._first_ngens`.
EXAMPLES::
sage: a.<x,y,z> = hyperplane_arrangements.braid(3) # indirect doctest sage: (x, y) == a._first_ngens(2) True """
""" Return the `i`-th hyperplane.
INPUT:
- ``i`` -- integer
OUTPUT:
The `i`-th hyperplane.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: h = x|y; h Arrangement <y | x> sage: h[0] Hyperplane 0*x + y + 0 sage: h[1] Hyperplane x + 0*y + 0 """
r""" Return the number of hyperplanes in the arrangement.
OUTPUT:
An integer.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([1,1,0], [2,3,-1], [4,5,3]) sage: A.n_hyperplanes() 3 sage: len(A) # equivalent 3 """
r""" Return the number of hyperplanes in the arrangement.
OUTPUT:
An integer.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([1,1,0], [2,3,-1], [4,5,3]) sage: A.hyperplanes() (Hyperplane x + 0*y + 1, Hyperplane 3*x - y + 2, Hyperplane 5*x + 3*y + 4)
Note that the hyperplanes can be indexed as if they were a list::
sage: A[0] Hyperplane x + 0*y + 1 """
r""" String representation for a hyperplane arrangement.
OUTPUT:
A string.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: H(x, y, x-1, y-1) Arrangement <y - 1 | y | x - 1 | x> sage: x | y | x - 1 | y - 1 | x + y | x - y Arrangement of 6 hyperplanes of dimension 2 and rank 2 sage: H() Empty hyperplane arrangement of dimension 2 """ len(self), self.dimension(), self.rank())
""" Return the ambient space dimension of the arrangement.
OUTPUT:
An integer.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: (x | x-1 | x+1).dimension() 2 sage: H(x).dimension() 2 """
""" Return the rank.
OUTPUT:
The dimension of the span of the normals to the hyperplanes in the arrangement.
EXAMPLES::
sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: A = H([[0, 1, 2, 3],[-3, 4, 5, 6]]) sage: A.dimension() 3 sage: A.rank() 2
sage: B = hyperplane_arrangements.braid(3) sage: B.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) sage: B.dimension() 3 sage: B.rank() 2
sage: p = polytopes.simplex(5, project=True) sage: H = p.hyperplane_arrangement() sage: H.rank() 5 """
""" Compare two hyperplane arrangements.
EXAMPLES::
sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: H(x) == H(y) False
TESTS::
sage: H(x) == 0 False """
r""" The union of ``self`` with ``other``.
INPUT:
- ``other`` -- a hyperplane arrangement or something that can be converted into a hyperplane arrangement
OUTPUT:
A new hyperplane arrangement.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([1,2,3], [0,1,1], [0,1,-1], [1,-1,0], [1,1,0]) sage: B = H([1,1,1], [1,-1,1], [1,0,-1]) sage: A.union(B) Arrangement of 8 hyperplanes of dimension 2 and rank 2 sage: A | B # syntactic sugar Arrangement of 8 hyperplanes of dimension 2 and rank 2
A single hyperplane is coerced into a hyperplane arrangement if necessary::
sage: A.union(x+y-1) Arrangement of 6 hyperplanes of dimension 2 and rank 2 sage: A.add_hyperplane(x+y-1) # alias Arrangement of 6 hyperplanes of dimension 2 and rank 2
sage: P.<x,y> = HyperplaneArrangements(RR) sage: C = P(2*x + 4*y + 5) sage: C.union(A) Arrangement of 6 hyperplanes of dimension 2 and rank 2 """
""" Plot the hyperplane arrangement.
OUTPUT:
A graphics object.
EXAMPLES::
sage: L.<x, y> = HyperplaneArrangements(QQ) sage: L(x, y, x+y-2).plot() Graphics object consisting of 3 graphics primitives """
r""" Return the cone over the hyperplane arrangement.
INPUT:
- ``variable`` -- string; the name of the additional variable
OUTPUT:
A new hyperplane arrangement. Its equations consist of `[0, -d, a_1, \ldots, a_n]` for each `[d, a_1, \ldots, a_n]` in the original arrangement and the equation `[0, 1, 0, \ldots, 0]`.
.. WARNING::
While there is an almost-one-to-one correspondence between the hyperplanes of ``self`` and those of ``self.cone()``, there is no guarantee that the order in which they appear in ``self.hyperplanes()`` will match the order in which their counterparts in ``self.cone()`` will appear in ``self.cone().hyperplanes()``!
EXAMPLES::
sage: a.<x,y,z> = hyperplane_arrangements.semiorder(3) sage: b = a.cone() sage: a.characteristic_polynomial().factor() x * (x^2 - 6*x + 12) sage: b.characteristic_polynomial().factor() (x - 1) * x * (x^2 - 6*x + 12) sage: a.hyperplanes() (Hyperplane 0*x + y - z - 1, Hyperplane 0*x + y - z + 1, Hyperplane x - y + 0*z - 1, Hyperplane x - y + 0*z + 1, Hyperplane x + 0*y - z - 1, Hyperplane x + 0*y - z + 1) sage: b.hyperplanes() (Hyperplane -t + 0*x + y - z + 0, Hyperplane -t + x - y + 0*z + 0, Hyperplane -t + x + 0*y - z + 0, Hyperplane t + 0*x + 0*y + 0*z + 0, Hyperplane t + 0*x + y - z + 0, Hyperplane t + x - y + 0*z + 0, Hyperplane t + x + 0*y - z + 0) """
def intersection_poset(self): r""" Return the intersection poset of the hyperplane arrangement.
OUTPUT:
The poset of non-empty intersections of hyperplanes.
EXAMPLES::
sage: a = hyperplane_arrangements.coordinate(2) sage: a.intersection_poset() Finite poset containing 4 elements
sage: A = hyperplane_arrangements.semiorder(3) sage: A.intersection_poset() Finite poset containing 19 elements """
""" Return the characteristic polynomial of the hyperplane arrangement.
This is the slow computation directly from the definition. For educational use only.
EXAMPLES::
sage: a = hyperplane_arrangements.coordinate(2) sage: a._slow_characteristic_polynomial() x^2 - 2*x + 1 """
def characteristic_polynomial(self): r""" Return the characteristic polynomial of the hyperplane arrangement.
OUTPUT:
The characteristic polynomial in `\QQ[x]`.
EXAMPLES::
sage: a = hyperplane_arrangements.coordinate(2) sage: a.characteristic_polynomial() x^2 - 2*x + 1
TESTS::
sage: H.<s,t,u,v> = HyperplaneArrangements(QQ) sage: m = matrix([(0, -1, 0, 1, -1), (0, -1, 1, -1, 0), (0, -1, 1, 0, -1), ....: (0, 1, 0, 0, 0), (0, 1, 0, 1, -1), (0, 1, 1, -1, 0), (0, 1, 1, 0, -1)]) sage: R.<x> = QQ[] sage: expected_charpoly = (x - 1) * x * (x^2 - 6*x + 12) sage: for s in SymmetricGroup(4): # long time (about a second on a Core i7) ....: m_perm = [m.column(i) for i in [0, s(1), s(2), s(3), s(4)]] ....: m_perm = matrix(m_perm).transpose() ....: charpoly = H(m_perm.rows()).characteristic_polynomial() ....: assert charpoly == expected_charpoly """
def poincare_polynomial(self): r""" Return the Poincaré polynomial of the hyperplane arrangement.
OUTPUT:
The Poincaré polynomial in `\QQ[x]`.
EXAMPLES::
sage: a = hyperplane_arrangements.coordinate(2) sage: a.poincare_polynomial() x^2 + 2*x + 1 """
r""" Return the hyperplane arrangement obtained by removing ``h``.
INPUT:
- ``h`` -- a hyperplane or hyperplane arrangement
OUTPUT:
A new hyperplane arrangement with the given hyperplane(s) ``h`` removed.
.. SEEALSO::
:meth:`restriction`
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([0,1,0], [1,0,1], [-1,0,1], [0,1,-1], [0,1,1]); A Arrangement of 5 hyperplanes of dimension 2 and rank 2 sage: A.deletion(x) Arrangement <y - 1 | y + 1 | x - y | x + y> sage: h = H([0,1,0], [0,1,1]) sage: A.deletion(h) Arrangement <y - 1 | y + 1 | x - y>
TESTS::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([0,1,0], [1,0,1], [-1,0,1], [0,1,-1], [0,1,1]) sage: h = H([0,4,0]) sage: A.deletion(h) Arrangement <y - 1 | y + 1 | x - y | x + y> sage: l = H([1,2,3]) sage: A.deletion(l) Traceback (most recent call last): ... ValueError: hyperplane is not in the arrangement """
r""" Return the restriction to a hyperplane.
INPUT:
- ``hyperplane`` -- a hyperplane of the hyperplane arrangement
OUTPUT:
The restriction of the hyperplane arrangement to the given ``hyperplane``.
EXAMPLES::
sage: A.<u,x,y,z> = hyperplane_arrangements.braid(4); A Arrangement of 6 hyperplanes of dimension 4 and rank 3 sage: H = A[0]; H Hyperplane 0*u + 0*x + y - z + 0 sage: R = A.restriction(H); R Arrangement <x - z | u - x | u - z> sage: D = A.deletion(H); D Arrangement of 5 hyperplanes of dimension 4 and rank 3 sage: ca = A.characteristic_polynomial() sage: cr = R.characteristic_polynomial() sage: cd = D.characteristic_polynomial() sage: ca x^4 - 6*x^3 + 11*x^2 - 6*x sage: cd - cr x^4 - 6*x^3 + 11*x^2 - 6*x
.. SEEALSO::
:meth:`deletion` """ raise ValueError('hyperplane not in arrangement')
""" Return hyperplane arrangement over the new base ring.
INPUT:
- ``base_ring`` -- the new base ring; must be a field for hyperplane arrangements
OUTPUT:
The hyperplane arrangement obtained by changing the base field, as a new hyperplane arrangement.
.. WARNING::
While there is often a one-to-one correspondence between the hyperplanes of ``self`` and those of ``self.change_ring(base_ring)``, there is no guarantee that the order in which they appear in ``self.hyperplanes()`` will match the order in which their counterparts in ``self.cone()`` will appear in ``self.change_ring(base_ring).hyperplanes()``!
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([(1,1), 0], [(2,3), -1]) sage: A.change_ring(FiniteField(2)) Arrangement <y + 1 | x + y> """
def n_regions(self): r""" The number of regions of the hyperplane arrangement.
OUTPUT:
An integer.
EXAMPLES::
sage: A = hyperplane_arrangements.semiorder(3) sage: A.n_regions() 19
TESTS::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([(1,1), 0], [(2,3), -1], [(4,5), 3]) sage: B = A.change_ring(FiniteField(7)) sage: B.n_regions() Traceback (most recent call last): ... TypeError: base field must have characteristic zero """
def n_bounded_regions(self): r""" Return the number of (relatively) bounded regions.
OUTPUT:
An integer. The number of relatively bounded regions of the hyperplane arrangement.
EXAMPLES::
sage: A = hyperplane_arrangements.semiorder(3) sage: A.n_bounded_regions() 7
TESTS::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3]) sage: B = A.change_ring(FiniteField(7)) sage: B.n_bounded_regions() Traceback (most recent call last): ... TypeError: base field must have characteristic zero """
r""" Return whether the hyperplane arrangement has good reduction mod `p`.
Let `A` be a hyperplane arrangement with equations defined over the integers, and let `B` be the hyperplane arrangement defined by reducing these equations modulo a prime `p`. Then `A` has good reduction modulo `p` if the intersection posets of `A` and `B` are isomorphic.
INPUT:
- ``p`` -- prime number
OUTPUT:
A boolean.
EXAMPLES::
sage: a = hyperplane_arrangements.semiorder(3) sage: a.has_good_reduction(5) True sage: a.has_good_reduction(3) False sage: b = a.change_ring(GF(3)) sage: a.characteristic_polynomial() x^3 - 6*x^2 + 12*x sage: b.characteristic_polynomial() # not equal to that for a x^3 - 6*x^2 + 10*x """ raise TypeError('arrangement must be defined over QQ') raise TypeError('must reduce modulo a prime number')
r""" Test whether all hyperplanes pass through the origin.
OUTPUT:
A boolean. Whether all the hyperplanes pass through the origin.
EXAMPLES::
sage: a = hyperplane_arrangements.semiorder(3) sage: a.is_linear() False sage: b = hyperplane_arrangements.braid(3) sage: b.is_linear() True
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: c = H(x+1, y+1) sage: c.is_linear() False sage: c.is_central() True """
r""" Test whether the hyperplane arrangement is essential.
A hyperplane arrangement is essential if the span of the normals of its hyperplanes spans the ambient space.
.. SEEALSO::
:meth:`essentialization`
OUTPUT:
A boolean indicating whether the hyperplane arrangement is essential.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: H(x, x+1).is_essential() False sage: H(x, y).is_essential() True """
def is_central(self): r""" Test whether the intersection of all the hyperplanes is nonempty.
OUTPUT:
A boolean whether the hyperplane arrangement is such that the intersection of all the hyperplanes in the arrangement is nonempty.
EXAMPLES::
sage: a = hyperplane_arrangements.braid(2) sage: a.is_central() True """
def essentialization(self): r""" Return the essentialization of the hyperplane arrangement.
The essentialization of a hyperplane arrangement whose base field has characteristic 0 is obtained by intersecting the hyperplanes by the space spanned by their normal vectors.
OUTPUT:
The essentialization as a new hyperplane arrangement.
EXAMPLES::
sage: a = hyperplane_arrangements.braid(3) sage: a.is_essential() False sage: a.essentialization() Arrangement <t1 - t2 | t1 + 2*t2 | 2*t1 + t2>
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: B = H([(1,0),1], [(1,0),-1]) sage: B.is_essential() False sage: B.essentialization() Arrangement <-x + 1 | x + 1> sage: B.essentialization().parent() Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x
sage: H.<x,y> = HyperplaneArrangements(GF(2)) sage: C = H([(1,1),1], [(1,1),0]) sage: C.essentialization() Arrangement <y | y + 1>
sage: h = hyperplane_arrangements.semiorder(4) sage: h.essentialization() Arrangement of 12 hyperplanes of dimension 3 and rank 3
TESTS::
sage: b = hyperplane_arrangements.coordinate(2) sage: b.is_essential() True sage: b.essentialization() is b True """ """helper to iterat over the echelon pivot column indices"""
# find a (any) complement to the normals else: # we don't necessarily have an orthogonal complement, pick any complement # reduce the hyperplane equations # eliminate the pivot'ed coordinates continue # Construct the result
r""" Indicates on which side of each hyperplane the given point `p` lies.
The base field must have characteristic zero.
INPUT:
- ``p`` -- point as a list/tuple/iterable
OUTPUT:
A vector whose entries are in `[-1, 0, +1]`.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([(1,0), 0], [(0,1), 1]); A Arrangement <y + 1 | x> sage: A.sign_vector([2, -2]) (-1, 1) sage: A.sign_vector((-1, -1)) (0, -1)
TESTS::
sage: H.<x,y> = HyperplaneArrangements(GF(3)) sage: A = H(x, y) sage: A.sign_vector([1, 2]) Traceback (most recent call last): ... ValueError: characteristic must be zero """
r""" Return the face vector.
OUTPUT:
A vector of integers.
The `d`-th entry is the number of faces of dimension `d`. A *face* is the intersection of a region with a hyperplane of the arrangement.
EXAMPLES::
sage: A = hyperplane_arrangements.Shi(3) sage: A.face_vector() (0, 6, 21, 16) """
def _parallel_hyperplanes(self): """ Return the hyperplanes grouped into parallel sets.
OUTPUT:
A tuple with one entry per set of parallel hyperplanes. Each entry is a tuple of triples, one for each parallel hyperplane in the parallel set. The triple consists of the hyperplane, the normal vector `A`, and the constant `b` of the hyperplane equation `Ax+b`. The normalization is such that `A` is the same for each hyperplane of the parallel set, and the order is in increasing order of the `b` values.
In other words, each parallel set of hyperplanes is also ordered by the order with which a common normal passes through them.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: h = (x + 2*y | 2*x + 4*y + 1 | -x/4 - y/2 + 1); h Arrangement <-x - 2*y + 4 | x + 2*y | 2*x + 4*y + 1> sage: h._parallel_hyperplanes()[0] ((Hyperplane -x - 2*y + 4, (1, 2), -4), (Hyperplane x + 2*y + 0, (1, 2), 0), (Hyperplane 2*x + 4*y + 1, (1, 2), 1/2))
sage: hyperplane_arrangements.Shi(3)._parallel_hyperplanes() (((Hyperplane 0*t0 + t1 - t2 - 1, (0, 1, -1), -1), (Hyperplane 0*t0 + t1 - t2 + 0, (0, 1, -1), 0)), ((Hyperplane t0 - t1 + 0*t2 - 1, (1, -1, 0), -1), (Hyperplane t0 - t1 + 0*t2 + 0, (1, -1, 0), 0)), ((Hyperplane t0 + 0*t1 - t2 - 1, (1, 0, -1), -1), (Hyperplane t0 + 0*t1 - t2 + 0, (1, 0, -1), 0))) """ for hyperplane in sorted(parallels[key]))) for key in parallels.keys()]
""" Return the vertices.
The vertices are the zero-dimensional faces, see :meth:`face_vector`.
INPUT:
- ``exclude_sandwiched`` -- boolean (default: ``False``). Whether to exclude hyperplanes that are sandwiched between parallel hyperplanes. Useful if you only need the convex hull.
OUTPUT:
The vertices in a sorted tuple. Each vertex is returned as a vector in the ambient vector space.
EXAMPLES::
sage: A = hyperplane_arrangements.Shi(3).essentialization() sage: A.dimension() 2 sage: A.face_vector() (6, 21, 16) sage: A.vertices() ((-2/3, 1/3), (-1/3, -1/3), (0, -1), (0, 0), (1/3, -2/3), (2/3, -1/3)) sage: point2d(A.vertices(), size=20) + A.plot() Graphics object consisting of 7 graphics primitives
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: chessboard = [] sage: N = 8 sage: for x0 in range(N+1): ....: for y0 in range(N+1): ....: chessboard.extend([x-x0, y-y0]) sage: chessboard = H(chessboard) sage: len(chessboard.vertices()) 81 sage: chessboard.vertices(exclude_sandwiched=True) ((0, 0), (0, 8), (8, 0), (8, 8)) """ for parallel in parallels] return b_list # vertices are solutions v * lhs = rhs
""" Helper method to construct a region.
INPUT:
- ``hyperplanes`` -- a list/tuple/iterable of hyperplanes
OUTPUT:
The polyhedron constructed from taking the linear expressions as inequalities.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: h = H(x) sage: h._make_region([x, 1-x, y, 1-y]) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices """ base_ring=self.parent().base_ring())
def regions(self): r""" Return the regions of the hyperplane arrangement.
The base field must have characteristic zero.
OUTPUT:
A tuple containing the regions as polyhedra.
The regions are the connected components of the complement of the union of the hyperplanes as a subset of `\RR^n`.
EXAMPLES::
sage: a = hyperplane_arrangements.braid(2) sage: a.regions() (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line)
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H(x, y+1) sage: A.regions() (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays)
sage: chessboard = [] sage: N = 8 sage: for x0 in range(N+1): ....: for y0 in range(N+1): ....: chessboard.extend([x-x0, y-y0]) sage: chessboard = H(chessboard) sage: len(chessboard.bounded_regions()) # long time, 359 ms on a Core i7 64 """ raise ValueError('base field must have characteristic zero')
r""" Return the closed faces of the hyperplane arrangement ``self`` (provided that ``self`` is defined over a totally ordered field).
Let `\mathcal{A}` be a hyperplane arrangement in the vector space `K^n`, whose hyperplanes are the zero sets of the affine-linear functions `u_1, u_2, \ldots, u_N`. (We consider these functions `u_1, u_2, \ldots, u_N`, and not just the hyperplanes, as given. We also assume the field `K` to be totally ordered.) For any point `x \in K^n`, we define the *sign vector* of `x` to be the vector `(v_1, v_2, \ldots, v_N) \in \{-1, 0, 1\}^N` such that (for each `i`) the number `v_i` is the sign of `u_i(x)`. For any `v \in \{-1, 0, 1\}^N`, we let `F_v` be the set of all `x \in K^n` which have sign vector `v`. The nonempty ones among all these subsets `F_v` are called the *open faces* of `\mathcal{A}`. They form a partition of the set `K^n`.
Furthermore, for any `v = (v_1, v_2, \ldots, v_N) \in \{-1, 0, 1\}^N`, we let `G_v` be the set of all `x \in K^n` such that, for every `i`, the sign of `u_i(x)` is either `0` or `v_i`. Then, `G_v` is a polyhedron. The nonempty ones among all these polyhedra `G_v` are called the *closed faces* of `\mathcal{A}`. While several sign vectors `v` can lead to one and the same closed face `G_v`, we can assign to every closed face a canonical choice of a sign vector: Namely, if `G` is a closed face of `\mathcal{A}`, then the *sign vector* of `G` is defined to be the vector `(v_1, v_2, \ldots, v_N) \in \{-1, 0, 1\}^N` where `x` is any point in the relative interior of `G` and where, for each `i`, the number `v_i` is the sign of `u_i(x)`. (This does not depend on the choice of `x`.)
There is a one-to-one correspondence between the closed faces and the open faces of `\mathcal{A}`. It sends a closed face `G` to the open face `F_v`, where `v` is the sign vector of `G`; this `F_v` is also the relative interior of `G_v`. The inverse map sends any open face `O` to the closure of `O`.
INPUT:
- ``labelled`` -- boolean (default: ``True``); if ``True``, then this method returns not the faces itself but rather pairs `(v, F)` where `F` is a closed face and `v` is its sign vector (here, the order and the orientation of the `u_1, u_2, \ldots, u_N` is as given by ``self.hyperplanes()``).
OUTPUT:
A tuple containing the closed faces as polyhedra, or (if ``labelled`` is set to ``True``) the pairs of sign vectors and corresponding closed faces.
.. TODO::
Should the output rather be a dictionary where the keys are the sign vectors and the values are the faces?
EXAMPLES::
sage: a = hyperplane_arrangements.braid(2) sage: a.hyperplanes() (Hyperplane t0 - t1 + 0,) sage: a.closed_faces() (((0,), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line), ((1,), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line), ((-1,), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line)) sage: a.closed_faces(labelled=False) (A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line) sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] [((0,), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line, (0, 0)), ((1,), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, (0, -1)), ((-1,), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, 1 ray, 1 line, (-1, 0))]
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: a = H(x, y+1) sage: a.hyperplanes() (Hyperplane 0*x + y + 1, Hyperplane x + 0*y + 0) sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] [((0, 0), A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, (0, -1)), ((0, 1), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, (1, -1)), ((0, -1), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, (-1, -1)), ((1, 0), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, (0, 0)), ((1, 1), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, (1, 0)), ((1, -1), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, (-1, 0)), ((-1, 0), A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 ray, (0, -2)), ((-1, 1), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, (1, -2)), ((-1, -1), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, (-1, -2))]
sage: a = hyperplane_arrangements.braid(3) sage: a.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) sage: [(v, F, F.representative_point()) for v, F in a.closed_faces()] [((0, 0, 0), A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line, (0, 0, 0)), ((0, 1, 1), A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, (0, -1, -1)), ((0, -1, -1), A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, (-1, 0, 0)), ((1, 0, 1), A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, (1, 1, 0)), ((1, 1, 1), A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, (0, -1, -2)), ((1, -1, 0), A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, (-1, 0, -1)), ((1, -1, 1), A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, (1, 2, 0)), ((1, -1, -1), A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, (-2, 0, -1)), ((-1, 0, -1), A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, (0, 0, 1)), ((-1, 1, 0), A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line, (1, 0, 1)), ((-1, 1, 1), A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, (0, -2, -1)), ((-1, 1, -1), A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, (1, 0, 2)), ((-1, -1, -1), A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 2 rays, 1 line, (-1, 0, 1))]
Let us check that the number of closed faces with a given dimension computed using ``self.closed_faces()`` equals the one computed using :meth:`face_vector`::
sage: def test_number(a): ....: Qx = PolynomialRing(QQ, 'x'); x = Qx.gen() ....: RHS = Qx.sum(vi * x ** i for i, vi in enumerate(a.face_vector())) ....: LHS = Qx.sum(x ** F[1].dim() for F in a.closed_faces()) ....: return LHS == RHS sage: a = hyperplane_arrangements.Catalan(2) sage: test_number(a) True sage: a = hyperplane_arrangements.Shi(3) sage: test_number(a) # long time True
TESTS:
An empty border case::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: a = H() sage: a.closed_faces() (((), A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines),) """ raise ValueError('base field must have characteristic zero') # Loop invariant: # ``faces == Hk.closed_faces()``, where ``Hk`` is the # hyperplane arrangement given by the first ``k`` hyperplanes # in the list ``hypes`` (that is, by ``hypes[:k]``). # ``zero_half`` is the hyperplane ``hyperplane`` itself # (viewed as a polyhedron). # So ``face`` is a face of the hyperplane arrangement # given by the first ``k`` hyperplanes in the list # ``hypes``, and ``signs`` is the corresponding # (length-``k``) sign vector. # Adding the intersection of ``face`` with ``hyperplane``: # If the intersection of ``face`` with ``hyperplane`` # has the same dimension as ``face``, then this # intersection *is* ``face``, so we can continue # (without adding the other two intersections, since # those are empty): # If we are here, then ``face`` is not contained in # ``hyperplane``. # Do not append ``zero_part`` yet! It might be # redundant (in the sense that some of its defining # inequalities are always equalities on it). Check for # this: else: # Now we know ``zero_part`` is not redundant. # Adding the intersection of ``face`` with the positive # halfspace: # If this condition is not satisfied, then # ``pos_part`` is either ``zero_part`` or the empty # set; in either case we need not add it. Conversely, # if it is satisfied, then ``pos_part`` is not yet in # ``subdivided``, nor is it redundant. # If this condition is not satisfied, then # ``neg_part`` is either ``zero_part`` or the empty # set; in either case we need not add it. Conversely, # if it is satisfied, then ``neg_part`` is not yet in # ``subdivided``, nor is it redundant. # Or, if we want a dictionary: # return {F[0]: F[1] for F in faces}
r""" Return the product `FG` in the face semigroup of ``self``, where `F` and `G` are two closed faces of ``self``.
The face semigroup of a hyperplane arrangement `\mathcal{A}` is defined as follows: As a set, it is the set of all open faces of ``self`` (see :meth:`closed_faces`). Its product is defined by the following rule: If `F` and `G` are two open faces of `\mathcal{A}`, then `FG` is an open face of `\mathcal{A}`, and for every hyperplane `H \in \mathcal{A}`, the open face `FG` lies on the same side of `H` as `F` unless `F \subseteq H`, in which case `FG` lies on the same side of `H` as `G`. Alternatively, `FG` can be defined as follows: If `f` and `g` are two points in `F` and `G`, respectively, then `FG` is the face that contains the point `(f + \varepsilon g) / (1 + \varepsilon)` for any sufficiently small positive `\varepsilon`.
In our implementation, the face semigroup consists of closed faces rather than open faces (thanks to the 1-to-1 correspondence between open faces and closed faces, this is not really a different semigroup); these closed faces are given as polyhedra.
The face semigroup of a hyperplane arrangement is always a left-regular band (i.e., a semigroup satisfying the identities `x^2 = x` and `xyx = xy`). When the arrangement is central, then this semigroup is a monoid. See [Br2000]_ (Appendix A in particular) for further properties.
INPUT:
- ``F``, ``G`` -- two faces of ``self`` (as polyhedra)
- ``normalize`` -- Boolean (default: ``True``); if ``True``, then this method returns the precise instance of `FG` in the list returned by ``self.closed_faces()``, rather than creating a new instance
EXAMPLES::
sage: a = hyperplane_arrangements.braid(3) sage: a.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) sage: faces = {F0: F1 for F0, F1 in a.closed_faces()} sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z sage: xGyEz.representative_point() (0, -1, -1) sage: xGyEz = faces[(0, 1, 1)] # closed face x >= y = z sage: xGyEz.representative_point() (0, -1, -1) sage: yGxGz = faces[(1, -1, 1)] # closed face y >= x >= z sage: xGyGz = faces[(1, 1, 1)] # closed face x >= y >= z sage: a.face_product(xGyEz, yGxGz) == xGyGz True sage: a.face_product(yGxGz, xGyEz) == yGxGz True sage: xEzGy = faces[(-1, 1, 0)] # closed face x = z >= y sage: xGzGy = faces[(-1, 1, 1)] # closed face x >= z >= y sage: a.face_product(xEzGy, yGxGz) == xGzGy True """ # Decide which side of ``hyperplane`` our face ``FG`` will be # on. else: side = -1 else: side = 0 eqns.append(ieq) else: return face # Look for ``I`` in ``self.closed_faces()``:
r""" Return the face semigroup algebra of ``self``.
This is the semigroup algebra of the face semigroup of ``self`` (see :meth:`face_product` for the definition of the semigroup).
Due to limitations of the current Sage codebase (e.g., semigroup algebras do not profit from the functionality of the :class:`FiniteDimensionalAlgebra` class), this is implemented not as a semigroup algebra, but as a :class:`FiniteDimensionalAlgebra`. The closed faces of ``self`` (in the order in which the :meth:`closed_faces` method outputs them) are identified with the vectors `(0, 0, \ldots, 0, 1, 0, 0, \ldots, 0)` (with the `1` moving from left to right).
INPUT:
- ``field`` -- a field (default: `\mathbb{Q}`), to be used as the base ring for the algebra (can also be a commutative ring, but then certain representation-theoretical methods might misbehave)
- ``names`` -- (default: ``'e'``) string; names for the basis elements of the algebra
.. TODO::
Also implement it as an actual semigroup algebra?
EXAMPLES::
sage: a = hyperplane_arrangements.braid(3) sage: [(i, F[0]) for i, F in enumerate(a.closed_faces())] [(0, (0, 0, 0)), (1, (0, 1, 1)), (2, (0, -1, -1)), (3, (1, 0, 1)), (4, (1, 1, 1)), (5, (1, -1, 0)), (6, (1, -1, 1)), (7, (1, -1, -1)), (8, (-1, 0, -1)), (9, (-1, 1, 0)), (10, (-1, 1, 1)), (11, (-1, 1, -1)), (12, (-1, -1, -1))] sage: U = a.face_semigroup_algebra(); U Finite-dimensional algebra of degree 13 over Rational Field sage: e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() sage: e0 * e1 e1 sage: e0 * e5 e5 sage: e5 * e0 e5 sage: e3 * e2 e6 sage: e7 * e12 e7 sage: e3 * e12 e6 sage: e4 * e8 e4 sage: e8 * e4 e11 sage: e8 * e1 e11 sage: e5 * e12 e7 sage: (e3 + 2*e4) * (e1 - e7) e4 - e6
sage: U3 = a.face_semigroup_algebra(field=GF(3)); U3 Finite-dimensional algebra of degree 13 over Finite Field of size 3
TESTS:
The ``names`` keyword works::
sage: a = hyperplane_arrangements.braid(3) sage: U = a.face_semigroup_algebra(names='x'); U Finite-dimensional algebra of degree 13 over Rational Field sage: e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() sage: e0 * e1 x1 """ # ``Fs`` is the list of the sign vectors of all closed faces of # ``self``. # ``Fdict`` is a dictionary whose keys are the sign vectors of the # closed faces of ``self``, and whose values are their positions # in the list ``Fs``. # Some hackery to generate a matrix quickly and without # unnecessary sanitization/ducktyping: for l, sil in enumerate(si)]
r""" The region in the hyperplane arrangement containing a given point.
The base field must have characteristic zero.
INPUT:
- ``p`` -- point
OUTPUT:
A polyhedron. A ``ValueError`` is raised if the point is not interior to a region, that is, sits on a hyperplane.
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H([(1,0), 0], [(0,1), 1], [(0,1), -1], [(1,-1), 0], [(1,1), 0]) sage: A.region_containing_point([1,2]) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays
TESTS::
sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3]) sage: B = A.change_ring(FiniteField(7)) sage: B.region_containing_point((1,2)) Traceback (most recent call last): ... ValueError: base field must have characteristic zero
sage: A = H([(1,1),0], [(2,3),-1], [(4,5),3]) sage: A.region_containing_point((1,-1)) Traceback (most recent call last): ... ValueError: point sits on a hyperplane """ else:
def _bounded_region_indices(self): r""" Return the relatively bounded regions.
OUTPUT:
Tuple of integers. The positions of the relatively bounded regions in :meth:`regions`.
EXAMPLES::
sage: a = hyperplane_arrangements.semiorder(3) sage: a._bounded_region_indices() (2, 7, 8, 9, 10, 11, 16) """ lines=[hyperplane.normal() for hyperplane in self]) transverse = lambda poly: poly else: if transverse(region).is_compact())
r""" Return the relatively bounded regions of the arrangement.
A region is relatively bounded if its intersection with the space spanned by the normals to the hyperplanes is bounded. This is the same as being bounded in the case that the hyperplane arrangement is essential. It is assumed that the arrangement is defined over the rationals.
OUTPUT:
Tuple of polyhedra. The relatively bounded regions of the arrangement.
.. SEEALSO::
:meth:`unbounded_regions`
EXAMPLES::
sage: A = hyperplane_arrangements.semiorder(3) sage: A.bounded_regions() (A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line, A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 1 line) sage: A.bounded_regions()[0].is_compact() # the regions are only *relatively* bounded False sage: A.is_essential() False """
r""" Return the relatively bounded regions of the arrangement.
OUTPUT:
Tuple of polyhedra. The regions of the arrangement that are not relatively bounded. It is assumed that the arrangement is defined over the rationals.
.. SEEALSO::
:meth:`bounded_regions`
EXAMPLES::
sage: A = hyperplane_arrangements.semiorder(3) sage: B = A.essentialization() sage: B.n_regions() - B.n_bounded_regions() 12 sage: B.unbounded_regions() (A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 1 ray, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays) """
def whitney_data(self): r""" Return the Whitney numbers.
.. SEEALSO::
:meth:`whitney_number`, :meth:`doubly_indexed_whitney_number`
OUTPUT:
A pair of integer matrices. The two matrices are the doubly-indexed Whitney numbers of the first or second kind, respectively. The `i,j`-th entry is the `i,j`-th doubly-indexed Whitney number.
EXAMPLES::
sage: A = hyperplane_arrangements.Shi(3) sage: A.whitney_data() ( [ 1 -6 9] [ 1 6 6] [ 0 6 -15] [ 0 6 15] [ 0 0 6], [ 0 0 6] ) """
r""" Return the `i,j`-th doubly-indexed Whitney number.
If ``kind=1``, this number is obtained by adding the Möbius function values `mu(x,y)` over all `x, y` in the intersection poset with `\mathrm{rank}(x) = i` and `\mathrm{rank}(y) = j`.
If `kind=2`, this number is the number of elements `x,y` in the intersection poset such that `x \leq y` with ranks `i` and `j`, respectively.
INPUT:
- ``i``, ``j`` -- integers
- ``kind`` -- (default: 1) 1 or 2
OUTPUT:
Integer. The `(i,j)`-th entry of the ``kind`` Whitney number.
.. SEEALSO::
:meth:`whitney_number`, :meth:`whitney_data`
EXAMPLES::
sage: A = hyperplane_arrangements.Shi(3) sage: A.doubly_indexed_whitney_number(0, 2) 9 sage: A.whitney_number(2) 9 sage: A.doubly_indexed_whitney_number(1, 2) -15
REFERENCES:
- [GZ1983]_ """ elif kind == 2: return self.whitney_data()[1][i, j] raise ValueError('argument out of range')
r""" Return the ``k``-th Whitney number.
If ``kind=1``, this number is obtained by summing the Möbius function values `mu(0, x)` over all `x` in the intersection poset with `\mathrm{rank}(x) = k`.
If ``kind=2``, this number is the number of elements `x, y` in the intersection poset such that `x \leq y` with ranks `i` and `j`, respectively.
See [GZ1983]_ for more details.
INPUT:
- ``k`` -- integer
- ``kind`` -- 1 or 2 (default: 1)
OUTPUT:
Integer. The ``k``-th Whitney number.
.. SEEALSO::
:meth:`doubly_indexed_whitney_number` :meth:`whitney_data`
EXAMPLES::
sage: A = hyperplane_arrangements.Shi(3) sage: A.whitney_number(0) 1 sage: A.whitney_number(1) -6 sage: A.whitney_number(2) 9 sage: A.characteristic_polynomial() x^3 - 6*x^2 + 9*x sage: A.whitney_number(1,kind=2) 6 sage: p = A.intersection_poset() sage: r = p.rank_function() sage: len([i for i in p if r(i) == 1]) 6 """ raise ValueError('argument out of range')
r""" Test whether the ``hyperplane`` separates the given regions.
INPUT:
- ``region1``, ``region2`` -- polyhedra or list/tuple/iterable of coordinates which are regions of the arrangement or an interior point of a region
- ``hyperplane`` -- a hyperplane
OUTPUT:
A boolean. Whether the hyperplane ``hyperplane`` separate the given regions.
EXAMPLES::
sage: A.<x,y> = hyperplane_arrangements.coordinate(2) sage: A.is_separating_hyperplane([1,1], [2,1], y) False sage: A.is_separating_hyperplane([1,1], [-1,1], x) True sage: r = A.region_containing_point([1,1]) sage: s = A.region_containing_point([-1,1]) sage: A.is_separating_hyperplane(r, s, x) True """ raise ValueError('requires characteristic zero') raise ValueError('point lies on hyperplane')
r""" Return the number of hyperplanes separating the two regions.
INPUT:
- ``region1``, ``region2`` -- regions of the arrangement or representative points of regions
OUTPUT:
An integer. The number of hyperplanes separating the two regions.
EXAMPLES::
sage: c = hyperplane_arrangements.coordinate(2) sage: r = c.region_containing_point([-1, -1]) sage: s = c.region_containing_point([1, 1]) sage: c.distance_between_regions(r, s) 2 sage: c.distance_between_regions(s, s) 0 """ if self.is_separating_hyperplane(region1, region2, hyperplane))
r""" Return the generating function for the number of hyperplanes at given distance.
INPUT:
- ``base_region`` -- region of arrangement or point in region
OUTPUT:
A polynomial `f(x)` for which the coefficient of `x^i` is the number of hyperplanes of distance `i` from ``base_region``, i.e., the number of hyperplanes separated by `i` hyperplanes from ``base_region``.
EXAMPLES::
sage: c = hyperplane_arrangements.coordinate(3) sage: c.distance_enumerator(c.region_containing_point([1,1,1])) x^3 + 3*x^2 + 3*x + 1 """
r""" Return the Varchenko matrix of the arrangement.
Let `H_1, \ldots, H_s` and `R_1, \ldots, R_t` denote the hyperplanes and regions, respectively, of the arrangement. Let `S = \QQ[h_1, \ldots, h_s]`, a polynomial ring with indeterminate `h_i` corresponding to hyperplane `H_i`. The Varchenko matrix is the `t \times t` matrix with `i,j`-th entry the product of those `h_k` such that `H_k` separates `R_i` and `R_j`.
INPUT:
- ``names`` -- string or list/tuple/iterable of strings. The variable names for the polynomial ring `S`.
OUTPUT:
The Varchenko matrix.
EXAMPLES::
sage: a = hyperplane_arrangements.coordinate(3) sage: v = a.varchenko_matrix(); v [ 1 h2 h1] [ h2 1 h1*h2] [ h1 h1*h2 1] sage: factor(det(v)) (h2 - 1) * (h2 + 1) * (h1 - 1) * (h1 + 1) """ self.is_separating_hyperplane(region[i], region[j], self[p]))
def matroid(self): r""" Return the matroid associated to ``self``.
Let `A` denote a central hyperplane arrangement and `n_H` the normal vector of some hyperplane `H \in A`. We define a matroid `M_A` as the linear matroid spanned by `\{ n_H | H \in A \}`. The matroid `M_A` is such that the lattice of flats of `M` is isomorphic to the intersection lattice of `A` (Proposition 3.6 in [Sta2007]_).
EXAMPLES::
sage: P.<x,y,z> = HyperplaneArrangements(QQ) sage: A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z) sage: M = A.matroid(); M Linear matroid of rank 3 on 7 elements represented over the Rational Field
We check the lattice of flats is isomorphic to the intersection lattice::
sage: f = sum([list(M.flats(i)) for i in range(M.rank()+1)], []) sage: PF = Poset([f, lambda x,y: x < y]) sage: PF.is_isomorphic(A.intersection_poset()) True """ raise ValueError("the hyperplane arrangement must be central")
""" Return the Orlik-Solomon algebra of ``self``.
INPUT:
- ``base_ring`` -- (default: the base field of ``self``) the ring over which the Orlik-Solomon algebra will be defined - ``ordering`` -- (optional) an ordering of the ground set
EXAMPLES::
sage: P.<x,y,z> = HyperplaneArrangements(QQ) sage: A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z) sage: A.orlik_solomon_algebra() Orlik-Solomon algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field sage: A.orlik_solomon_algebra(base_ring=ZZ) Orlik-Solomon algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field """
def minimal_generated_number(self): r""" Return the minimum `k` such that ``self`` is `k`-generated.
Let `A` be a central hyperplane arrangement. Let `W_k` denote the solution space of the linear system corresponding to the linear dependencies among the hyperplanes of `A` of length at most `k`. We say `A` is `k`-*generated* if `\dim W_k = \operatorname{rank} A`.
Equivalently this says all dependencies forming the Orlik-Terao ideal are generated by at most `k` hyperplanes.
EXAMPLES:
We construct Example 2.2 from [Yuz1993]_::
sage: P.<x,y,z> = HyperplaneArrangements(QQ) sage: A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, 3*x+5*z, 3*x+4*y+5*z) sage: B = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, x+3*z, x+2*y+3*z) sage: A.minimal_generated_number() 3 sage: B.minimal_generated_number() 4 """ return self.n_hyperplanes()
""" Return if ``self`` is formal.
A hyperplane arrangement is *formal* if it is 3-generated [Yuz1993]_, where `k`-generated is defined in :meth:`minimal_generated_number`.
EXAMPLES::
sage: P.<x,y,z> = HyperplaneArrangements(QQ) sage: A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, 3*x+5*z, 3*x+4*y+5*z) sage: B = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z, x+3*z, x+2*y+3*z) sage: A.is_formal() True sage: B.is_formal() False """
r""" Return the defining polynomial of ``A``.
Let `A = (H_i)_i` be a hyperplane arrangement in a vector space `V` corresponding to the null spaces of `\alpha_{H_i} \in V^*`. Then the *defining polynomial* of `A` is given by
.. MATH::
Q(A) = \prod_i \alpha_{H_i} \in S(V^*).
EXAMPLES::
sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: A = H([2*x + y - z, -x - 2*y + z]) sage: p = A.defining_polynomial(); p -2*x^2 - 5*x*y - 2*y^2 + 3*x*z + 3*y*z - z^2 sage: p.factor() (-1) * (x + 2*y - z) * (2*x + y - z) """
def derivation_module_free_chain(self): r""" Return a free chain for the derivation module if one exists, otherwise return ``None``.
.. SEEALSO::
:meth:`is_free`
EXAMPLES::
sage: W = WeylGroup(['A',3], prefix='s') sage: A = W.long_element().inversion_arrangement() sage: for M in A.derivation_module_free_chain(): print("%s\n"%M) [ 1 0 0] [ 0 1 0] [ 0 0 a3] <BLANKLINE> [ 1 0 0] [ 0 0 1] [ 0 a2 0] <BLANKLINE> [ 1 0 0] [ 0 -1 -1] [ 0 a2 -a3] <BLANKLINE> [ 0 1 0] [ 0 0 1] [a1 0 0] <BLANKLINE> [ 1 0 -1] [a3 -1 0] [a1 0 a2] <BLANKLINE> [ 1 0 0] [ a3 -1 -1] [ 0 a1 -a2 - a3] <BLANKLINE> """ raise NotImplementedError("only implemented for central arrangements")
""" Return if ``self`` is free.
A hyperplane arrangement `A` is free if the module of derivations `\operatorname{Der}(A)` is a free `S`-module, where `S` is the corresponding symmetric space.
INPUT:
- ``algorithm`` -- (default: ``"singular"``) can be one of the following:
* ``"singular"`` -- use Singular's minimal free resolution * ``"BC"`` -- use the algorithm given by Barakat and Cuntz in [BC2012]_ (much slower than using Singular)
ALGORITHM:
.. RUBRIC:: singular
Check that the minimal free resolution has length at most 2 by using Singular.
.. RUBRIC:: BC
This implementation follows [BC2012]_ by constructing a chain of free modules
.. MATH::
D(A) = D(A_n) < D(A_{n-1}) < \cdots < D(A_1) < D(A_0)
corresponding to some ordering of the arrangements `A_0 \subset A_1 \subset \cdots \subset A_{n-1} \subset A_n = A`. Such a chain is found by using a backtracking algorithm.
EXAMPLES:
For type `A` arrangements, chordality is equivalent to freeness. We verify that in type `A_3`::
sage: W = WeylGroup(['A',3], prefix='s') sage: for x in W: ....: A = x.inversion_arrangement() ....: assert A.matroid().is_chordal() == A.is_free()
TESTS:
We check that the algorithms agree::
sage: W = WeylGroup(['B',3], prefix='s') sage: for x in W: # long time ....: A = x.inversion_arrangement() ....: assert (A.is_free(algorithm="BC") ....: == A.is_free(algorithm="singular")) """ raise NotImplementedError("only implemented for central arrangements") # TODO: Implement this using libSingular elif algorithm == "BC": return self.derivation_module_free_chain() is not None else: raise ValueError("invalid algorithm")
""" Return a basis for the derivation module of ``self`` if one exists, otherwise return ``None``.
.. SEEALSO::
:meth:`derivation_module_free_chain`, :meth:`is_free`
INPUT:
- ``algorithm`` -- (default: ``"singular"``) can be one of the following:
* ``"singular"`` -- use Singular's minimal free resolution * ``"BC"`` -- use the algorithm given by Barakat and Cuntz in [BC2012]_ (much slower than using Singular)
OUTPUT:
A basis for the derivation module (over `S`, the :meth:`symmetric space <sage.geometry.hyperplane_arrangement.hyperplane.AmbientVectorSpace.symmetric_space>`) as vectors of a free module over `S`.
ALGORITHM:
.. RUBRIC:: Singular
This gets the reduced syzygy module of the Jacobian ideal of the defining polynomial `f` of ``self``. It then checks Saito's criterion that the determinant of the basis matrix is a scalar multiple of `f`. If the basis matrix is not square or it fails Saito's criterion, then we check if the arrangement is free. If it is free, then we fall back to the Barakat-Cuntz algorithm.
.. RUBRIC:: BC
Return the product of the derivation module free chain matrices. See Section 6 of [BC2012]_.
EXAMPLES::
sage: W = WeylGroup(['A',2], prefix='s') sage: A = W.long_element().inversion_arrangement() sage: A.derivation_module_basis() [(a1, a2), (0, a1*a2 + a2^2)]
TESTS:
We check the algorithms produce a basis with the same exponents::
sage: W = WeylGroup(['A',2], prefix='s') sage: exponents = lambda B: sorted([max(x.degree() for x in b) ....: for b in B]) sage: for x in W: # long time ....: A = x.inversion_arrangement() ....: B = A.derivation_module_basis(algorithm="singular") ....: Bp = A.derivation_module_basis(algorithm="BC") ....: if B is None: ....: assert Bp is None ....: else: ....: assert exponents(B) == exponents(Bp) """ #import sage.libs.singular.function_factory #syz = sage.libs.singular.function_factory.ff.syz # Check using Saito's criterion except ValueError: # Non-square matrix or det = 0 pass # Check if it is free if not self.is_free(algorithm=alg): return None # The syzygy module did not give a basis, but since it is free, # fallback to the Barakat-Cuntz method alg = "BC" if alg == "BC": C = self.derivation_module_free_chain() if C is not None: if not C: # C is an empty list S = self.parent().ambient_space().symmetric_space() return matrix.identity(S, self.dimension()).rows() from sage.misc.misc_c import prod return prod(reversed(C)).rows() return None else: raise ValueError("invalid algorithm")
""" Hyperplane arrangements.
For more information on hyperplane arrangements, see :mod:`sage.geometry.hyperplane_arrangement.arrangement`.
INPUT:
- ``base_ring`` -- ring; the base ring
- ``names`` -- tuple of strings; the variable names
EXAMPLES::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: x Hyperplane x + 0*y + 0 sage: x + y Hyperplane x + y + 0 sage: H(x, y, x-1, y-1) Arrangement <y - 1 | y | x - 1 | x> """
""" Initialize ``self``.
TESTS::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: K = HyperplaneArrangements(QQ, names=('x', 'y')) sage: H is K True sage: type(K) <class 'sage.geometry.hyperplane_arrangement.arrangement.HyperplaneArrangements_with_category'> sage: K.change_ring(RR).gen(0) Hyperplane 1.00000000000000*x + 0.000000000000000*y + 0.000000000000000
TESTS::
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: TestSuite(H).run() sage: K = HyperplaneArrangements(QQ) sage: TestSuite(K).run() """ raise ValueError('base ring must be a field')
""" Return the base ring.
OUTPUT:
The base ring of the hyperplane arrangement.
EXAMPLES::
sage: L.<x,y> = HyperplaneArrangements(QQ) sage: L.base_ring() Rational Field """
""" Return hyperplane arrangements over a different base ring.
INPUT:
- ``base_ring`` -- a ring; the new base ring.
OUTPUT:
A new :class:`HyperplaneArrangements` instance over the new base ring.
EXAMPLES::
sage: L.<x,y> = HyperplaneArrangements(QQ) sage: L.gen(0) Hyperplane x + 0*y + 0 sage: L.change_ring(RR).gen(0) Hyperplane 1.00000000000000*x + 0.000000000000000*y + 0.000000000000000
TESTS::
sage: L.change_ring(QQ) is L True """
def ambient_space(self): """ Return the ambient space.
The ambient space is the parent of hyperplanes. That is, new hyperplanes are always constructed internally from the ambient space instance.
EXAMPLES::
sage: L.<x, y> = HyperplaneArrangements(QQ) sage: L.ambient_space()([(1,0), 0]) Hyperplane x + 0*y + 0 sage: L.ambient_space()([(1,0), 0]) == x True """
""" Return a string representation.
OUTPUT:
A string.
EXAMPLES::
sage: L.<x, y> = HyperplaneArrangements(QQ); L Hyperplane arrangements in 2-dimensional linear space over Rational Field with coordinates x, y """
""" Construct an element of ``self``.
INPUT:
- ``*args`` -- positional arguments, each defining a hyperplane; alternatively, a single polytope or a single hyperplane arrangement
- ``signed`` -- boolean (optional, default: ``True``); whether to preserve signs of hyperplane equations
- ``warn_duplicates`` -- boolean (optional, default: ``False``); whether to issue a warning if duplicate hyperplanes were passed -- note that duplicate hyperplanes are always removed, whether or not there is a warning shown
- ``check`` -- boolean (optional, default: ``True``); whether to perform argument checking.
EXAMPLES::
sage: L.<x, y> = HyperplaneArrangements(QQ) sage: L._element_constructor_(x, y) Arrangement <y | x> sage: L._element_constructor_([x, y]) Arrangement <y | x> sage: L._element_constructor_([0, 1, 0], [0, 0, 1]) Arrangement <y | x> sage: L._element_constructor_([[0, 1, 0], [0, 0, 1]]) Arrangement <y | x>
sage: L._element_constructor_(polytopes.hypercube(2)) Arrangement <-x + 1 | -y + 1 | y + 1 | x + 1>
sage: L(x, x, warn_duplicates=True) doctest:...: UserWarning: Input contained 2 hyperplanes, but only 1 are distinct. Arrangement <x> sage: L(-x, x + y - 1, signed=False) Arrangement <-x - y + 1 | x>
TESTS::
sage: L() Empty hyperplane arrangement of dimension 2 sage: L(0) # zero is equivalent to no argument, Trac #8648 Empty hyperplane arrangement of dimension 2 sage: L(0*x) # degenerate hyperplane is NOT allowed Traceback (most recent call last): ... ValueError: linear expression must be non-constant to define a hyperplane sage: L(0*x, y) # ditto Traceback (most recent call last): ... ValueError: linear expression must be non-constant to define a hyperplane """ # optimization if argument is already a hyperplane arrangement return arg # zero = neutral element under addition = the empty hyperplane arrangement # process keyword arguments raise ValueError('unknown keyword argument') # process positional arguments raise else: # argument checking (optional but recommended) raise ValueError('cannot be signed in characteristic 2') raise ValueError('arrangement cannot simultaneously have h and -h as hyperplane')
def ngens(self): """ Return the number of linear variables.
OUTPUT:
An integer.
EXAMPLES::
sage: L.<x, y, z> = HyperplaneArrangements(QQ); L Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z sage: L.ngens() 3 """
def gens(self): """ Return the coordinate hyperplanes.
OUTPUT:
A tuple of linear expressions, one for each linear variable.
EXAMPLES::
sage: L = HyperplaneArrangements(QQ, ('x', 'y', 'z')) sage: L.gens() (Hyperplane x + 0*y + 0*z + 0, Hyperplane 0*x + y + 0*z + 0, Hyperplane 0*x + 0*y + z + 0) """
""" Return the `i`-th coordinate hyperplane.
INPUT:
- ``i`` -- integer
OUTPUT:
A linear expression.
EXAMPLES::
sage: L.<x, y, z> = HyperplaneArrangements(QQ); L Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z sage: L.gen(0) Hyperplane x + 0*y + 0*z + 0 """
""" Return whether there is a coercion.
TESTS::
sage: L.<x> = HyperplaneArrangements(QQ); L Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x sage: M.<y> = HyperplaneArrangements(RR); M Hyperplane arrangements in 1-dimensional linear space over Real Field with 53 bits of precision with coordinate y
sage: L.coerce_map_from(ZZ) Coercion map: From: Integer Ring To: Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x sage: M.coerce_map_from(L) Coercion map: From: Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x To: Hyperplane arrangements in 1-dimensional linear space over Real Field with 53 bits of precision with coordinate y sage: L.coerce_map_from(M) """
|