# PolytopeFace Class

This class handles all computations relating to faces of lattice polytopes.

## Constructor

`cytools.polytopeface.PolytopeFace`

**Description:**
Constructs a `PolytopeFace`

object describing a face of a lattice polytope.
This is handled by the hidden `__init__`

function.

**Arguments:**

`ambient_poly`

*(Polytope)*: The ambient polytope.`vertices`

*(array_like)*: The list of vertices.`saturated_ineqs`

*(frozenset)*: A frozenset containing the indices of the inequalities that this face saturates.`dim`

*(int, optional)*: The dimension of the face. If it is not given then it is computed.

**Example**

Since objects of this class should not be directly created by the end user,
we demostrate how to construct these objects using the
`faces`

function of the `Polytope`

class.

`from cytools import Polytope`

p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])

faces_3 = p.faces(3) # Find the 3-dimensional faces

print(faces_3[0]) # Print the first 3-face

# A 3-dimensional face of a 4-dimensional polytope in ZZ^4

## Functions

`ambient_dimension`

**Description:**
Returns the dimension of the ambient lattice.

**Arguments:**
None.

**Returns:**
*(int)* The dimension of the ambient lattice.

**Aliases:**
`ambient_dim`

.

**Example**

We construct a face from a polytope and print its ambient dimension.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

f.ambient_dimension()

# 4

`ambient_polytope`

**Description:**
Returns the ambient polytope of the face.

**Arguments:**
None.

**Returns:**
*(Polytope)* The ambient polytope.

**Example**

We construct a face object from a polytope, then find the ambient polytope and verify that it is the starting polytope.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

ambient_poly = f.ambient_polytope()

ambient_poly is p

# True

`as_polytope`

**Description:**
Returns the face as a Polytope object.

**Arguments:**
None.

**Returns:**
*(Polytope)* The `Polytope`

corresponding to the face.

**Example**

We construct a face object and then convert it into a
`Polytope`

object.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

f_poly = f.as_polytope()

print(f_poly)

# A 3-dimensional lattice polytope in ZZ^4

`boundary_points`

**Description:**
Returns the boundary lattice points of the face.

**Arguments:**

`as_indices`

*(bool)*: Return the points as indices of the full list of points of the polytope.

**Returns:**
*(numpy.ndarray)* The list of boundary lattice points of the face.

**Aliases:**
`boundary_pts`

.

**Example**

We construct a face object and find its boundary lattice points.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

f.boundary_points()

# array([[-1, -1, -1, -1],

# [ 0, 0, 0, 1],

# [ 0, 0, 1, 0],

# [ 0, 1, 0, 0]])

`clear_cache`

**Description:**
Clears the cached results of any previous computation.

**Arguments:**
None.

**Returns:**
Nothing.

**Example**

We construct a face object and find its lattice points, then we clear the cache and compute the points again.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

pts = f.points() # Find the lattice points

f.clear_cache() # Clears the results of any previos computation

pts = f.points() # Find the lattice points again

`dimension`

**Description:**
Returns the dimension of the face.

**Arguments:**
None.

**Returns:**
*(int)* The dimension of the face.

**Aliases:**
`dim`

.

**Example**

We construct a face from a polytope and print its dimension.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

f.dimension()

# 3

`dual_face`

**Description:**
Returns the dual face of the dual polytope.

This duality is only implemented for reflexive polytopes. An exception is raised if the polytope is not reflexive.

**Arguments:**
None.

**Returns:**
*(PolytopeFace)* The dual face.

**Aliases:**
`dual`

.

**Example**

We construct a face object from a polytope, then find the dual face in the dual polytope.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(2)[0] # Pick one of the 2-faces

f_dual = f.dual_face()

print(f_dual)

# A 1-dimensional face of a 4-dimensional polytope in ZZ^4

`faces`

**Description:**
Computes the faces of the face.

**Arguments:**

`d`

*(int, optional)*: Optional parameter that specifies the dimension of the desired faces.

**Returns:**
*(tuple)* A tuple of `PolytopeFace`

objects of
dimension d, if specified. Otherwise, a tuple of tuples of
`PolytopeFace`

objects organized in ascending
dimension.

**Example**

We construct a face from a polytope and find its vertices.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

print(f.faces(2)[0]) # Print one of its 2-faces

# A 2-dimensional face of a 4-dimensional polytope in ZZ^4

`interior_points`

**Description:**
Returns the interior lattice points of the face.

**Arguments:**

`as_indices`

*(bool)*: Return the points as indices of the full list of points of the polytope.

**Returns:**
*(numpy.ndarray)* The list of interior lattice points of the face.

**Aliases:**
`interior_pts`

.

**Example**

We construct a face object and find its interior lattice points.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-6,-9]])`

f = p.faces(3)[2] # Pick one of the 3-faces

f.interior_points()

# array([[ 0, 0, -1, -2],

# [ 0, 0, 0, -1]])

`points`

**Description:**
Returns the lattice points of the face.

**Arguments:**

`as_indices`

*(bool)*: Return the points as indices of the full list of points of the polytope.

**Returns:**
*(numpy.ndarray)* The list of lattice points of the face.

**Aliases:**
`pts`

.

**Example**

We construct a face object and find its lattice points.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0] # Pick one of the 3-faces

f.points()

# array([[-1, -1, -1, -1],

# [ 0, 0, 0, 1],

# [ 0, 0, 1, 0],

# [ 0, 1, 0, 0]])

`triangulate`

**Description:**
Returns a single regular triangulation of the face.

Just a simple wrapper for the Triangulation constructor.

Also see Polytope.triangulate

**Arguments:**

`heights`

*(array_like, optional)*: A list of heights specifying the regular triangulation. When not specified, it will return the Delaunay triangulation when using CGAL, a triangulation obtained from random heights near the Delaunay when using QHull, or the placing triangulation when using TOPCOM. Heights can only be specified when using CGAL or QHull as the backend.`simplices`

*(array_like, optional)*: A list of simplices specifying the triangulation. This is useful when a triangulation was previously computed and it needs to be used again. Note that the order of the points needs to be consistent with the order that the`Polytope`

class uses.`check_input_simplices`

*(bool, optional, default=True)*: Flag that specifies whether to check if the input simplices define a valid triangulation.`backend`

*(str, optional, default="cgal")*: Specifies the backend used to compute the triangulation. The available options are "qhull", "cgal", and "topcom". CGAL is the default one as it is very fast and robust.

**Returns:**
*(Triangulation)* A `Triangulation`

object describing
a triangulation of the polytope.

`vertices`

**Description:**
Returns the vertices of the face.

**Arguments:**
None.

**Returns:**
*(numpy.ndarray)* The list of vertices of the face.

**Example**

We construct a face from a polytope and find its vertices.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(2)[0] # Pick one of the 2-faces

f.vertices()

# array([[-1, -1, -1, -1],

# [ 0, 0, 0, 1],

# [ 0, 0, 1, 0]])

## Hidden Functions

`__init__`

**Description:**
Initializes a `PolytopeFace`

object.

**Arguments:**

`ambient_poly`

*(Polytope)*: The ambient polytope.`vertices`

*(array_like)*: The list of vertices.`saturated_ineqs`

*(frozenset)*: A frozenset containing the indices of the inequalities that this face saturates.`dim`

*(int, optional)*: The dimension of the face. If it is not given then it is computed.

**Returns:**
Nothing.

**Example**

This is the function that is called when creating a new
`PolytopeFace`

object. Thus, it is used in the following example.

`from cytools import Polytope`

p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])

faces_3 = p.faces(3) # Find the 3-dimensional faces

print(faces_3[0]) # Print the first 3-face

# A 3-dimensional face of a 4-dimensional polytope in ZZ^4

`__repr__`

**Description:**
Returns a string describing the face.

**Arguments:**
None.

**Returns:**
*(str)* A string describing the face.

**Example**

This function can be used to convert the face to a string or to print information about the face.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0]

face_info = str(f) # Converts to string

print(f) # Prints face info

`_points_saturated`

**Description:**
Computes the lattice points of the face along with the indices of the
hyperplane inequalities that they saturate.

- Points are sorted in the same way as for the
`_points_saturated`

function of the`Polytope`

class. - Typically this function should not be called by the user. Instead, it is called by various other functions in the PolytopeFace class.

**Arguments:**
None.

**Returns:**
*(list)* A list of tuples. The first component of each tuple is the list
of coordinates of the point and the second component is a
`frozenset`

of the hyperplane inequalities that it saturates.

**Example**

We construct a face and compute the lattice points along with the inequalities that they saturate. We print the second point and the inequalities that it saturates.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])`

f = p.faces(3)[0]

pts_sat = f._points_saturated()

print(pts_sat[1])

# ((0, 0, 0, 1), frozenset({0, 1, 2, 4}))

p.inequalities()[list(pts_sat[1][1])]

# array([[ 4, -1, -1, -1, 1],

# [-1, 4, -1, -1, 1],

# [-1, -1, 4, -1, 1],

# [-1, -1, -1, 4, 1]])