Hyperplanes#

Note

If you want to learn about Sage’s hyperplane arrangements then you should start with sage.geometry.hyperplane_arrangement.arrangement. This module is used to represent the individual hyperplanes, but you should never construct the classes from this module directly (but only via the HyperplaneArrangements.

A linear expression, for example, \(3x+3y-5z-7\) stands for the hyperplane with the equation \(x+3y-5z=7\). To create it in Sage, you first have to create a 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.coefficients()
[-7, 3, 2, -5]
sage: h.normal()
(3, 2, -5)
sage: h.constant_term()
-7
sage: h.change_ring(GF(3))
Hyperplane 0*x + 2*y + z + 2
sage: h.point()
(21/38, 7/19, -35/38)
sage: h.linear_part()
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[  1   0 3/5]
[  0   1 2/5]
>>> 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.coefficients()
[-7, 3, 2, -5]
>>> h.normal()
(3, 2, -5)
>>> h.constant_term()
-7
>>> h.change_ring(GF(Integer(3)))
Hyperplane 0*x + 2*y + z + 2
>>> h.point()
(21/38, 7/19, -35/38)
>>> h.linear_part()
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[  1   0 3/5]
[  0   1 2/5]

Another syntax to create hyperplanes is to specify coefficients and a constant term:

sage: V = H.ambient_space();  V
3-dimensional linear space over Rational Field with coordinates x, y, z
sage: h in V
True
sage: V([3, 2, -5], -7)
Hyperplane 3*x + 2*y - 5*z - 7
>>> from sage.all import *
>>> V = H.ambient_space();  V
3-dimensional linear space over Rational Field with coordinates x, y, z
>>> h in V
True
>>> V([Integer(3), Integer(2), -Integer(5)], -Integer(7))
Hyperplane 3*x + 2*y - 5*z - 7

Or constant term and coefficients together in one list/tuple/iterable:

sage: V([-7, 3, 2, -5])
Hyperplane 3*x + 2*y - 5*z - 7
sage: v = vector([-7, 3, 2, -5]);  v
(-7, 3, 2, -5)
sage: V(v)
Hyperplane 3*x + 2*y - 5*z - 7
>>> from sage.all import *
>>> V([-Integer(7), Integer(3), Integer(2), -Integer(5)])
Hyperplane 3*x + 2*y - 5*z - 7
>>> v = vector([-Integer(7), Integer(3), Integer(2), -Integer(5)]);  v
(-7, 3, 2, -5)
>>> V(v)
Hyperplane 3*x + 2*y - 5*z - 7

Note that the constant term comes first, which matches the notation for Sage’s Polyhedron()

sage: Polyhedron(ieqs=[(4,1,2,3)]).Hrepresentation()
(An inequality (1, 2, 3) x + 4 >= 0,)
>>> from sage.all import *
>>> Polyhedron(ieqs=[(Integer(4),Integer(1),Integer(2),Integer(3))]).Hrepresentation()
(An inequality (1, 2, 3) x + 4 >= 0,)

The difference between hyperplanes as implemented in this module and hyperplane arrangements is that:

  • hyperplane arrangements contain multiple hyperplanes (of course),

  • linear expressions are a module over the base ring, and these module structure is inherited by the hyperplanes.

The latter means that you can add and multiply by a scalar:

sage: h = 3*x + 2*y - 5*z - 7;  h
Hyperplane 3*x + 2*y - 5*z - 7
sage: -h
Hyperplane -3*x - 2*y + 5*z + 7
sage: h + x
Hyperplane 4*x + 2*y - 5*z - 7
sage: h + 7
Hyperplane 3*x + 2*y - 5*z + 0
sage: 3*h
Hyperplane 9*x + 6*y - 15*z - 21
sage: h * RDF(3)
Hyperplane 9.0*x + 6.0*y - 15.0*z - 21.0
>>> from sage.all import *
>>> h = Integer(3)*x + Integer(2)*y - Integer(5)*z - Integer(7);  h
Hyperplane 3*x + 2*y - 5*z - 7
>>> -h
Hyperplane -3*x - 2*y + 5*z + 7
>>> h + x
Hyperplane 4*x + 2*y - 5*z - 7
>>> h + Integer(7)
Hyperplane 3*x + 2*y - 5*z + 0
>>> Integer(3)*h
Hyperplane 9*x + 6*y - 15*z - 21
>>> h * RDF(Integer(3))
Hyperplane 9.0*x + 6.0*y - 15.0*z - 21.0

Which you can’t do with hyperplane arrangements:

sage: arrangement = H(h, x, y, x+y-1);  arrangement
Arrangement <y | x | x + y - 1 | 3*x + 2*y - 5*z - 7>
sage: arrangement + x
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +:
'Hyperplane arrangements in 3-dimensional linear space
     over Rational Field with coordinates x, y, z' and
'Hyperplane arrangements in 3-dimensional linear space
     over Rational Field with coordinates x, y, z'
>>> from sage.all import *
>>> arrangement = H(h, x, y, x+y-Integer(1));  arrangement
Arrangement <y | x | x + y - 1 | 3*x + 2*y - 5*z - 7>
>>> arrangement + x
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +:
'Hyperplane arrangements in 3-dimensional linear space
     over Rational Field with coordinates x, y, z' and
'Hyperplane arrangements in 3-dimensional linear space
     over Rational Field with coordinates x, y, z'
class sage.geometry.hyperplane_arrangement.hyperplane.AmbientVectorSpace(base_ring, names=())[source]#

Bases: LinearExpressionModule

The ambient space for hyperplanes.

This class is the parent for the Hyperplane instances.

Element[source]#

alias of Hyperplane

change_ring(base_ring)[source]#

Return a ambient vector space with a changed base ring.

INPUT:

  • base_ring – a ring; the new base ring

OUTPUT:

A new AmbientVectorSpace.

EXAMPLES:

sage: M.<y> = HyperplaneArrangements(QQ)
sage: V = M.ambient_space()
sage: V.change_ring(RR)
1-dimensional linear space over Real Field with 53 bits of precision with coordinate y
>>> from sage.all import *
>>> M = HyperplaneArrangements(QQ, names=('y',)); (y,) = M._first_ngens(1)
>>> V = M.ambient_space()
>>> V.change_ring(RR)
1-dimensional linear space over Real Field with 53 bits of precision with coordinate y
dimension()[source]#

Return the ambient space dimension.

OUTPUT:

An integer.

EXAMPLES:

sage: M.<x,y> = HyperplaneArrangements(QQ)
sage: x.parent().dimension()
2
sage: x.parent() is M.ambient_space()
True
sage: x.dimension()
1
>>> from sage.all import *
>>> M = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = M._first_ngens(2)
>>> x.parent().dimension()
2
>>> x.parent() is M.ambient_space()
True
>>> x.dimension()
1
symmetric_space()[source]#

Construct the symmetric space of self.

Consider a hyperplane arrangement \(A\) in the vector space \(V = k^n\), for some field \(k\). The symmetric space is the symmetric algebra \(S(V^*)\) as the polynomial ring \(k[x_1, x_2, \ldots, x_n]\) where \((x_1, x_2, \ldots, x_n)\) is a basis for \(V\).

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: A = H.ambient_space()
sage: A.symmetric_space()
Multivariate Polynomial Ring in x, y, z over Rational Field
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> A = H.ambient_space()
>>> A.symmetric_space()
Multivariate Polynomial Ring in x, y, z over Rational Field
class sage.geometry.hyperplane_arrangement.hyperplane.Hyperplane(parent, coefficients, constant)[source]#

Bases: LinearExpression

A hyperplane.

You should always use AmbientVectorSpace to construct instances of this class.

INPUT:

  • parent – the parent AmbientVectorSpace

  • coefficients – a vector of coefficients of the linear variables

  • constant – the constant term for the linear expression

EXAMPLES:

sage: H.<x,y> = HyperplaneArrangements(QQ)
sage: x+y-1
Hyperplane x + y - 1

sage: ambient = H.ambient_space()
sage: ambient._element_constructor_(x+y-1)
Hyperplane x + y - 1
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2)
>>> x+y-Integer(1)
Hyperplane x + y - 1

>>> ambient = H.ambient_space()
>>> ambient._element_constructor_(x+y-Integer(1))
Hyperplane x + y - 1

For technical reasons, we must allow the degenerate cases of an empty space and of a full space:

sage: 0*x
Hyperplane 0*x + 0*y + 0
sage: 0*x + 1
Hyperplane 0*x + 0*y + 1
sage: x + 0 == x + ambient(0)    # because coercion requires them
True
>>> from sage.all import *
>>> Integer(0)*x
Hyperplane 0*x + 0*y + 0
>>> Integer(0)*x + Integer(1)
Hyperplane 0*x + 0*y + 1
>>> x + Integer(0) == x + ambient(Integer(0))    # because coercion requires them
True
dimension()[source]#

The dimension of the hyperplane.

OUTPUT:

An integer.

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: h = x + y + z - 1
sage: h.dimension()
2
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + y + z - Integer(1)
>>> h.dimension()
2
intersection(other)[source]#

The intersection of self with other.

INPUT:

  • other – a hyperplane, a polyhedron, or something that defines a polyhedron

OUTPUT:

A polyhedron.

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: h = x + y + z - 1
sage: h.intersection(x - y)
A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line
sage: h.intersection(polytopes.cube())
A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + y + z - Integer(1)
>>> h.intersection(x - y)
A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line
>>> h.intersection(polytopes.cube())
A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices
linear_part()[source]#

The linear part of the affine space.

OUTPUT:

Vector subspace of the ambient vector space, parallel to the hyperplane.

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: h = x + 2*y + 3*z - 1
sage: h.linear_part()
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[   1    0 -1/3]
[   0    1 -2/3]
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + Integer(2)*y + Integer(3)*z - Integer(1)
>>> h.linear_part()
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[   1    0 -1/3]
[   0    1 -2/3]
linear_part_projection(point)[source]#

Orthogonal projection onto the linear part.

INPUT:

  • point – vector of the ambient space, or anything that can be converted into one; not necessarily on the hyperplane

OUTPUT:

Coordinate vector of the projection of point with respect to the basis of linear_part(). In particular, the length of this vector is one less than the ambient space dimension.

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: h = x + 2*y + 3*z - 4
sage: h.linear_part()
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[   1    0 -1/3]
[   0    1 -2/3]
sage: p1 = h.linear_part_projection(0);  p1
(0, 0)
sage: p2 = h.linear_part_projection([3,4,5]);  p2
(8/7, 2/7)
sage: h.linear_part().basis()
[
(1, 0, -1/3),
(0, 1, -2/3)
]
sage: p3 = h.linear_part_projection([1,1,1]);  p3
(4/7, 1/7)
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + Integer(2)*y + Integer(3)*z - Integer(4)
>>> h.linear_part()
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[   1    0 -1/3]
[   0    1 -2/3]
>>> p1 = h.linear_part_projection(Integer(0));  p1
(0, 0)
>>> p2 = h.linear_part_projection([Integer(3),Integer(4),Integer(5)]);  p2
(8/7, 2/7)
>>> h.linear_part().basis()
[
(1, 0, -1/3),
(0, 1, -2/3)
]
>>> p3 = h.linear_part_projection([Integer(1),Integer(1),Integer(1)]);  p3
(4/7, 1/7)
normal()[source]#

Return the normal vector.

OUTPUT:

A vector over the base ring.

EXAMPLES:

sage: H.<x, y, z> = HyperplaneArrangements(QQ)
sage: x.normal()
(1, 0, 0)
sage: x.A(), x.b()
((1, 0, 0), 0)
sage: (x + 2*y + 3*z + 4).normal()
(1, 2, 3)
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> x.normal()
(1, 0, 0)
>>> x.A(), x.b()
((1, 0, 0), 0)
>>> (x + Integer(2)*y + Integer(3)*z + Integer(4)).normal()
(1, 2, 3)
orthogonal_projection(point)[source]#

Return the orthogonal projection of a point.

INPUT:

  • point – vector of the ambient space, or anything that can be converted into one; not necessarily on the hyperplane

OUTPUT:

A vector in the ambient vector space that lies on the hyperplane.

In finite characteristic, a ValueError is raised if the the norm of the hyperplane normal is zero.

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: h = x + 2*y + 3*z - 4
sage: p1 = h.orthogonal_projection(0);  p1
(2/7, 4/7, 6/7)
sage: p1 in h
True
sage: p2 = h.orthogonal_projection([3,4,5]);  p2
(10/7, 6/7, 2/7)
sage: p1 in h
True
sage: p3 = h.orthogonal_projection([1,1,1]);  p3
(6/7, 5/7, 4/7)
sage: p3 in h
True
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + Integer(2)*y + Integer(3)*z - Integer(4)
>>> p1 = h.orthogonal_projection(Integer(0));  p1
(2/7, 4/7, 6/7)
>>> p1 in h
True
>>> p2 = h.orthogonal_projection([Integer(3),Integer(4),Integer(5)]);  p2
(10/7, 6/7, 2/7)
>>> p1 in h
True
>>> p3 = h.orthogonal_projection([Integer(1),Integer(1),Integer(1)]);  p3
(6/7, 5/7, 4/7)
>>> p3 in h
True
plot(**kwds)[source]#

Plot the hyperplane.

OUTPUT:

A graphics object.

EXAMPLES:

sage: L.<x, y> = HyperplaneArrangements(QQ)
sage: (x + y - 2).plot()                                                    # needs sage.plot
Graphics object consisting of 2 graphics primitives
>>> from sage.all import *
>>> L = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = L._first_ngens(2)
>>> (x + y - Integer(2)).plot()                                                    # needs sage.plot
Graphics object consisting of 2 graphics primitives
point()[source]#

Return the point closest to the origin.

OUTPUT:

A vector of the ambient vector space. The closest point to the origin in the \(L^2\)-norm.

In finite characteristic a random point will be returned if the norm of the hyperplane normal vector is zero.

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: h = x + 2*y + 3*z - 4
sage: h.point()
(2/7, 4/7, 6/7)
sage: h.point() in h
True

sage: # needs sage.rings.finite_rings
sage: H.<x,y,z> = HyperplaneArrangements(GF(3))
sage: h = 2*x + y + z + 1
sage: h.point()
(1, 0, 0)
sage: h.point().base_ring()
Finite Field of size 3

sage: H.<x,y,z> = HyperplaneArrangements(GF(3))
sage: h = x + y + z + 1
sage: h.point()
(2, 0, 0)
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + Integer(2)*y + Integer(3)*z - Integer(4)
>>> h.point()
(2/7, 4/7, 6/7)
>>> h.point() in h
True

>>> # needs sage.rings.finite_rings
>>> H = HyperplaneArrangements(GF(Integer(3)), names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = Integer(2)*x + y + z + Integer(1)
>>> h.point()
(1, 0, 0)
>>> h.point().base_ring()
Finite Field of size 3

>>> H = HyperplaneArrangements(GF(Integer(3)), names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + y + z + Integer(1)
>>> h.point()
(2, 0, 0)
polyhedron(**kwds)[source]#

Return the hyperplane as a polyhedron.

OUTPUT:

A Polyhedron() instance.

EXAMPLES:

sage: H.<x,y,z> = HyperplaneArrangements(QQ)
sage: h = x + 2*y + 3*z - 4
sage: P = h.polyhedron();  P
A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 lines
sage: P.Hrepresentation()
(An equation (1, 2, 3) x - 4 == 0,)
sage: P.Vrepresentation()
(A line in the direction (0, 3, -2),
 A line in the direction (3, 0, -1),
 A vertex at (0, 0, 4/3))
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y', 'z',)); (x, y, z,) = H._first_ngens(3)
>>> h = x + Integer(2)*y + Integer(3)*z - Integer(4)
>>> P = h.polyhedron();  P
A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 lines
>>> P.Hrepresentation()
(An equation (1, 2, 3) x - 4 == 0,)
>>> P.Vrepresentation()
(A line in the direction (0, 3, -2),
 A line in the direction (3, 0, -1),
 A vertex at (0, 0, 4/3))
primitive(signed=True)[source]#

Return hyperplane defined by primitive equation.

INPUT:

  • signed – boolean (default: True); whether to preserve the overall sign

OUTPUT:

Hyperplane whose linear expression has common factors and denominators cleared. That is, the same hyperplane (with the same sign) but defined by a rescaled equation. Note that different linear expressions must define different hyperplanes as comparison is used in caching.

If signed, the overall rescaling is by a positive constant only.

EXAMPLES:

sage: H.<x,y> = HyperplaneArrangements(QQ)
sage: h = -1/3*x + 1/2*y - 1;  h
Hyperplane -1/3*x + 1/2*y - 1
sage: h.primitive()
Hyperplane -2*x + 3*y - 6
sage: h == h.primitive()
False
sage: (4*x + 8).primitive()
Hyperplane x + 0*y + 2

sage: (4*x - y - 8).primitive(signed=True)   # default
Hyperplane 4*x - y - 8
sage: (4*x - y - 8).primitive(signed=False)
Hyperplane -4*x + y + 8
>>> from sage.all import *
>>> H = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = H._first_ngens(2)
>>> h = -Integer(1)/Integer(3)*x + Integer(1)/Integer(2)*y - Integer(1);  h
Hyperplane -1/3*x + 1/2*y - 1
>>> h.primitive()
Hyperplane -2*x + 3*y - 6
>>> h == h.primitive()
False
>>> (Integer(4)*x + Integer(8)).primitive()
Hyperplane x + 0*y + 2

>>> (Integer(4)*x - y - Integer(8)).primitive(signed=True)   # default
Hyperplane 4*x - y - 8
>>> (Integer(4)*x - y - Integer(8)).primitive(signed=False)
Hyperplane -4*x + y + 8
to_symmetric_space()[source]#

Return self considered as an element in the corresponding symmetric space.

EXAMPLES:

sage: L.<x, y> = HyperplaneArrangements(QQ)
sage: h = -1/3*x + 1/2*y
sage: h.to_symmetric_space()
-1/3*x + 1/2*y

sage: hp = -1/3*x + 1/2*y - 1
sage: hp.to_symmetric_space()
Traceback (most recent call last):
...
ValueError: the hyperplane must pass through the origin
>>> from sage.all import *
>>> L = HyperplaneArrangements(QQ, names=('x', 'y',)); (x, y,) = L._first_ngens(2)
>>> h = -Integer(1)/Integer(3)*x + Integer(1)/Integer(2)*y
>>> h.to_symmetric_space()
-1/3*x + 1/2*y

>>> hp = -Integer(1)/Integer(3)*x + Integer(1)/Integer(2)*y - Integer(1)
>>> hp.to_symmetric_space()
Traceback (most recent call last):
...
ValueError: the hyperplane must pass through the origin