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)