Source code for mpt4py.geometry.zonotope
import numpy as np
from itertools import product
from typing import Optional, Union, Sequence
from mpt4py.base import Vector, Matrix, VData
from .polyhedron import Polyhedron
[docs]
class Zonotope(Polyhedron):
r"""
The zonotope class.
A zonotope :math:`\mathcal{Z}\subset \mathbb{R}^n` is defined as:
.. math::
\mathcal{Z} := \{ c+\sum\limits_{i=1}^p \beta_i g_i \mid \beta_i \in \left[-1,1\right] \}
"""
def __init__(self, G: Matrix, c: Optional[Vector] = None):
if c is None:
c = np.zeros((G.shape[1],))
vertices = self._compute_vertices(G, c)
super().__init__(V=VData(V=vertices))
self._c = c
self._G = G
self._chebyshev_center = self.c
self._chebyshev_radius = np.min(np.sum(np.abs(self.G), axis=0)) # Min over summed absolute column values
def _compute_vertices(self, generators: Matrix, center: Vector) -> Matrix:
n, _ = generators.shape # number of generators, dimension
sign_combinations = np.array(list(product([-1, 1], repeat=n)))
vertices = center + sign_combinations @ generators
return vertices
@property
def c(self) -> Vector:
"""
Get the center of the zonotope.
"""
return self._c
@property
def G(self) -> Matrix:
"""
Get the generator matrix of the zonotope.
"""
return self._G
center = c
generators = G
@property
def dim(self) -> int:
return self.c.size
[docs]
def projection(self, dims: Sequence, method: Optional[str] = None) -> "Zonotope":
r"""
Compute the orthogonal projection of a zonotope onto given dimensions.
"""
return Zonotope(G=self.G[:, dims], c=self.c[dims])
[docs]
def minkowski_sum(self, other: Union[Vector, Polyhedron, "Zonotope"]) -> Union[Polyhedron, "Zonotope"]:
r"""
Compute the Minkowski sum of two zonotopes.
"""
if isinstance(other, np.ndarray):
new_center = self.c + other
return Zonotope(new_center, self.G)
elif isinstance(other, Zonotope):
new_center = self.c + other.c
new_generators = np.vstack((self.G, other.G))
return Zonotope(new_center, new_generators)
elif isinstance(other, Polyhedron):
return other.minkowski_sum(self)
else:
raise ValueError("Unsupported argument type.")
def __add__(self, other: Union[Vector, Polyhedron, "Zonotope"]) -> Union[Polyhedron, "Zonotope"]:
return self.minkowski_sum(other)
[docs]
def affine_map(self, T: Matrix, t: Optional[Vector] = None) -> "Zonotope":
r"""
Apply an affine transformation to the zonotope.
:param T: Affine transformation matrix.
:param t: Translation vector.
"""
if t is None:
t = np.zeros((self.dim,))
return Zonotope(T @ self.G, T @ self.c + t)