# 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]])

`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]])