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 \(3x + 3y - 5z = 7\). To create it
in Sage, you first have to create a 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
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = Integer(3)*x + Integer(2)*y - Integer(5)*z - Integer(7); h
Hyperplane 3*x + 2*y - 5*z - 7
>>> h.normal()
(3, 2, -5)
>>> h.constant_term()
-7
H.<x,y,z> = HyperplaneArrangements(QQ) h = 3*x + 2*y - 5*z - 7; h h.normal() h.constant_term()
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)
>>> from sage.all import *
>>> -Integer(2)*h
Hyperplane -6*x - 4*y + 10*z + 14
>>> x, y, z
(Hyperplane x + 0*y + 0*z + 0,
Hyperplane 0*x + y + 0*z + 0,
Hyperplane 0*x + 0*y + z + 0)
-2*h x, y, z
See 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
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
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2)
>>> box = x | y | x-Integer(1) | y-Integer(1); box
Arrangement <y - 1 | y | x - 1 | x>
>>> box == H(x, y, x-Integer(1), y-Integer(1)) # alternative syntax
True
H.<x,y> = HyperplaneArrangements(QQ) box = x | y | x-1 | y-1; box box == H(x, y, x-1, y-1) # alternative syntax
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
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, ('x', 'y'))
>>> triangle = H([(Integer(1), Integer(0)), Integer(0)], [(Integer(0), Integer(1)), Integer(0)], [(Integer(1),Integer(1)), -Integer(1)]); triangle
Arrangement <y | x | x + y - 1>
>>> H.inject_variables()
Defining x, y
>>> triangle == x | y | x+y-Integer(1)
True
H = HyperplaneArrangements(QQ, ('x', 'y')) triangle = H([(1, 0), 0], [(0, 1), 0], [(1,1), -1]); triangle H.inject_variables() triangle == x | y | x+y-1
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>
>>> from sage.all import *
>>> H = HyperplaneArrangements(GF(Integer(5)), names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> a = H([(Integer(1),Integer(2),Integer(3)), Integer(4)], [(Integer(5),Integer(6),Integer(7)), Integer(8)]); a
Arrangement <y + 2*z + 3 | x + 2*y + 3*z + 4>
H.<x,y,z> = HyperplaneArrangements(GF(5)) a = H([(1,2,3), 4], [(5,6,7), 8]); a
Number fields are also possible:
sage: # needs sage.rings.number_field
sage: x = polygen(QQ, 'x')
sage: NF.<a> = NumberField(x**4 - 5*x**2 + 5, embedding=1.90)
sage: H.<y,z> = HyperplaneArrangements(NF)
sage: A = H([[(-a**3 + 3*a, -a**2 + 4), 1], [(a**3 - 4*a, -1), 1],
....: [(0, 2*a**2 - 6), 1], [(-a**3 + 4*a, -1), 1],
....: [(a**3 - 3*a, -a**2 + 4), 1]])
sage: A
Arrangement of 5 hyperplanes of dimension 2 and rank 2
sage: A.base_ring()
Number Field in a with defining polynomial x^4 - 5*x^2 + 5
with a = 1.902113032590308?
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> x = polygen(QQ, 'x')
>>> NF = NumberField(x**Integer(4) - Integer(5)*x**Integer(2) + Integer(5), embedding=RealNumber('1.90'), names=('a',)); (a,) = NF._first_ngens(1)
>>> H = HyperplaneArrangements(NF, names=('y', 'z',)); (y, z,) = H._first_ngens(2)
>>> A = H([[(-a**Integer(3) + Integer(3)*a, -a**Integer(2) + Integer(4)), Integer(1)], [(a**Integer(3) - Integer(4)*a, -Integer(1)), Integer(1)],
... [(Integer(0), Integer(2)*a**Integer(2) - Integer(6)), Integer(1)], [(-a**Integer(3) + Integer(4)*a, -Integer(1)), Integer(1)],
... [(a**Integer(3) - Integer(3)*a, -a**Integer(2) + Integer(4)), Integer(1)]])
>>> A
Arrangement of 5 hyperplanes of dimension 2 and rank 2
>>> A.base_ring()
Number Field in a with defining polynomial x^4 - 5*x^2 + 5
with a = 1.902113032590308?
# needs sage.rings.number_field x = polygen(QQ, 'x') NF.<a> = NumberField(x**4 - 5*x**2 + 5, embedding=1.90) H.<y,z> = HyperplaneArrangements(NF) A = H([[(-a**3 + 3*a, -a**2 + 4), 1], [(a**3 - 4*a, -1), 1], [(0, 2*a**2 - 6), 1], [(-a**3 + 4*a, -1), 1], [(a**3 - 3*a, -a**2 + 4), 1]]) A A.base_ring()
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>
>>> from sage.all import *
>>> H = HyperplaneArrangements(GF(Integer(5)), names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> k = [x+i for i in range(Integer(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]
>>> H(k)
Arrangement <x | x + 1 | x + 2 | x + 3>
H.<x,y,z> = HyperplaneArrangements(GF(5)) k = [x+i for i in range(4)]; k H(k)
Notation (iv): using the library of arrangements:
sage: hyperplane_arrangements.braid(4) # needs sage.graphs
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()) # needs sage.graphs
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
>>> from sage.all import *
>>> hyperplane_arrangements.braid(Integer(4)) # needs sage.graphs
Arrangement of 6 hyperplanes of dimension 4 and rank 3
>>> hyperplane_arrangements.semiorder(Integer(3))
Arrangement of 6 hyperplanes of dimension 3 and rank 2
>>> hyperplane_arrangements.graphical(graphs.PetersenGraph()) # needs sage.graphs
Arrangement of 15 hyperplanes of dimension 10 and rank 9
>>> hyperplane_arrangements.Ish(Integer(5))
Arrangement of 20 hyperplanes of dimension 5 and rank 4
hyperplane_arrangements.braid(4) # needs sage.graphs hyperplane_arrangements.semiorder(3) hyperplane_arrangements.graphical(graphs.PetersenGraph()) # needs sage.graphs hyperplane_arrangements.Ish(5)
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
>>> from sage.all import *
>>> a = polytopes.cube().hyperplane_arrangement(); a
Arrangement of 6 hyperplanes of dimension 3 and rank 3
>>> a.n_regions()
27
a = polytopes.cube().hyperplane_arrangement(); a a.n_regions()
New arrangements from old:
sage: # needs sage.graphs
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: # needs sage.combinat sage.graphs
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
>>> from sage.all import *
>>> # needs sage.graphs
>>> a = hyperplane_arrangements.braid(Integer(3))
>>> b = a.add_hyperplane([Integer(4), Integer(1), Integer(2), Integer(3)])
>>> b
Arrangement <t1 - t2 | t0 - t1 | t0 - t2 | t0 + 2*t1 + 3*t2 + 4>
>>> c = b.deletion([Integer(4), Integer(1), Integer(2), Integer(3)])
>>> a == c
True
>>> # needs sage.combinat sage.graphs
>>> a = hyperplane_arrangements.braid(Integer(3))
>>> b = a.union(hyperplane_arrangements.semiorder(Integer(3)))
>>> b == a | hyperplane_arrangements.semiorder(Integer(3)) # alternate syntax
True
>>> b == hyperplane_arrangements.Catalan(Integer(3))
True
>>> a
Arrangement <t1 - t2 | t0 - t1 | t0 - t2>
>>> a = hyperplane_arrangements.coordinate(Integer(4))
>>> h = a.hyperplanes()[Integer(0)]
>>> b = a.restriction(h)
>>> b == hyperplane_arrangements.coordinate(Integer(3))
True
# needs sage.graphs a = hyperplane_arrangements.braid(3) b = a.add_hyperplane([4, 1, 2, 3]) b c = b.deletion([4, 1, 2, 3]) a == c # needs sage.combinat sage.graphs a = hyperplane_arrangements.braid(3) b = a.union(hyperplane_arrangements.semiorder(3)) b == a | hyperplane_arrangements.semiorder(3) # alternate syntax b == hyperplane_arrangements.Catalan(3) a a = hyperplane_arrangements.coordinate(4) h = a.hyperplanes()[0] b = a.restriction(h) b == hyperplane_arrangements.coordinate(3)
Properties of Arrangements¶
A hyperplane arrangement is essential if the normals to its hyperplanes 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: # needs sage.graphs
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
>>> from sage.all import *
>>> # needs sage.graphs
>>> a = hyperplane_arrangements.braid(Integer(4)); a
Arrangement of 6 hyperplanes of dimension 4 and rank 3
>>> a.is_essential()
False
>>> a.rank() < a.dimension() # double-check
True
>>> a.essentialization()
Arrangement of 6 hyperplanes of dimension 3 and rank 3
# needs sage.graphs a = hyperplane_arrangements.braid(4); a a.is_essential() a.rank() < a.dimension() # double-check a.essentialization()
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)
>>> from sage.all import *
>>> a = hyperplane_arrangements.semiorder(Integer(3))
>>> b = a.essentialization(); b
Arrangement of 6 hyperplanes of dimension 2 and rank 2
>>> b.n_regions()
19
>>> 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)
>>> 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)
>>> b.n_bounded_regions()
7
>>> 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)
a = hyperplane_arrangements.semiorder(3) b = a.essentialization(); b b.n_regions() b.regions() b.bounded_regions() b.n_bounded_regions() a.unbounded_regions()
The distance between regions is defined as the number of hyperplanes separating them. For example:
sage: # needs sage.combinat
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
>>> from sage.all import *
>>> # needs sage.combinat
>>> r1 = b.regions()[Integer(0)]
>>> r2 = b.regions()[Integer(1)]
>>> b.distance_between_regions(r1, r2)
1
>>> [hyp for hyp in b if b.is_separating_hyperplane(r1, r2, hyp)]
[Hyperplane 2*t1 + t2 + 1]
>>> b.distance_enumerator(r1) # generating function for distances from r1
6*x^3 + 6*x^2 + 6*x + 1
# needs sage.combinat r1 = b.regions()[0] r2 = b.regions()[1] b.distance_between_regions(r1, r2) [hyp for hyp in b if b.is_separating_hyperplane(r1, r2, hyp)] b.distance_enumerator(r1) # generating function for distances from r1
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: # needs sage.graphs
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
>>> from sage.all import *
>>> # needs sage.graphs
>>> a = hyperplane_arrangements.braid(Integer(3))
>>> p = a.intersection_poset()
>>> p.is_ranked()
True
>>> p.order_polytope()
A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 10 vertices
# needs sage.graphs a = hyperplane_arrangements.braid(3) p = a.intersection_poset() p.is_ranked() p.order_polytope()
The characteristic polynomial is a basic invariant of a hyperplane arrangement. It is defined as
where \(P\) is the
intersection_poset()
of the
arrangement and \(\mu\) is the Möbius function of \(P\):
sage: # long time
sage: a = hyperplane_arrangements.semiorder(5)
sage: a.characteristic_polynomial() # about a second on Core i7
x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x
sage: a.poincare_polynomial()
1380*x^4 + 790*x^3 + 180*x^2 + 20*x + 1
sage: a.n_regions()
2371
sage: charpoly = a.characteristic_polynomial()
sage: charpoly(-1)
-2371
sage: a.n_bounded_regions()
751
sage: charpoly(1)
751
>>> from sage.all import *
>>> # long time
>>> a = hyperplane_arrangements.semiorder(Integer(5))
>>> a.characteristic_polynomial() # about a second on Core i7
x^5 - 20*x^4 + 180*x^3 - 790*x^2 + 1380*x
>>> a.poincare_polynomial()
1380*x^4 + 790*x^3 + 180*x^2 + 20*x + 1
>>> a.n_regions()
2371
>>> charpoly = a.characteristic_polynomial()
>>> charpoly(-Integer(1))
-2371
>>> a.n_bounded_regions()
751
>>> charpoly(Integer(1))
751
# long time a = hyperplane_arrangements.semiorder(5) a.characteristic_polynomial() # about a second on Core i7 a.poincare_polynomial() a.n_regions() charpoly = a.characteristic_polynomial() charpoly(-1) a.n_bounded_regions() charpoly(1)
For finer invariants derived from the intersection poset, see
whitney_number()
and
doubly_indexed_whitney_number()
.
Miscellaneous methods (see documentation for an explanation):
sage: a = hyperplane_arrangements.semiorder(3)
sage: a.has_good_reduction(5) # needs sage.rings.finite_rings
True
sage: b = a.change_ring(GF(5))
sage: pa = a.intersection_poset() # needs sage.graphs
sage: pb = b.intersection_poset() # needs sage.rings.finite_rings
sage: pa.is_isomorphic(pb) # needs sage.graphs sage.rings.finite_rings
True
sage: a.face_vector() # needs sage.graphs
(0, 12, 30, 19)
sage: a.face_vector() # needs sage.graphs
(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()[:6, :6]
[ 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]
>>> from sage.all import *
>>> a = hyperplane_arrangements.semiorder(Integer(3))
>>> a.has_good_reduction(Integer(5)) # needs sage.rings.finite_rings
True
>>> b = a.change_ring(GF(Integer(5)))
>>> pa = a.intersection_poset() # needs sage.graphs
>>> pb = b.intersection_poset() # needs sage.rings.finite_rings
>>> pa.is_isomorphic(pb) # needs sage.graphs sage.rings.finite_rings
True
>>> a.face_vector() # needs sage.graphs
(0, 12, 30, 19)
>>> a.face_vector() # needs sage.graphs
(0, 12, 30, 19)
>>> a.is_central()
False
>>> a.is_linear()
False
>>> a.sign_vector((Integer(1),Integer(1),Integer(1)))
(-1, 1, -1, 1, -1, 1)
>>> a.varchenko_matrix()[:Integer(6), :Integer(6)]
[ 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]
a = hyperplane_arrangements.semiorder(3) a.has_good_reduction(5) # needs sage.rings.finite_rings b = a.change_ring(GF(5)) pa = a.intersection_poset() # needs sage.graphs pb = b.intersection_poset() # needs sage.rings.finite_rings pa.is_isomorphic(pb) # needs sage.graphs sage.rings.finite_rings a.face_vector() # needs sage.graphs a.face_vector() # needs sage.graphs a.is_central() a.is_linear() a.sign_vector((1,1,1)) a.varchenko_matrix()[:6, :6]
There are extensive methods for visualizing hyperplane arrangements in
low dimensions. See plot()
for
details.
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.
- class sage.geometry.hyperplane_arrangement.arrangement.HyperplaneArrangementElement(parent, hyperplanes, check=True, backend=None)[source]¶
Bases:
Element
A hyperplane arrangement.
Warning
You should never create
HyperplaneArrangementElement
instances directly, always use the parent.- add_hyperplane(other)[source]¶
The union of
self
withother
.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: C = A.union(B); C Arrangement of 8 hyperplanes of dimension 2 and rank 2 sage: C == A | B # syntactic sugar True
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([Integer(1),Integer(2),Integer(3)], [Integer(0),Integer(1),Integer(1)], [Integer(0),Integer(1),-Integer(1)], [Integer(1),-Integer(1),Integer(0)], [Integer(1),Integer(1),Integer(0)]) >>> B = H([Integer(1),Integer(1),Integer(1)], [Integer(1),-Integer(1),Integer(1)], [Integer(1),Integer(0),-Integer(1)]) >>> C = A.union(B); C Arrangement of 8 hyperplanes of dimension 2 and rank 2 >>> C == A | B # syntactic sugar True
H.<x,y> = HyperplaneArrangements(QQ) A = H([1,2,3], [0,1,1], [0,1,-1], [1,-1,0], [1,1,0]) B = H([1,1,1], [1,-1,1], [1,0,-1]) C = A.union(B); C C == A | B # syntactic sugar
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
>>> from sage.all import * >>> A.union(x+y-Integer(1)) Arrangement of 6 hyperplanes of dimension 2 and rank 2 >>> A.add_hyperplane(x+y-Integer(1)) # alias Arrangement of 6 hyperplanes of dimension 2 and rank 2 >>> P = HyperplaneArrangements(RR, names=('x', 'y',)); (x, y,) = P._first_ngens(2) >>> C = P(Integer(2)*x + Integer(4)*y + Integer(5)) >>> C.union(A) Arrangement of 6 hyperplanes of dimension 2 and rank 2
A.union(x+y-1) A.add_hyperplane(x+y-1) # alias P.<x,y> = HyperplaneArrangements(RR) C = P(2*x + 4*y + 5) C.union(A)
- backend()[source]¶
Return the backend used for polyhedral objects.
OUTPUT: string giving the backend or
None
if none is specifiedEXAMPLES:
By default, no backend is specified:
sage: H = HyperplaneArrangements(QQ) sage: A = H() sage: A.backend()
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ) >>> A = H() >>> A.backend()
H = HyperplaneArrangements(QQ) A = H() A.backend()
Otherwise, one may specify a polyhedral backend:
sage: A = H(backend='ppl') sage: A.backend() 'ppl' sage: A = H(backend='normaliz') sage: A.backend() 'normaliz'
>>> from sage.all import * >>> A = H(backend='ppl') >>> A.backend() 'ppl' >>> A = H(backend='normaliz') >>> A.backend() 'normaliz'
A = H(backend='ppl') A.backend() A = H(backend='normaliz') A.backend()
- bounded_regions()[source]¶
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.
See also
EXAMPLES:
sage: # needs sage.combinat 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
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.semiorder(Integer(3)) >>> 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) >>> A.bounded_regions()[Integer(0)].is_compact() # the regions are only *relatively* bounded False >>> A.is_essential() False
# needs sage.combinat A = hyperplane_arrangements.semiorder(3) A.bounded_regions() A.bounded_regions()[0].is_compact() # the regions are only *relatively* bounded A.is_essential()
- center()[source]¶
Return the center of the hyperplane arrangement.
The polyhedron defined to be the set of all points in the ambient space of the arrangement that lie on all of the hyperplanes.
OUTPUT: a polyhedron
EXAMPLES:
The empty hyperplane arrangement has the entire ambient space as its center:
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H() sage: A.center() A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H() >>> A.center() A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines
H.<x,y> = HyperplaneArrangements(QQ) A = H() A.center()
The Shi arrangement in dimension 3 has an empty center:
sage: A = hyperplane_arrangements.Shi(3) sage: A.center() The empty polyhedron in QQ^3
>>> from sage.all import * >>> A = hyperplane_arrangements.Shi(Integer(3)) >>> A.center() The empty polyhedron in QQ^3
A = hyperplane_arrangements.Shi(3) A.center()
The Braid arrangement in dimension 3 has a center that is neither empty nor full-dimensional:
sage: A = hyperplane_arrangements.braid(3) # needs sage.combinat sage: A.center() # needs sage.combinat A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line
>>> from sage.all import * >>> A = hyperplane_arrangements.braid(Integer(3)) # needs sage.combinat >>> A.center() # needs sage.combinat A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line
A = hyperplane_arrangements.braid(3) # needs sage.combinat A.center() # needs sage.combinat
- change_ring(base_ring)[source]¶
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 ofself.change_ring(base_ring)
, there is no guarantee that the order in which they appear inself.hyperplanes()
will match the order in which their counterparts inself.cone()
will appear inself.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>
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([(Integer(1),Integer(1)), Integer(0)], [(Integer(2),Integer(3)), -Integer(1)]) >>> A.change_ring(FiniteField(Integer(2))) Arrangement <y + 1 | x + y>
H.<x,y> = HyperplaneArrangements(QQ) A = H([(1,1), 0], [(2,3), -1]) A.change_ring(FiniteField(2))
- characteristic_polynomial()[source]¶
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
>>> from sage.all import * >>> a = hyperplane_arrangements.coordinate(Integer(2)) >>> a.characteristic_polynomial() x^2 - 2*x + 1
a = hyperplane_arrangements.coordinate(2) a.characteristic_polynomial()
- closed_faces(labelled=True)[source]¶
Return the closed faces of the hyperplane arrangement
self
(provided thatself
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
); ifTrue
, 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 byself.hyperplanes()
).
OUTPUT:
A tuple containing the closed faces as polyhedra, or (if
labelled
is set toTrue
) 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: # needs sage.graphs 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: # needs sage.graphs 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))]
>>> from sage.all import * >>> # needs sage.graphs >>> a = hyperplane_arrangements.braid(Integer(2)) >>> a.hyperplanes() (Hyperplane t0 - t1 + 0,) >>> 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)) >>> 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) >>> [(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))] >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> a = H(x, y+Integer(1)) >>> a.hyperplanes() (Hyperplane 0*x + y + 1, Hyperplane x + 0*y + 0) >>> [(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))] >>> # needs sage.graphs >>> a = hyperplane_arrangements.braid(Integer(3)) >>> a.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) >>> [(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))]
# needs sage.graphs a = hyperplane_arrangements.braid(2) a.hyperplanes() a.closed_faces() a.closed_faces(labelled=False) [(v, F, F.representative_point()) for v, F in a.closed_faces()] H.<x,y> = HyperplaneArrangements(QQ) a = H(x, y+1) a.hyperplanes() [(v, F, F.representative_point()) for v, F in a.closed_faces()] # needs sage.graphs a = hyperplane_arrangements.braid(3) a.hyperplanes() [(v, F, F.representative_point()) for v, F in a.closed_faces()]
Let us check that the number of closed faces with a given dimension computed using
self.closed_faces()
equals the one computed usingface_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) # needs sage.combinat True sage: a = hyperplane_arrangements.Shi(3) sage: test_number(a) # long time # needs sage.combinat True
>>> from sage.all import * >>> 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[Integer(1)].dim() for F in a.closed_faces()) ... return LHS == RHS >>> a = hyperplane_arrangements.Catalan(Integer(2)) >>> test_number(a) # needs sage.combinat True >>> a = hyperplane_arrangements.Shi(Integer(3)) >>> test_number(a) # long time # needs sage.combinat True
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 a = hyperplane_arrangements.Catalan(2) test_number(a) # needs sage.combinat a = hyperplane_arrangements.Shi(3) test_number(a) # long time # needs sage.combinat
- cocharacteristic_polynomial()[source]¶
Return the cocharacteristic polynomial of
self
.The cocharacteristic polynomial of a hyperplane arrangement \(A\) is defined by
\[\Psi_A(z) := \sum_{X \in L} |\mu(B,X)| z^{\dim X},\]where \(L\) is the intersection poset of \(A\), \(B\) is the minimal element of \(L\) (here, the \(0\) dimensional subspace), and \(\mu\) is the Möbius function of \(L\).
OUTPUT: the cocharacteristic polynomial in \(\ZZ[z]\)
EXAMPLES:
sage: A = hyperplane_arrangements.coordinate(2) sage: A.cocharacteristic_polynomial() # needs sage.graphs z^2 + 2*z + 1 sage: B = hyperplane_arrangements.braid(3) sage: B.cocharacteristic_polynomial() # needs sage.graphs 2*z^3 + 3*z^2 + z
>>> from sage.all import * >>> A = hyperplane_arrangements.coordinate(Integer(2)) >>> A.cocharacteristic_polynomial() # needs sage.graphs z^2 + 2*z + 1 >>> B = hyperplane_arrangements.braid(Integer(3)) >>> B.cocharacteristic_polynomial() # needs sage.graphs 2*z^3 + 3*z^2 + z
A = hyperplane_arrangements.coordinate(2) A.cocharacteristic_polynomial() # needs sage.graphs B = hyperplane_arrangements.braid(3) B.cocharacteristic_polynomial() # needs sage.graphs
- cone(variable='t')[source]¶
Return the cone over the hyperplane arrangement.
INPUT:
variable
– string; the name of the additional variable
OUTPUT:
A new hyperplane arrangement \(L\). 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]\) (maybe not in this order).
Warning
While there is an almost-one-to-one correspondence between the hyperplanes of
self
and those ofself.cone()
, there is no guarantee that the order in which they appear inself.hyperplanes()
will match the order in which their counterparts inself.cone()
will appear inself.cone().hyperplanes()
! This warning does not apply to ordered hyperplane arrangements.EXAMPLES:
sage: # needs sage.combinat 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)
>>> from sage.all import * >>> # needs sage.combinat >>> a = hyperplane_arrangements.semiorder(Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = a._first_ngens(3) >>> b = a.cone() >>> a.characteristic_polynomial().factor() x * (x^2 - 6*x + 12) >>> b.characteristic_polynomial().factor() (x - 1) * x * (x^2 - 6*x + 12) >>> 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) >>> 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)
# needs sage.combinat a.<x,y,z> = hyperplane_arrangements.semiorder(3) b = a.cone() a.characteristic_polynomial().factor() b.characteristic_polynomial().factor() a.hyperplanes() b.hyperplanes()
- defining_polynomial()[source]¶
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
\[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)
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3) >>> A = H([Integer(2)*x + y - z, -x - Integer(2)*y + z]) >>> p = A.defining_polynomial(); p -2*x^2 - 5*x*y - 2*y^2 + 3*x*z + 3*y*z - z^2 >>> p.factor() (-1) * (x + 2*y - z) * (2*x + y - z)
H.<x,y,z> = HyperplaneArrangements(QQ) A = H([2*x + y - z, -x - 2*y + z]) p = A.defining_polynomial(); p p.factor()
- deletion(hyperplanes)[source]¶
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.See also
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>
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([Integer(0),Integer(1),Integer(0)], [Integer(1),Integer(0),Integer(1)], [-Integer(1),Integer(0),Integer(1)], [Integer(0),Integer(1),-Integer(1)], [Integer(0),Integer(1),Integer(1)]); A Arrangement of 5 hyperplanes of dimension 2 and rank 2 >>> A.deletion(x) Arrangement <y - 1 | y + 1 | x - y | x + y> >>> h = H([Integer(0),Integer(1),Integer(0)], [Integer(0),Integer(1),Integer(1)]) >>> A.deletion(h) Arrangement <y - 1 | y + 1 | x - y>
H.<x,y> = HyperplaneArrangements(QQ) A = H([0,1,0], [1,0,1], [-1,0,1], [0,1,-1], [0,1,1]); A A.deletion(x) h = H([0,1,0], [0,1,1]) A.deletion(h)
- derivation_module_basis(algorithm='singular')[source]¶
Return a basis for the derivation module of
self
if one exists, otherwise returnNone
.See also
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
symmetric space
) as vectors of a free module over \(S\).ALGORITHM:
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.BC
Return the product of the derivation module free chain matrices. See Section 6 of [BC2012].
EXAMPLES:
sage: # needs sage.combinat sage.groups 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)]
>>> from sage.all import * >>> # needs sage.combinat sage.groups >>> W = WeylGroup(['A', Integer(2)], prefix='s') >>> A = W.long_element().inversion_arrangement() >>> A.derivation_module_basis() [(a1, a2), (0, a1*a2 + a2^2)]
# needs sage.combinat sage.groups W = WeylGroup(['A', 2], prefix='s') A = W.long_element().inversion_arrangement() A.derivation_module_basis()
- derivation_module_free_chain()[source]¶
Return a free chain for the derivation module if one exists, otherwise return
None
.See also
EXAMPLES:
sage: # needs sage.combinat sage.groups 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] [ 1 0 0] [ 0 0 1] [ 0 a2 0] [ 1 0 0] [ 0 -1 -1] [ 0 a2 -a3] [ 0 1 0] [ 0 0 1] [a1 0 0] [ 1 0 -1] [a3 -1 0] [a1 0 a2] [ 1 0 0] [ a3 -1 -1] [ 0 a1 -a2 - a3]
>>> from sage.all import * >>> # needs sage.combinat sage.groups >>> W = WeylGroup(['A',Integer(3)], prefix='s') >>> A = W.long_element().inversion_arrangement() >>> 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>
# needs sage.combinat sage.groups W = WeylGroup(['A',3], prefix='s') A = W.long_element().inversion_arrangement() for M in A.derivation_module_free_chain(): print("%s\n"%M)
- dimension()[source]¶
Return the ambient space dimension of the arrangement.
OUTPUT: integer
EXAMPLES:
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: (x | x-1 | x+1).dimension() 2 sage: H(x).dimension() 2
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> (x | x-Integer(1) | x+Integer(1)).dimension() 2 >>> H(x).dimension() 2
H.<x,y> = HyperplaneArrangements(QQ) (x | x-1 | x+1).dimension() H(x).dimension()
- distance_between_regions(region1, region2)[source]¶
Return the number of hyperplanes separating the two regions.
INPUT:
region1
,region2
– regions of the arrangement or representative points of regions
OUTPUT: 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
>>> from sage.all import * >>> c = hyperplane_arrangements.coordinate(Integer(2)) >>> r = c.region_containing_point([-Integer(1), -Integer(1)]) >>> s = c.region_containing_point([Integer(1), Integer(1)]) >>> c.distance_between_regions(r, s) 2 >>> c.distance_between_regions(s, s) 0
c = hyperplane_arrangements.coordinate(2) r = c.region_containing_point([-1, -1]) s = c.region_containing_point([1, 1]) c.distance_between_regions(r, s) c.distance_between_regions(s, s)
- distance_enumerator(base_region)[source]¶
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 frombase_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
>>> from sage.all import * >>> c = hyperplane_arrangements.coordinate(Integer(3)) >>> c.distance_enumerator(c.region_containing_point([Integer(1),Integer(1),Integer(1)])) x^3 + 3*x^2 + 3*x + 1
c = hyperplane_arrangements.coordinate(3) c.distance_enumerator(c.region_containing_point([1,1,1]))
- doubly_indexed_whitney_number(i, j, kind=1)[source]¶
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
– integerskind
– (default: 1) 1 or 2
OUTPUT:
Integer. The \((i,j)\)-th entry of the
kind
Whitney number.See also
EXAMPLES:
sage: # needs sage.combinat 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
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.Shi(Integer(3)) >>> A.doubly_indexed_whitney_number(Integer(0), Integer(2)) 9 >>> A.whitney_number(Integer(2)) 9 >>> A.doubly_indexed_whitney_number(Integer(1), Integer(2)) -15
# needs sage.combinat A = hyperplane_arrangements.Shi(3) A.doubly_indexed_whitney_number(0, 2) A.whitney_number(2) A.doubly_indexed_whitney_number(1, 2)
REFERENCES:
- essentialization()[source]¶
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 \(\mathcal{A}'\) of \(\mathcal{A}\) as a new hyperplane arrangement.
EXAMPLES:
sage: a = hyperplane_arrangements.braid(3) # needs sage.graphs sage: a.is_essential() # needs sage.graphs False sage: a.essentialization() # needs sage.graphs 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
>>> from sage.all import * >>> a = hyperplane_arrangements.braid(Integer(3)) # needs sage.graphs >>> a.is_essential() # needs sage.graphs False >>> a.essentialization() # needs sage.graphs Arrangement <t1 - t2 | t1 + 2*t2 | 2*t1 + t2> >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> B = H([(Integer(1),Integer(0)),Integer(1)], [(Integer(1),Integer(0)),-Integer(1)]) >>> B.is_essential() False >>> B.essentialization() Arrangement <-x + 1 | x + 1> >>> B.essentialization().parent() Hyperplane arrangements in 1-dimensional linear space over Rational Field with coordinate x >>> H = HyperplaneArrangements(GF(Integer(2)), names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> C = H([(Integer(1),Integer(1)),Integer(1)], [(Integer(1),Integer(1)),Integer(0)]) >>> C.essentialization() Arrangement <y | y + 1> >>> h = hyperplane_arrangements.semiorder(Integer(4)) >>> h.essentialization() Arrangement of 12 hyperplanes of dimension 3 and rank 3
a = hyperplane_arrangements.braid(3) # needs sage.graphs a.is_essential() # needs sage.graphs a.essentialization() # needs sage.graphs H.<x,y> = HyperplaneArrangements(QQ) B = H([(1,0),1], [(1,0),-1]) B.is_essential() B.essentialization() B.essentialization().parent() H.<x,y> = HyperplaneArrangements(GF(2)) C = H([(1,1),1], [(1,1),0]) C.essentialization() h = hyperplane_arrangements.semiorder(4) h.essentialization()
- face_product(F, G, normalize=True)[source]¶
Return the product \(FG\) in the face semigroup of
self
, where \(F\) and \(G\) are two closed faces ofself
.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
(seeclosed_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 ofself
(as polyhedra)normalize
– boolean (default:True
); ifTrue
, then this method returns the precise instance of \(FG\) in the list returned byself.closed_faces()
, rather than creating a new instance
EXAMPLES:
sage: # needs sage.graphs 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
>>> from sage.all import * >>> # needs sage.graphs >>> a = hyperplane_arrangements.braid(Integer(3)) >>> a.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) >>> faces = {F0: F1 for F0, F1 in a.closed_faces()} >>> xGyEz = faces[(Integer(0), Integer(1), Integer(1))] # closed face x >= y = z >>> xGyEz.representative_point() (0, -1, -1) >>> xGyEz = faces[(Integer(0), Integer(1), Integer(1))] # closed face x >= y = z >>> xGyEz.representative_point() (0, -1, -1) >>> yGxGz = faces[(Integer(1), -Integer(1), Integer(1))] # closed face y >= x >= z >>> xGyGz = faces[(Integer(1), Integer(1), Integer(1))] # closed face x >= y >= z >>> a.face_product(xGyEz, yGxGz) == xGyGz True >>> a.face_product(yGxGz, xGyEz) == yGxGz True >>> xEzGy = faces[(-Integer(1), Integer(1), Integer(0))] # closed face x = z >= y >>> xGzGy = faces[(-Integer(1), Integer(1), Integer(1))] # closed face x >= z >= y >>> a.face_product(xEzGy, yGxGz) == xGzGy True
# needs sage.graphs a = hyperplane_arrangements.braid(3) a.hyperplanes() faces = {F0: F1 for F0, F1 in a.closed_faces()} xGyEz = faces[(0, 1, 1)] # closed face x >= y = z xGyEz.representative_point() xGyEz = faces[(0, 1, 1)] # closed face x >= y = z xGyEz.representative_point() yGxGz = faces[(1, -1, 1)] # closed face y >= x >= z xGyGz = faces[(1, 1, 1)] # closed face x >= y >= z a.face_product(xGyEz, yGxGz) == xGyGz a.face_product(yGxGz, xGyEz) == yGxGz xEzGy = faces[(-1, 1, 0)] # closed face x = z >= y xGzGy = faces[(-1, 1, 1)] # closed face x >= z >= y a.face_product(xEzGy, yGxGz) == xGzGy
- face_semigroup_algebra(field=None, names='e')[source]¶
Return the face semigroup algebra of
self
.This is the semigroup algebra of the face semigroup of
self
(seeface_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
FiniteDimensionalAlgebra
class), this is implemented not as a semigroup algebra, but as aFiniteDimensionalAlgebra
. The closed faces ofself
(in the order in which theclosed_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: \(\QQ\)), 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: # needs sage.graphs 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 # needs sage.graphs sage.rings.finite_rings Finite-dimensional algebra of degree 13 over Finite Field of size 3
>>> from sage.all import * >>> # needs sage.graphs >>> a = hyperplane_arrangements.braid(Integer(3)) >>> [(i, F[Integer(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))] >>> U = a.face_semigroup_algebra(); U Finite-dimensional algebra of degree 13 over Rational Field >>> e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() >>> e0 * e1 e1 >>> e0 * e5 e5 >>> e5 * e0 e5 >>> e3 * e2 e6 >>> e7 * e12 e7 >>> e3 * e12 e6 >>> e4 * e8 e4 >>> e8 * e4 e11 >>> e8 * e1 e11 >>> e5 * e12 e7 >>> (e3 + Integer(2)*e4) * (e1 - e7) e4 - e6 >>> U3 = a.face_semigroup_algebra(field=GF(Integer(3))); U3 # needs sage.graphs sage.rings.finite_rings Finite-dimensional algebra of degree 13 over Finite Field of size 3
# needs sage.graphs a = hyperplane_arrangements.braid(3) [(i, F[0]) for i, F in enumerate(a.closed_faces())] U = a.face_semigroup_algebra(); U e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12 = U.basis() e0 * e1 e0 * e5 e5 * e0 e3 * e2 e7 * e12 e3 * e12 e4 * e8 e8 * e4 e8 * e1 e5 * e12 (e3 + 2*e4) * (e1 - e7) U3 = a.face_semigroup_algebra(field=GF(3)); U3 # needs sage.graphs sage.rings.finite_rings
- face_vector()[source]¶
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() # needs sage.combinat (0, 6, 21, 16)
>>> from sage.all import * >>> A = hyperplane_arrangements.Shi(Integer(3)) >>> A.face_vector() # needs sage.combinat (0, 6, 21, 16)
A = hyperplane_arrangements.Shi(3) A.face_vector() # needs sage.combinat
- has_good_reduction(p)[source]¶
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: boolean
EXAMPLES:
sage: # needs sage.combinat 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
>>> from sage.all import * >>> # needs sage.combinat >>> a = hyperplane_arrangements.semiorder(Integer(3)) >>> a.has_good_reduction(Integer(5)) True >>> a.has_good_reduction(Integer(3)) False >>> b = a.change_ring(GF(Integer(3))) >>> a.characteristic_polynomial() x^3 - 6*x^2 + 12*x >>> b.characteristic_polynomial() # not equal to that for a x^3 - 6*x^2 + 10*x
# needs sage.combinat a = hyperplane_arrangements.semiorder(3) a.has_good_reduction(5) a.has_good_reduction(3) b = a.change_ring(GF(3)) a.characteristic_polynomial() b.characteristic_polynomial() # not equal to that for a
- hyperplanes()[source]¶
Return the hyperplanes in the arrangement as a tuple.
OUTPUT: a tuple
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)
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([Integer(1),Integer(1),Integer(0)], [Integer(2),Integer(3),-Integer(1)], [Integer(4),Integer(5),Integer(3)]) >>> A.hyperplanes() (Hyperplane x + 0*y + 1, Hyperplane 3*x - y + 2, Hyperplane 5*x + 3*y + 4)
H.<x,y> = HyperplaneArrangements(QQ) A = H([1,1,0], [2,3,-1], [4,5,3]) A.hyperplanes()
Note that the hyperplanes can be indexed as if they were a list:
sage: A[0] Hyperplane x + 0*y + 1
>>> from sage.all import * >>> A[Integer(0)] Hyperplane x + 0*y + 1
A[0]
- intersection_poset(element_label='int')[source]¶
Return the intersection poset of the hyperplane arrangement.
INPUT:
element_label
– (default:'int'
) specify how an intersection should be represented; must be one of the following:'subspace'
– as a subspace'subset'
– as a subset of the defining hyperplanes'int'
– as an integer
OUTPUT:
The poset of non-empty intersections of hyperplanes, with intersections represented by integers, subsets of integers or subspaces (see the examples for more details).
EXAMPLES:
By default, the elements of the poset are the integers from \(0\) through the cardinality of the poset minus one. The element labelled \(0\) always corresponds to the ambient vector space, and the hyperplanes themselves are labelled \(1, 2, \ldots, n\), where \(n\) is the number of hyperplanes of the arrangement.
sage: A = hyperplane_arrangements.coordinate(2) sage: L = A.intersection_poset(); L # needs sage.combinat Finite poset containing 4 elements sage: sorted(L) # needs sage.combinat [0, 1, 2, 3] sage: L.level_sets() # needs sage.combinat [[0], [1, 2], [3]]
>>> from sage.all import * >>> A = hyperplane_arrangements.coordinate(Integer(2)) >>> L = A.intersection_poset(); L # needs sage.combinat Finite poset containing 4 elements >>> sorted(L) # needs sage.combinat [0, 1, 2, 3] >>> L.level_sets() # needs sage.combinat [[0], [1, 2], [3]]
A = hyperplane_arrangements.coordinate(2) L = A.intersection_poset(); L # needs sage.combinat sorted(L) # needs sage.combinat L.level_sets() # needs sage.combinat
sage: # needs sage.combinat sage: A = hyperplane_arrangements.semiorder(3) sage: L = A.intersection_poset(); L Finite poset containing 19 elements sage: sorted(L) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] sage: [sorted(level_set) for level_set in L.level_sets()] [[0], [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]]
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.semiorder(Integer(3)) >>> L = A.intersection_poset(); L Finite poset containing 19 elements >>> sorted(L) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] >>> [sorted(level_set) for level_set in L.level_sets()] [[0], [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]]
# needs sage.combinat A = hyperplane_arrangements.semiorder(3) L = A.intersection_poset(); L sorted(L) [sorted(level_set) for level_set in L.level_sets()]
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.semiorder(Integer(3)) >>> L = A.intersection_poset(); L Finite poset containing 19 elements >>> sorted(L) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] >>> [sorted(level_set) for level_set in L.level_sets()] [[0], [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]]
# needs sage.combinat A = hyperplane_arrangements.semiorder(3) L = A.intersection_poset(); L sorted(L) [sorted(level_set) for level_set in L.level_sets()]
By passing the argument
element_label="subset"
, each element of the intersection poset is labelled by the set of indices of the hyperplanes whose intersection is said element. The index of a hyperplane is its index inself.hyperplanes()
.sage: A = hyperplane_arrangements.semiorder(3) sage: L = A.intersection_poset(element_label='subset') # needs sage.combinat sage: [sorted(level, key=sorted) for level in L.level_sets()] # needs sage.combinat [[{}], [{0}, {1}, {2}, {3}, {4}, {5}], [{0, 2}, {0, 3}, {0, 4}, {0, 5}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 4}, {2, 5}, {3, 4}, {3, 5}]]
>>> from sage.all import * >>> A = hyperplane_arrangements.semiorder(Integer(3)) >>> L = A.intersection_poset(element_label='subset') # needs sage.combinat >>> [sorted(level, key=sorted) for level in L.level_sets()] # needs sage.combinat [[{}], [{0}, {1}, {2}, {3}, {4}, {5}], [{0, 2}, {0, 3}, {0, 4}, {0, 5}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 4}, {2, 5}, {3, 4}, {3, 5}]]
A = hyperplane_arrangements.semiorder(3) L = A.intersection_poset(element_label='subset') # needs sage.combinat [sorted(level, key=sorted) for level in L.level_sets()] # needs sage.combinat
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: A = H((y, y-1, y+1, x-y, x+y)) sage: L = A.intersection_poset(element_label='subset') # needs sage.combinat sage: sorted(L, key=sorted) # needs sage.combinat [{}, {0}, {0, 3}, {0, 4}, {1}, {1, 3, 4}, {2}, {2, 3}, {2, 4}, {3}, {4}]
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H((y, y-Integer(1), y+Integer(1), x-y, x+y)) >>> L = A.intersection_poset(element_label='subset') # needs sage.combinat >>> sorted(L, key=sorted) # needs sage.combinat [{}, {0}, {0, 3}, {0, 4}, {1}, {1, 3, 4}, {2}, {2, 3}, {2, 4}, {3}, {4}]
H.<x,y> = HyperplaneArrangements(QQ) A = H((y, y-1, y+1, x-y, x+y)) L = A.intersection_poset(element_label='subset') # needs sage.combinat sorted(L, key=sorted) # needs sage.combinat
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H((y, y-Integer(1), y+Integer(1), x-y, x+y)) >>> L = A.intersection_poset(element_label='subset') # needs sage.combinat >>> sorted(L, key=sorted) # needs sage.combinat [{}, {0}, {0, 3}, {0, 4}, {1}, {1, 3, 4}, {2}, {2, 3}, {2, 4}, {3}, {4}]
H.<x,y> = HyperplaneArrangements(QQ) A = H((y, y-1, y+1, x-y, x+y)) L = A.intersection_poset(element_label='subset') # needs sage.combinat sorted(L, key=sorted) # needs sage.combinat
One can instead use affine subspaces as elements, which is what is used to compute the poset in the first place:
sage: A = hyperplane_arrangements.coordinate(2) sage: L = A.intersection_poset(element_label='subspace'); L # needs sage.combinat Finite poset containing 4 elements sage: sorted(L, key=lambda S: (S.dimension(), # needs sage.combinat ....: S.linear_part().basis_matrix())) [Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 0 over Rational Field Basis matrix: [], Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [0 1], Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [1 0], Affine space p + W where: p = (0, 0) W = Vector space of dimension 2 over Rational Field]
>>> from sage.all import * >>> A = hyperplane_arrangements.coordinate(Integer(2)) >>> L = A.intersection_poset(element_label='subspace'); L # needs sage.combinat Finite poset containing 4 elements >>> sorted(L, key=lambda S: (S.dimension(), # needs sage.combinat ... S.linear_part().basis_matrix())) [Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 0 over Rational Field Basis matrix: [], Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [0 1], Affine space p + W where: p = (0, 0) W = Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [1 0], Affine space p + W where: p = (0, 0) W = Vector space of dimension 2 over Rational Field]
A = hyperplane_arrangements.coordinate(2) L = A.intersection_poset(element_label='subspace'); L # needs sage.combinat sorted(L, key=lambda S: (S.dimension(), # needs sage.combinat S.linear_part().basis_matrix()))
- is_central(certificate=False)[source]¶
Test whether the intersection of all the hyperplanes is nonempty.
A hyperplane arrangement is central if the intersection of all the hyperplanes in the arrangement is nonempty.
INPUT:
certificate
– boolean (default:False
); specifies whether to return the center as a polyhedron (possibly empty) as part of the output
OUTPUT: if
certificate
isTrue
, returns a tuple containing:A boolean
The polyhedron defined to be the intersection of all the hyperplanes
If
certificate
isFalse
, returns a boolean.EXAMPLES:
sage: a = hyperplane_arrangements.braid(2) # needs sage.graphs sage: a.is_central() # needs sage.graphs True
>>> from sage.all import * >>> a = hyperplane_arrangements.braid(Integer(2)) # needs sage.graphs >>> a.is_central() # needs sage.graphs True
a = hyperplane_arrangements.braid(2) # needs sage.graphs a.is_central() # needs sage.graphs
The Catalan arrangement in dimension 3 is not central:
sage: b = hyperplane_arrangements.Catalan(3) sage: b.is_central(certificate=True) (False, The empty polyhedron in QQ^3)
>>> from sage.all import * >>> b = hyperplane_arrangements.Catalan(Integer(3)) >>> b.is_central(certificate=True) (False, The empty polyhedron in QQ^3)
b = hyperplane_arrangements.Catalan(3) b.is_central(certificate=True)
The empty arrangement in dimension 5 is central:
sage: H = HyperplaneArrangements(QQ, names=tuple(['x'+str(i) for i in range(7)])) sage: c = H() sage: c.is_central(certificate=True) (True, A 7-dimensional polyhedron in QQ^7 defined as the convex hull of 1 vertex and 7 lines)
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=tuple(['x'+str(i) for i in range(Integer(7))])) >>> c = H() >>> c.is_central(certificate=True) (True, A 7-dimensional polyhedron in QQ^7 defined as the convex hull of 1 vertex and 7 lines)
H = HyperplaneArrangements(QQ, names=tuple(['x'+str(i) for i in range(7)])) c = H() c.is_central(certificate=True)
- is_essential()[source]¶
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.
See also
OUTPUT: boolean
EXAMPLES:
sage: H.<x,y> = HyperplaneArrangements(QQ) sage: H(x, x+1).is_essential() False sage: H(x, y).is_essential() True
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> H(x, x+Integer(1)).is_essential() False >>> H(x, y).is_essential() True
H.<x,y> = HyperplaneArrangements(QQ) H(x, x+1).is_essential() H(x, y).is_essential()
- is_formal()[source]¶
Return if
self
is formal.A hyperplane arrangement is formal if it is 3-generated [Yuz1993], where \(k\)-generated is defined in
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
>>> from sage.all import * >>> P = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = P._first_ngens(3) >>> A = P(x, y, z, x+y+z, Integer(2)*x+y+z, Integer(2)*x+Integer(3)*y+z, Integer(2)*x+Integer(3)*y+Integer(4)*z, Integer(3)*x+Integer(5)*z, Integer(3)*x+Integer(4)*y+Integer(5)*z) >>> B = P(x, y, z, x+y+z, Integer(2)*x+y+z, Integer(2)*x+Integer(3)*y+z, Integer(2)*x+Integer(3)*y+Integer(4)*z, x+Integer(3)*z, x+Integer(2)*y+Integer(3)*z) >>> A.is_formal() True >>> B.is_formal() False
P.<x,y,z> = HyperplaneArrangements(QQ) 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) 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) A.is_formal() B.is_formal()
- is_free(algorithm='singular')[source]¶
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:
singular
Check that the minimal free resolution has length at most 2 by using Singular.
BC
This implementation follows [BC2012] by constructing a chain of free modules
\[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') # needs sage.combinat sage.groups sage: for x in W: # needs sage.combinat sage.groups ....: A = x.inversion_arrangement() ....: assert A.matroid().is_chordal() == A.is_free()
>>> from sage.all import * >>> W = WeylGroup(['A', Integer(3)], prefix='s') # needs sage.combinat sage.groups >>> for x in W: # needs sage.combinat sage.groups ... A = x.inversion_arrangement() ... assert A.matroid().is_chordal() == A.is_free()
W = WeylGroup(['A', 3], prefix='s') # needs sage.combinat sage.groups for x in W: # needs sage.combinat sage.groups A = x.inversion_arrangement() assert A.matroid().is_chordal() == A.is_free()
- is_linear()[source]¶
Test whether all hyperplanes pass through the origin.
OUTPUT: boolean
EXAMPLES:
sage: a = hyperplane_arrangements.semiorder(3) sage: a.is_linear() False sage: b = hyperplane_arrangements.braid(3) # needs sage.graphs sage: b.is_linear() # needs sage.graphs True sage: H.<x,y> = HyperplaneArrangements(QQ) sage: c = H(x+1, y+1) sage: c.is_linear() False sage: c.is_central() True
>>> from sage.all import * >>> a = hyperplane_arrangements.semiorder(Integer(3)) >>> a.is_linear() False >>> b = hyperplane_arrangements.braid(Integer(3)) # needs sage.graphs >>> b.is_linear() # needs sage.graphs True >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> c = H(x+Integer(1), y+Integer(1)) >>> c.is_linear() False >>> c.is_central() True
a = hyperplane_arrangements.semiorder(3) a.is_linear() b = hyperplane_arrangements.braid(3) # needs sage.graphs b.is_linear() # needs sage.graphs H.<x,y> = HyperplaneArrangements(QQ) c = H(x+1, y+1) c.is_linear() c.is_central()
- is_separating_hyperplane(region1, region2, hyperplane)[source]¶
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 regionhyperplane
– a hyperplane
OUTPUT: boolean; whether the hyperplane
hyperplane
separate the given regionsEXAMPLES:
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
>>> from sage.all import * >>> A = hyperplane_arrangements.coordinate(Integer(2), names=('x', 'y',)); (x, y,) = A._first_ngens(2) >>> A.is_separating_hyperplane([Integer(1),Integer(1)], [Integer(2),Integer(1)], y) False >>> A.is_separating_hyperplane([Integer(1),Integer(1)], [-Integer(1),Integer(1)], x) True >>> r = A.region_containing_point([Integer(1),Integer(1)]) >>> s = A.region_containing_point([-Integer(1),Integer(1)]) >>> A.is_separating_hyperplane(r, s, x) True
A.<x,y> = hyperplane_arrangements.coordinate(2) A.is_separating_hyperplane([1,1], [2,1], y) A.is_separating_hyperplane([1,1], [-1,1], x) r = A.region_containing_point([1,1]) s = A.region_containing_point([-1,1]) A.is_separating_hyperplane(r, s, x)
- is_simplicial()[source]¶
Test whether the arrangement is simplicial.
A region is simplicial if the normal vectors of its bounding hyperplanes are linearly independent. A hyperplane arrangement is said to be simplicial if every region is simplicial.
OUTPUT: boolean; whether the hyperplane arrangement is simplicial
EXAMPLES:
sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: A = H([[0,1,1,1], [0,1,2,3]]) sage: A.is_simplicial() True sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2]]) sage: A.is_simplicial() True sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) sage: A.is_simplicial() False sage: hyperplane_arrangements.braid(3).is_simplicial() # needs sage.graphs True
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3) >>> A = H([[Integer(0),Integer(1),Integer(1),Integer(1)], [Integer(0),Integer(1),Integer(2),Integer(3)]]) >>> A.is_simplicial() True >>> A = H([[Integer(0),Integer(1),Integer(1),Integer(1)], [Integer(0),Integer(1),Integer(2),Integer(3)], [Integer(0),Integer(1),Integer(3),Integer(2)]]) >>> A.is_simplicial() True >>> A = H([[Integer(0),Integer(1),Integer(1),Integer(1)], [Integer(0),Integer(1),Integer(2),Integer(3)], [Integer(0),Integer(1),Integer(3),Integer(2)], [Integer(0),Integer(2),Integer(1),Integer(3)]]) >>> A.is_simplicial() False >>> hyperplane_arrangements.braid(Integer(3)).is_simplicial() # needs sage.graphs True
H.<x,y,z> = HyperplaneArrangements(QQ) A = H([[0,1,1,1], [0,1,2,3]]) A.is_simplicial() A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2]]) A.is_simplicial() A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) A.is_simplicial() hyperplane_arrangements.braid(3).is_simplicial() # needs sage.graphs
- matroid()[source]¶
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
>>> from sage.all import * >>> P = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = P._first_ngens(3) >>> A = P(x, y, z, x+y+z, Integer(2)*x+y+z, Integer(2)*x+Integer(3)*y+z, Integer(2)*x+Integer(3)*y+Integer(4)*z) >>> M = A.matroid(); M Linear matroid of rank 3 on 7 elements represented over the Rational Field
P.<x,y,z> = HyperplaneArrangements(QQ) A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z) M = A.matroid(); M
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]) # needs sage.combinat sage: PF.is_isomorphic(A.intersection_poset()) # needs sage.combinat True
>>> from sage.all import * >>> f = sum([list(M.flats(i)) for i in range(M.rank() + Integer(1))], []) >>> PF = Poset([f, lambda x, y: x < y]) # needs sage.combinat >>> PF.is_isomorphic(A.intersection_poset()) # needs sage.combinat True
f = sum([list(M.flats(i)) for i in range(M.rank() + 1)], []) PF = Poset([f, lambda x, y: x < y]) # needs sage.combinat PF.is_isomorphic(A.intersection_poset()) # needs sage.combinat
- minimal_generated_number()[source]¶
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
>>> from sage.all import * >>> P = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = P._first_ngens(3) >>> A = P(x, y, z, x+y+z, Integer(2)*x+y+z, Integer(2)*x+Integer(3)*y+z, Integer(2)*x+Integer(3)*y+Integer(4)*z, Integer(3)*x+Integer(5)*z, Integer(3)*x+Integer(4)*y+Integer(5)*z) >>> B = P(x, y, z, x+y+z, Integer(2)*x+y+z, Integer(2)*x+Integer(3)*y+z, Integer(2)*x+Integer(3)*y+Integer(4)*z, x+Integer(3)*z, x+Integer(2)*y+Integer(3)*z) >>> A.minimal_generated_number() 3 >>> B.minimal_generated_number() 4
P.<x,y,z> = HyperplaneArrangements(QQ) 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) 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) A.minimal_generated_number() B.minimal_generated_number()
- n_bounded_regions()[source]¶
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
>>> from sage.all import * >>> A = hyperplane_arrangements.semiorder(Integer(3)) >>> A.n_bounded_regions() 7
A = hyperplane_arrangements.semiorder(3) A.n_bounded_regions()
- n_hyperplanes()[source]¶
Return the number of hyperplanes in the arrangement.
OUTPUT: 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
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([Integer(1),Integer(1),Integer(0)], [Integer(2),Integer(3),-Integer(1)], [Integer(4),Integer(5),Integer(3)]) >>> A.n_hyperplanes() 3 >>> len(A) # equivalent 3
H.<x,y> = HyperplaneArrangements(QQ) A = H([1,1,0], [2,3,-1], [4,5,3]) A.n_hyperplanes() len(A) # equivalent
- n_regions()[source]¶
The number of regions of the hyperplane arrangement.
OUTPUT: integer
EXAMPLES:
sage: A = hyperplane_arrangements.semiorder(3) sage: A.n_regions() 19
>>> from sage.all import * >>> A = hyperplane_arrangements.semiorder(Integer(3)) >>> A.n_regions() 19
A = hyperplane_arrangements.semiorder(3) A.n_regions()
- orlik_solomon_algebra(base_ring=None, ordering=None, **kwds)[source]¶
Return the Orlik-Solomon algebra of
self
.INPUT:
base_ring
– (default: the base field ofself
) the ring over which the Orlik-Solomon algebra will be definedordering
– (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
>>> from sage.all import * >>> P = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = P._first_ngens(3) >>> A = P(x, y, z, x+y+z, Integer(2)*x+y+z, Integer(2)*x+Integer(3)*y+z, Integer(2)*x+Integer(3)*y+Integer(4)*z) >>> A.orlik_solomon_algebra() Orlik-Solomon algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field >>> A.orlik_solomon_algebra(base_ring=ZZ) Orlik-Solomon algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field
P.<x,y,z> = HyperplaneArrangements(QQ) A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z) A.orlik_solomon_algebra() A.orlik_solomon_algebra(base_ring=ZZ)
- orlik_terao_algebra(base_ring=None, ordering=None, **kwds)[source]¶
Return the Orlik-Terao algebra of
self
.INPUT:
base_ring
– (default: the base field ofself
) the ring over which the Orlik-Terao algebra will be definedordering
– (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_terao_algebra() Orlik-Terao algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field over Rational Field sage: A.orlik_terao_algebra(base_ring=QQ['t']) Orlik-Terao algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field over Univariate Polynomial Ring in t over Rational Field
>>> from sage.all import * >>> P = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = P._first_ngens(3) >>> A = P(x, y, z, x+y+z, Integer(2)*x+y+z, Integer(2)*x+Integer(3)*y+z, Integer(2)*x+Integer(3)*y+Integer(4)*z) >>> A.orlik_terao_algebra() Orlik-Terao algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field over Rational Field >>> A.orlik_terao_algebra(base_ring=QQ['t']) Orlik-Terao algebra of Linear matroid of rank 3 on 7 elements represented over the Rational Field over Univariate Polynomial Ring in t over Rational Field
P.<x,y,z> = HyperplaneArrangements(QQ) A = P(x, y, z, x+y+z, 2*x+y+z, 2*x+3*y+z, 2*x+3*y+4*z) A.orlik_terao_algebra() A.orlik_terao_algebra(base_ring=QQ['t'])
- plot(**kwds)[source]¶
Plot the hyperplane arrangement.
OUTPUT: a graphics object
EXAMPLES:
sage: L.<x, y> = HyperplaneArrangements(QQ) sage: L(x, y, x+y-2).plot() # needs sage.plot Graphics object consisting of 3 graphics primitives
>>> from sage.all import * >>> L = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = L._first_ngens(2) >>> L(x, y, x+y-Integer(2)).plot() # needs sage.plot Graphics object consisting of 3 graphics primitives
L.<x, y> = HyperplaneArrangements(QQ) L(x, y, x+y-2).plot() # needs sage.plot
- poincare_polynomial()[source]¶
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
>>> from sage.all import * >>> a = hyperplane_arrangements.coordinate(Integer(2)) >>> a.poincare_polynomial() x^2 + 2*x + 1
a = hyperplane_arrangements.coordinate(2) a.poincare_polynomial()
- poset_of_regions(B=None, numbered_labels=True)[source]¶
Return the poset of regions for a central hyperplane arrangement.
The poset of regions is a partial order on the set of regions where the regions are ordered by \(R\leq R'\) if and only if \(S(R) \subseteq S(R')\) where \(S(R)\) is the set of hyperplanes which separate the region \(R\) from the base region \(B\).
INPUT:
B
– a region (optional); ifNone
, then an arbitrary region is chosen as the base regionnumbered_labels
– boolean (default:True
); ifTrue
, then the elements of the poset are numbered. Else they are labelled with the regions themselves.
OUTPUT: a Poset object containing the poset of regions
EXAMPLES:
sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: A = H([[0,1,1,1], [0,1,2,3]]) sage: A.poset_of_regions() # needs sage.combinat Finite poset containing 4 elements sage: # needs sage.combinat sage.graphs sage: A = hyperplane_arrangements.braid(3) sage: A.poset_of_regions() Finite poset containing 6 elements sage: A.poset_of_regions(numbered_labels=False) Finite poset containing 6 elements sage: A = hyperplane_arrangements.braid(4) sage: A.poset_of_regions() Finite poset containing 24 elements sage: H.<x,y,z> = HyperplaneArrangements(QQ) sage: A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) sage: R = A.regions() sage: base_region = R[3] sage: A.poset_of_regions(B=base_region) # needs sage.combinat Finite poset containing 14 elements
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3) >>> A = H([[Integer(0),Integer(1),Integer(1),Integer(1)], [Integer(0),Integer(1),Integer(2),Integer(3)]]) >>> A.poset_of_regions() # needs sage.combinat Finite poset containing 4 elements >>> # needs sage.combinat sage.graphs >>> A = hyperplane_arrangements.braid(Integer(3)) >>> A.poset_of_regions() Finite poset containing 6 elements >>> A.poset_of_regions(numbered_labels=False) Finite poset containing 6 elements >>> A = hyperplane_arrangements.braid(Integer(4)) >>> A.poset_of_regions() Finite poset containing 24 elements >>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3) >>> A = H([[Integer(0),Integer(1),Integer(1),Integer(1)], [Integer(0),Integer(1),Integer(2),Integer(3)], [Integer(0),Integer(1),Integer(3),Integer(2)], [Integer(0),Integer(2),Integer(1),Integer(3)]]) >>> R = A.regions() >>> base_region = R[Integer(3)] >>> A.poset_of_regions(B=base_region) # needs sage.combinat Finite poset containing 14 elements
H.<x,y,z> = HyperplaneArrangements(QQ) A = H([[0,1,1,1], [0,1,2,3]]) A.poset_of_regions() # needs sage.combinat # needs sage.combinat sage.graphs A = hyperplane_arrangements.braid(3) A.poset_of_regions() A.poset_of_regions(numbered_labels=False) A = hyperplane_arrangements.braid(4) A.poset_of_regions() H.<x,y,z> = HyperplaneArrangements(QQ) A = H([[0,1,1,1], [0,1,2,3], [0,1,3,2], [0,2,1,3]]) R = A.regions() base_region = R[3] A.poset_of_regions(B=base_region) # needs sage.combinat
- primitive_eulerian_polynomial()[source]¶
Return the primitive Eulerian polynomial of
self
.The primitive Eulerian polynomial of a hyperplane arrangement \(A\) is defined [BHS2023] by
\[P_A(z) := \sum_{X \in L} |\mu(B,X)| (z - 1)^{\mathrm{codim} X},\]where \(L\) is the intersection poset of \(A\), \(B\) is the minimal element of \(L\) (here, the \(0\) dimensional subspace), and \(\mu\) is the Möbius function of \(L\).
OUTPUT: the primitive Eulerian polynomial in \(\ZZ[z]\)
EXAMPLES:
sage: A = hyperplane_arrangements.coordinate(2) sage: A.primitive_eulerian_polynomial() # needs sage.graphs z^2 sage: B = hyperplane_arrangements.braid(3) sage: B.primitive_eulerian_polynomial() # needs sage.graphs z^2 + z sage: H = hyperplane_arrangements.Shi(['B',2]).cone() sage: H.is_simplicial() False sage: H.primitive_eulerian_polynomial() # needs sage.graphs z^3 + 11*z^2 + 4*z sage: H = hyperplane_arrangements.graphical(graphs.CycleGraph(4)) sage: H.primitive_eulerian_polynomial() # needs sage.graphs z^3 + 3*z^2 - z
>>> from sage.all import * >>> A = hyperplane_arrangements.coordinate(Integer(2)) >>> A.primitive_eulerian_polynomial() # needs sage.graphs z^2 >>> B = hyperplane_arrangements.braid(Integer(3)) >>> B.primitive_eulerian_polynomial() # needs sage.graphs z^2 + z >>> H = hyperplane_arrangements.Shi(['B',Integer(2)]).cone() >>> H.is_simplicial() False >>> H.primitive_eulerian_polynomial() # needs sage.graphs z^3 + 11*z^2 + 4*z >>> H = hyperplane_arrangements.graphical(graphs.CycleGraph(Integer(4))) >>> H.primitive_eulerian_polynomial() # needs sage.graphs z^3 + 3*z^2 - z
A = hyperplane_arrangements.coordinate(2) A.primitive_eulerian_polynomial() # needs sage.graphs B = hyperplane_arrangements.braid(3) B.primitive_eulerian_polynomial() # needs sage.graphs H = hyperplane_arrangements.Shi(['B',2]).cone() H.is_simplicial() H.primitive_eulerian_polynomial() # needs sage.graphs H = hyperplane_arrangements.graphical(graphs.CycleGraph(4)) H.primitive_eulerian_polynomial() # needs sage.graphs
We verify Example 2.4 in [BHS2023] for \(k = 2,3,4,5\):
sage: R.<x,y> = HyperplaneArrangements(QQ) sage: for k in range(2,6): # needs sage.graphs ....: H = R([x+j*y for j in range(k)]) ....: H.primitive_eulerian_polynomial() z^2 z^2 + z z^2 + 2*z z^2 + 3*z
>>> from sage.all import * >>> R = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = R._first_ngens(2) >>> for k in range(Integer(2),Integer(6)): # needs sage.graphs ... H = R([x+j*y for j in range(k)]) ... H.primitive_eulerian_polynomial() z^2 z^2 + z z^2 + 2*z z^2 + 3*z
R.<x,y> = HyperplaneArrangements(QQ) for k in range(2,6): # needs sage.graphs H = R([x+j*y for j in range(k)]) H.primitive_eulerian_polynomial()
We verify Equation (4) in [BHS2023] on some examples:
sage: # needs sage.graphs sage: R.<x> = ZZ[] sage: Arr = [hyperplane_arrangements.braid(n) for n in range(2,6)] sage: all(R(A.cocharacteristic_polynomial()(1/(x-1)) * (x-1)^A.dimension()) ....: == R(A.primitive_eulerian_polynomial()) for A in Arr) True
>>> from sage.all import * >>> # needs sage.graphs >>> R = ZZ['x']; (x,) = R._first_ngens(1) >>> Arr = [hyperplane_arrangements.braid(n) for n in range(Integer(2),Integer(6))] >>> all(R(A.cocharacteristic_polynomial()(Integer(1)/(x-Integer(1))) * (x-Integer(1))**A.dimension()) ... == R(A.primitive_eulerian_polynomial()) for A in Arr) True
# needs sage.graphs R.<x> = ZZ[] Arr = [hyperplane_arrangements.braid(n) for n in range(2,6)] all(R(A.cocharacteristic_polynomial()(1/(x-1)) * (x-1)^A.dimension()) == R(A.primitive_eulerian_polynomial()) for A in Arr)
We compute types \(H_3\) and \(F_4\) in Table 1 of [BHS2023]:
sage: # needs sage.libs.gap sage: W = CoxeterGroup(['H',3], implementation='matrix') sage: A = HyperplaneArrangements(W.base_ring(), tuple(f'x{s}' for s in range(W.rank()))) sage: H = A([[0] + list(r) for r in W.positive_roots()]) sage: H.is_simplicial() # needs sage.graphs True sage: H.primitive_eulerian_polynomial() z^3 + 28*z^2 + 16*z sage: W = CoxeterGroup(['F',4], implementation='permutation') sage: A = HyperplaneArrangements(QQ, tuple(f'x{s}' for s in range(W.rank()))) sage: H = A([[0] + list(r) for r in W.positive_roots()]) sage: H.primitive_eulerian_polynomial() # long time # needs sage.graphs z^4 + 116*z^3 + 220*z^2 + 48*z
>>> from sage.all import * >>> # needs sage.libs.gap >>> W = CoxeterGroup(['H',Integer(3)], implementation='matrix') >>> A = HyperplaneArrangements(W.base_ring(), tuple(f'x{s}' for s in range(W.rank()))) >>> H = A([[Integer(0)] + list(r) for r in W.positive_roots()]) >>> H.is_simplicial() # needs sage.graphs True >>> H.primitive_eulerian_polynomial() z^3 + 28*z^2 + 16*z >>> W = CoxeterGroup(['F',Integer(4)], implementation='permutation') >>> A = HyperplaneArrangements(QQ, tuple(f'x{s}' for s in range(W.rank()))) >>> H = A([[Integer(0)] + list(r) for r in W.positive_roots()]) >>> H.primitive_eulerian_polynomial() # long time # needs sage.graphs z^4 + 116*z^3 + 220*z^2 + 48*z
# needs sage.libs.gap W = CoxeterGroup(['H',3], implementation='matrix') A = HyperplaneArrangements(W.base_ring(), tuple(f'x{s}' for s in range(W.rank()))) H = A([[0] + list(r) for r in W.positive_roots()]) H.is_simplicial() # needs sage.graphs H.primitive_eulerian_polynomial() W = CoxeterGroup(['F',4], implementation='permutation') A = HyperplaneArrangements(QQ, tuple(f'x{s}' for s in range(W.rank()))) H = A([[0] + list(r) for r in W.positive_roots()]) H.primitive_eulerian_polynomial() # long time # needs sage.graphs
We verify Proposition 2.5 in [BHS2023] on the braid arrangement \(B_k\) for \(k = 2,3,4,5\):
sage: B = [hyperplane_arrangements.braid(k) for k in range(2,6)] sage: all(H.is_simplicial() for H in B) True sage: all(c > 0 for H in B # needs sage.graphs ....: for c in H.primitive_eulerian_polynomial().coefficients()) True
>>> from sage.all import * >>> B = [hyperplane_arrangements.braid(k) for k in range(Integer(2),Integer(6))] >>> all(H.is_simplicial() for H in B) True >>> all(c > Integer(0) for H in B # needs sage.graphs ... for c in H.primitive_eulerian_polynomial().coefficients()) True
B = [hyperplane_arrangements.braid(k) for k in range(2,6)] all(H.is_simplicial() for H in B) all(c > 0 for H in B # needs sage.graphs for c in H.primitive_eulerian_polynomial().coefficients())
We verify Example 9.4 in [BHS2023] showing a hyperplane arrangement whose primitive Eulerian polynomial does not have real roots (in general, the graphical arrangement of a cycle graph corresponds to the arrangements in Example 9.4):
sage: # needs sage.graphs sage: H = hyperplane_arrangements.graphical(graphs.CycleGraph(5)) sage: pep = H.primitive_eulerian_polynomial(); pep z^4 + 6*z^3 - 4*z^2 + z sage: pep.roots(QQbar) [(-6.626418492719221?, 1), (0, 1), (0.3132092463596102? - 0.2298065541510677?*I, 1), (0.3132092463596102? + 0.2298065541510677?*I, 1)] sage: pep.roots(AA) [(-6.626418492719221?, 1), (0, 1)]
>>> from sage.all import * >>> # needs sage.graphs >>> H = hyperplane_arrangements.graphical(graphs.CycleGraph(Integer(5))) >>> pep = H.primitive_eulerian_polynomial(); pep z^4 + 6*z^3 - 4*z^2 + z >>> pep.roots(QQbar) [(-6.626418492719221?, 1), (0, 1), (0.3132092463596102? - 0.2298065541510677?*I, 1), (0.3132092463596102? + 0.2298065541510677?*I, 1)] >>> pep.roots(AA) [(-6.626418492719221?, 1), (0, 1)]
# needs sage.graphs H = hyperplane_arrangements.graphical(graphs.CycleGraph(5)) pep = H.primitive_eulerian_polynomial(); pep pep.roots(QQbar) pep.roots(AA)
- rank()[source]¶
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: # needs sage.graphs 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
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3) >>> A = H([[Integer(0), Integer(1), Integer(2), Integer(3)],[-Integer(3), Integer(4), Integer(5), Integer(6)]]) >>> A.dimension() 3 >>> A.rank() 2 >>> # needs sage.graphs >>> B = hyperplane_arrangements.braid(Integer(3)) >>> B.hyperplanes() (Hyperplane 0*t0 + t1 - t2 + 0, Hyperplane t0 - t1 + 0*t2 + 0, Hyperplane t0 + 0*t1 - t2 + 0) >>> B.dimension() 3 >>> B.rank() 2 >>> p = polytopes.simplex(Integer(5), project=True) >>> H = p.hyperplane_arrangement() >>> H.rank() 5
H.<x,y,z> = HyperplaneArrangements(QQ) A = H([[0, 1, 2, 3],[-3, 4, 5, 6]]) A.dimension() A.rank() # needs sage.graphs B = hyperplane_arrangements.braid(3) B.hyperplanes() B.dimension() B.rank() p = polytopes.simplex(5, project=True) H = p.hyperplane_arrangement() H.rank()
- region_containing_point(p)[source]¶
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
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([(Integer(1),Integer(0)), Integer(0)], [(Integer(0),Integer(1)), Integer(1)], [(Integer(0),Integer(1)), -Integer(1)], [(Integer(1),-Integer(1)), Integer(0)], [(Integer(1),Integer(1)), Integer(0)]) >>> A.region_containing_point([Integer(1),Integer(2)]) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays
H.<x,y> = HyperplaneArrangements(QQ) A = H([(1,0), 0], [(0,1), 1], [(0,1), -1], [(1,-1), 0], [(1,1), 0]) A.region_containing_point([1,2])
- regions()[source]¶
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) # needs sage.graphs sage: a.regions() # needs sage.graphs (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
>>> from sage.all import * >>> a = hyperplane_arrangements.braid(Integer(2)) # needs sage.graphs >>> a.regions() # needs sage.graphs (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) >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H(x, y+Integer(1)) >>> 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) >>> chessboard = [] >>> N = Integer(8) >>> for x0 in range(N + Integer(1)): ... for y0 in range(N + Integer(1)): ... chessboard.extend([x-x0, y-y0]) >>> chessboard = H(chessboard) >>> len(chessboard.bounded_regions()) # long time, 359 ms on a Core i7 64
a = hyperplane_arrangements.braid(2) # needs sage.graphs a.regions() # needs sage.graphs H.<x,y> = HyperplaneArrangements(QQ) A = H(x, y+1) A.regions() chessboard = [] N = 8 for x0 in range(N + 1): for y0 in range(N + 1): chessboard.extend([x-x0, y-y0]) chessboard = H(chessboard) len(chessboard.bounded_regions()) # long time, 359 ms on a Core i7
Example 6 of [KP2020]:
sage: from itertools import product sage: def zero_one(d): ....: for x in product([0,1], repeat=d): ....: if any(x): ....: yield [0] + list(x) sage: K.<x,y> = HyperplaneArrangements(QQ) sage: A = K(*zero_one(2)) sage: len(A.regions()) 6 sage: K.<x,y,z> = HyperplaneArrangements(QQ) sage: A = K(*zero_one(3)) sage: len(A.regions()) 32 sage: K.<x,y,z,w> = HyperplaneArrangements(QQ) sage: A = K(*zero_one(4)) sage: len(A.regions()) 370 sage: K.<x,y,z,w,r> = HyperplaneArrangements(QQ) sage: A = K(*zero_one(5)) sage: len(A.regions()) # not tested (~25s) 11292
>>> from sage.all import * >>> from itertools import product >>> def zero_one(d): ... for x in product([Integer(0),Integer(1)], repeat=d): ... if any(x): ... yield [Integer(0)] + list(x) >>> K = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = K._first_ngens(2) >>> A = K(*zero_one(Integer(2))) >>> len(A.regions()) 6 >>> K = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = K._first_ngens(3) >>> A = K(*zero_one(Integer(3))) >>> len(A.regions()) 32 >>> K = HyperplaneArrangements(QQ, names=('x', 'y', 'z', 'w',)); (x, y, z, w,) = K._first_ngens(4) >>> A = K(*zero_one(Integer(4))) >>> len(A.regions()) 370 >>> K = HyperplaneArrangements(QQ, names=('x', 'y', 'z', 'w', 'r',)); (x, y, z, w, r,) = K._first_ngens(5) >>> A = K(*zero_one(Integer(5))) >>> len(A.regions()) # not tested (~25s) 11292
from itertools import product def zero_one(d): for x in product([0,1], repeat=d): if any(x): yield [0] + list(x) K.<x,y> = HyperplaneArrangements(QQ) A = K(*zero_one(2)) len(A.regions()) K.<x,y,z> = HyperplaneArrangements(QQ) A = K(*zero_one(3)) len(A.regions()) K.<x,y,z,w> = HyperplaneArrangements(QQ) A = K(*zero_one(4)) len(A.regions()) K.<x,y,z,w,r> = HyperplaneArrangements(QQ) A = K(*zero_one(5)) len(A.regions()) # not tested (~25s)
It is possible to specify the backend:
sage: # needs sage.rings.number_field sage: K.<q> = CyclotomicField(9) sage: L.<r9> = NumberField((q + q**(-1)).minpoly(), ....: embedding=AA(q + q**-1)) sage: norms = [[1, 1/3*(-2*r9**2-r9+1), 0], ....: [1, -r9**2 - r9, 0], ....: [1, -r9**2 + 1, 0], ....: [1, -r9**2, 0], ....: [1, r9**2 - 4, -r9**2+3]] sage: H.<x,y,z> = HyperplaneArrangements(L) sage: A = H(backend='normaliz') sage: for v in norms: ....: a,b,c = v ....: A = A.add_hyperplane(a*x + b*y + c*z) sage: R = A.regions() # optional - pynormaliz sage: R[0].backend() # optional - pynormaliz 'normaliz'
>>> from sage.all import * >>> # needs sage.rings.number_field >>> K = CyclotomicField(Integer(9), names=('q',)); (q,) = K._first_ngens(1) >>> L = NumberField((q + q**(-Integer(1))).minpoly(), ... embedding=AA(q + q**-Integer(1)), names=('r9',)); (r9,) = L._first_ngens(1) >>> norms = [[Integer(1), Integer(1)/Integer(3)*(-Integer(2)*r9**Integer(2)-r9+Integer(1)), Integer(0)], ... [Integer(1), -r9**Integer(2) - r9, Integer(0)], ... [Integer(1), -r9**Integer(2) + Integer(1), Integer(0)], ... [Integer(1), -r9**Integer(2), Integer(0)], ... [Integer(1), r9**Integer(2) - Integer(4), -r9**Integer(2)+Integer(3)]] >>> H = HyperplaneArrangements(L, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3) >>> A = H(backend='normaliz') >>> for v in norms: ... a,b,c = v ... A = A.add_hyperplane(a*x + b*y + c*z) >>> R = A.regions() # optional - pynormaliz >>> R[Integer(0)].backend() # optional - pynormaliz 'normaliz'
# needs sage.rings.number_field K.<q> = CyclotomicField(9) L.<r9> = NumberField((q + q**(-1)).minpoly(), embedding=AA(q + q**-1)) norms = [[1, 1/3*(-2*r9**2-r9+1), 0], [1, -r9**2 - r9, 0], [1, -r9**2 + 1, 0], [1, -r9**2, 0], [1, r9**2 - 4, -r9**2+3]] H.<x,y,z> = HyperplaneArrangements(L) A = H(backend='normaliz') for v in norms: a,b,c = v A = A.add_hyperplane(a*x + b*y + c*z) R = A.regions() # optional - pynormaliz R[0].backend() # optional - pynormaliz
- restriction(hyperplane, repetitions=False)[source]¶
Return the restriction to a hyperplane.
INPUT:
hyperplane
– a hyperplane of the hyperplane arrangementrepetitions
– boolean (default:False
); eliminate repetitions for ordered arrangements
OUTPUT:
The restriction \(\mathcal{A}_H\) of the hyperplane arrangement \(\mathcal{A}\) to the given
hyperplane
\(H\).EXAMPLES:
sage: # needs sage.graphs 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: A.add_hyperplane(z).restriction(z) Arrangement of 6 hyperplanes of dimension 3 and rank 3 sage: A.add_hyperplane(u).restriction(u) Arrangement of 6 hyperplanes of dimension 3 and rank 3 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
>>> from sage.all import * >>> # needs sage.graphs >>> A = hyperplane_arrangements.braid(Integer(4), names=('u', 'x', 'y', 'z',)); (u, x, y, z,) = A._first_ngens(4); A Arrangement of 6 hyperplanes of dimension 4 and rank 3 >>> H = A[Integer(0)]; H Hyperplane 0*u + 0*x + y - z + 0 >>> R = A.restriction(H); R Arrangement <x - z | u - x | u - z> >>> A.add_hyperplane(z).restriction(z) Arrangement of 6 hyperplanes of dimension 3 and rank 3 >>> A.add_hyperplane(u).restriction(u) Arrangement of 6 hyperplanes of dimension 3 and rank 3 >>> D = A.deletion(H); D Arrangement of 5 hyperplanes of dimension 4 and rank 3 >>> ca = A.characteristic_polynomial() >>> cr = R.characteristic_polynomial() >>> cd = D.characteristic_polynomial() >>> ca x^4 - 6*x^3 + 11*x^2 - 6*x >>> cd - cr x^4 - 6*x^3 + 11*x^2 - 6*x
# needs sage.graphs A.<u,x,y,z> = hyperplane_arrangements.braid(4); A H = A[0]; H R = A.restriction(H); R A.add_hyperplane(z).restriction(z) A.add_hyperplane(u).restriction(u) D = A.deletion(H); D ca = A.characteristic_polynomial() cr = R.characteristic_polynomial() cd = D.characteristic_polynomial() ca cd - cr
See also
- sign_vector(p)[source]¶
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)
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([(Integer(1),Integer(0)), Integer(0)], [(Integer(0),Integer(1)), Integer(1)]); A Arrangement <y + 1 | x> >>> A.sign_vector([Integer(2), -Integer(2)]) (-1, 1) >>> A.sign_vector((-Integer(1), -Integer(1))) (0, -1)
H.<x,y> = HyperplaneArrangements(QQ) A = H([(1,0), 0], [(0,1), 1]); A A.sign_vector([2, -2]) A.sign_vector((-1, -1))
- unbounded_regions()[source]¶
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.
See also
EXAMPLES:
sage: # needs sage.combinat 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)
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.semiorder(Integer(3)) >>> B = A.essentialization() >>> B.n_regions() - B.n_bounded_regions() 12 >>> 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)
# needs sage.combinat A = hyperplane_arrangements.semiorder(3) B = A.essentialization() B.n_regions() - B.n_bounded_regions() B.unbounded_regions()
- union(other)[source]¶
The union of
self
withother
.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: C = A.union(B); C Arrangement of 8 hyperplanes of dimension 2 and rank 2 sage: C == A | B # syntactic sugar True
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> A = H([Integer(1),Integer(2),Integer(3)], [Integer(0),Integer(1),Integer(1)], [Integer(0),Integer(1),-Integer(1)], [Integer(1),-Integer(1),Integer(0)], [Integer(1),Integer(1),Integer(0)]) >>> B = H([Integer(1),Integer(1),Integer(1)], [Integer(1),-Integer(1),Integer(1)], [Integer(1),Integer(0),-Integer(1)]) >>> C = A.union(B); C Arrangement of 8 hyperplanes of dimension 2 and rank 2 >>> C == A | B # syntactic sugar True
H.<x,y> = HyperplaneArrangements(QQ) A = H([1,2,3], [0,1,1], [0,1,-1], [1,-1,0], [1,1,0]) B = H([1,1,1], [1,-1,1], [1,0,-1]) C = A.union(B); C C == A | B # syntactic sugar
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
>>> from sage.all import * >>> A.union(x+y-Integer(1)) Arrangement of 6 hyperplanes of dimension 2 and rank 2 >>> A.add_hyperplane(x+y-Integer(1)) # alias Arrangement of 6 hyperplanes of dimension 2 and rank 2 >>> P = HyperplaneArrangements(RR, names=('x', 'y',)); (x, y,) = P._first_ngens(2) >>> C = P(Integer(2)*x + Integer(4)*y + Integer(5)) >>> C.union(A) Arrangement of 6 hyperplanes of dimension 2 and rank 2
A.union(x+y-1) A.add_hyperplane(x+y-1) # alias P.<x,y> = HyperplaneArrangements(RR) C = P(2*x + 4*y + 5) C.union(A)
- varchenko_matrix(names='h')[source]¶
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 h1*h2 h0*h1*h2 h0*h1 h0*h2 h0] [ h2 1 h1*h2 h1 h0*h1 h0*h1*h2 h0 h0*h2] [ h1 h1*h2 1 h2 h0*h2 h0 h0*h1*h2 h0*h1] [ h1*h2 h1 h2 1 h0 h0*h2 h0*h1 h0*h1*h2] [h0*h1*h2 h0*h1 h0*h2 h0 1 h2 h1 h1*h2] [ h0*h1 h0*h1*h2 h0 h0*h2 h2 1 h1*h2 h1] [ h0*h2 h0 h0*h1*h2 h0*h1 h1 h1*h2 1 h2] [ h0 h0*h2 h0*h1 h0*h1*h2 h1*h2 h1 h2 1] sage: factor(det(v)) (h2 - 1)^4 * (h2 + 1)^4 * (h1 - 1)^4 * (h1 + 1)^4 * (h0 - 1)^4 * (h0 + 1)^4
>>> from sage.all import * >>> a = hyperplane_arrangements.coordinate(Integer(3)) >>> v = a.varchenko_matrix(); v [ 1 h2 h1 h1*h2 h0*h1*h2 h0*h1 h0*h2 h0] [ h2 1 h1*h2 h1 h0*h1 h0*h1*h2 h0 h0*h2] [ h1 h1*h2 1 h2 h0*h2 h0 h0*h1*h2 h0*h1] [ h1*h2 h1 h2 1 h0 h0*h2 h0*h1 h0*h1*h2] [h0*h1*h2 h0*h1 h0*h2 h0 1 h2 h1 h1*h2] [ h0*h1 h0*h1*h2 h0 h0*h2 h2 1 h1*h2 h1] [ h0*h2 h0 h0*h1*h2 h0*h1 h1 h1*h2 1 h2] [ h0 h0*h2 h0*h1 h0*h1*h2 h1*h2 h1 h2 1] >>> factor(det(v)) (h2 - 1)^4 * (h2 + 1)^4 * (h1 - 1)^4 * (h1 + 1)^4 * (h0 - 1)^4 * (h0 + 1)^4
a = hyperplane_arrangements.coordinate(3) v = a.varchenko_matrix(); v factor(det(v))
- vertices(exclude_sandwiched=False)[source]¶
Return the vertices.
The vertices are the zero-dimensional faces, see
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: # needs sage.combinat 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() # needs sage.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))
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.Shi(Integer(3)).essentialization() >>> A.dimension() 2 >>> A.face_vector() (6, 21, 16) >>> A.vertices() ((-2/3, 1/3), (-1/3, -1/3), (0, -1), (0, 0), (1/3, -2/3), (2/3, -1/3)) >>> point2d(A.vertices(), size=Integer(20)) + A.plot() # needs sage.plot Graphics object consisting of 7 graphics primitives >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> chessboard = [] >>> N = Integer(8) >>> for x0 in range(N + Integer(1)): ... for y0 in range(N + Integer(1)): ... chessboard.extend([x-x0, y-y0]) >>> chessboard = H(chessboard) >>> len(chessboard.vertices()) 81 >>> chessboard.vertices(exclude_sandwiched=True) ((0, 0), (0, 8), (8, 0), (8, 8))
# needs sage.combinat A = hyperplane_arrangements.Shi(3).essentialization() A.dimension() A.face_vector() A.vertices() point2d(A.vertices(), size=20) + A.plot() # needs sage.plot H.<x,y> = HyperplaneArrangements(QQ) chessboard = [] N = 8 for x0 in range(N + 1): for y0 in range(N + 1): chessboard.extend([x-x0, y-y0]) chessboard = H(chessboard) len(chessboard.vertices()) chessboard.vertices(exclude_sandwiched=True)
- whitney_data()[source]¶
Return the Whitney numbers.
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: # needs sage.combinat 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] )
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.Shi(Integer(3)) >>> A.whitney_data() ( [ 1 -6 9] [ 1 6 6] [ 0 6 -15] [ 0 6 15] [ 0 0 6], [ 0 0 6] )
# needs sage.combinat A = hyperplane_arrangements.Shi(3) A.whitney_data()
- whitney_number(k, kind=1)[source]¶
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
– integerkind
– 1 or 2 (default: 1)
OUTPUT:
Integer. The
k
-th Whitney number.EXAMPLES:
sage: # needs sage.combinat 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
>>> from sage.all import * >>> # needs sage.combinat >>> A = hyperplane_arrangements.Shi(Integer(3)) >>> A.whitney_number(Integer(0)) 1 >>> A.whitney_number(Integer(1)) -6 >>> A.whitney_number(Integer(2)) 9 >>> A.characteristic_polynomial() x^3 - 6*x^2 + 9*x >>> A.whitney_number(Integer(1), kind=Integer(2)) 6 >>> p = A.intersection_poset() >>> r = p.rank_function() >>> len([i for i in p if r(i) == Integer(1)]) 6
# needs sage.combinat A = hyperplane_arrangements.Shi(3) A.whitney_number(0) A.whitney_number(1) A.whitney_number(2) A.characteristic_polynomial() A.whitney_number(1, kind=2) p = A.intersection_poset() r = p.rank_function() len([i for i in p if r(i) == 1])
- class sage.geometry.hyperplane_arrangement.arrangement.HyperplaneArrangements(base_ring, names=())[source]¶
Bases:
Parent
,UniqueRepresentation
Hyperplane arrangements.
For more information on hyperplane arrangements, see
sage.geometry.hyperplane_arrangement.arrangement
.INPUT:
base_ring
– ring; the base ringnames
– 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>
>>> from sage.all import * >>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2) >>> x Hyperplane x + 0*y + 0 >>> x + y Hyperplane x + y + 0 >>> H(x, y, x-Integer(1), y-Integer(1)) Arrangement <y - 1 | y | x - 1 | x>
H.<x,y> = HyperplaneArrangements(QQ) x x + y H(x, y, x-1, y-1)
- Element[source]¶
alias of
HyperplaneArrangementElement
- ambient_space()[source]¶
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
>>> from sage.all import * >>> L = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = L._first_ngens(2) >>> L.ambient_space()([(Integer(1),Integer(0)), Integer(0)]) Hyperplane x + 0*y + 0 >>> L.ambient_space()([(Integer(1),Integer(0)), Integer(0)]) == x True
L.<x, y> = HyperplaneArrangements(QQ) L.ambient_space()([(1,0), 0]) L.ambient_space()([(1,0), 0]) == x
- base_ring()[source]¶
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
>>> from sage.all import * >>> L = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = L._first_ngens(2) >>> L.base_ring() Rational Field
L.<x,y> = HyperplaneArrangements(QQ) L.base_ring()
- change_ring(base_ring)[source]¶
Return hyperplane arrangements over a different base ring.
INPUT:
base_ring
– a ring; the new base ring
OUTPUT:
A new
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
>>> from sage.all import * >>> L = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = L._first_ngens(2) >>> L.gen(Integer(0)) Hyperplane x + 0*y + 0 >>> L.change_ring(RR).gen(Integer(0)) Hyperplane 1.00000000000000*x + 0.000000000000000*y + 0.000000000000000
L.<x,y> = HyperplaneArrangements(QQ) L.gen(0) L.change_ring(RR).gen(0)
- gen(i)[source]¶
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
>>> from sage.all import * >>> L = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = L._first_ngens(3); L Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z >>> L.gen(Integer(0)) Hyperplane x + 0*y + 0*z + 0
L.<x, y, z> = HyperplaneArrangements(QQ); L L.gen(0)
- gens()[source]¶
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)
>>> from sage.all import * >>> L = HyperplaneArrangements(QQ, ('x', 'y', 'z')) >>> L.gens() (Hyperplane x + 0*y + 0*z + 0, Hyperplane 0*x + y + 0*z + 0, Hyperplane 0*x + 0*y + z + 0)
L = HyperplaneArrangements(QQ, ('x', 'y', 'z')) L.gens()
- ngens()[source]¶
Return the number of linear variables.
OUTPUT: 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
>>> from sage.all import * >>> L = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = L._first_ngens(3); L Hyperplane arrangements in 3-dimensional linear space over Rational Field with coordinates x, y, z >>> L.ngens() 3
L.<x, y, z> = HyperplaneArrangements(QQ); L L.ngens()