class_docstr: A polytope sampler using Delaunay triangulation.
  
  This sampler first enumerates the vertices of the constraint polytope and
  then uses a Delaunay triangulation to tesselate its convex hull.
  
  The sampling happens in two stages:
  1. First, we sample from the set of hypertriangles generated by the
  Delaunay triangulation (i.e. which hyper-triangle to draw the sample
  from) with probabilities proportional to the triangle volumes.
  2. Then, we sample uniformly from the chosen hypertriangle by sampling
  uniformly from the unit simplex of the appropriate dimension, and
  then computing the convex combination of the vertices of the
  hypertriangle according to that draw from the simplex.
  
  The best reference (not exactly the same, but functionally equivalent) is
  [Trikalinos2014polytope]_. A simple R implementation is available at
  https://github.com/gertvv/tesselample.
class_docstr_tok: ["A","polytope","sampler","using","Delaunay","triangulation",".","This","sampler","first","enumerates","the","vertices","of","the","constraint","polytope","and","then","uses","a","Delaunay","triangulation","to","tesselate","its","convex","hull",".","The","sampling","happens","in","two","stages",":","1",".","First",",","we","sample","from","the","set","of","hypertriangles","generated","by","the","Delaunay","triangulation","(","i.e",".","which","hyper-triangle","to","draw","the","sample","from",")","with","probabilities","proportional","to","the","triangle","volumes",".","2",".","Then",",","we","sample","uniformly","from","the","chosen","hypertriangle","by","sampling","uniformly","from","the","unit","simplex","of","the","appropriate","dimension",",","and","then","computing","the","convex","combination","of","the","vertices","of","the","hypertriangle","according","to","that","draw","from","the","simplex",".","The","best","reference","(","not","exactly","the","same",",","but","functionally","equivalent",")","is","[","Trikalinos2014polytope","]","_",".","A","simple","R","implementation","is","available","at","https",":","\/\/github.com\/gertvv\/tesselample","."]
docstr: Initialize DelaunayPolytopeSampler.
  
  Args:
      inequality_constraints: Tensors `(A, b)` describing inequality
          constraints `A @ x <= b`, where `A` is a `n_ineq_con x d`-dim
          Tensor and `b` is a `n_ineq_con x 1`-dim Tensor, with `n_ineq_con`
          the number of inequalities and `d` the dimension of the sample space.
      equality_constraints: Tensors `(C, d)` describing the equality constraints
          `C @ x = d`, where `C` is a `n_eq_con x d`-dim Tensor and `d` is a
          `n_eq_con x 1`-dim Tensor with `n_eq_con` the number of equalities.
      bounds: A `2 x d`-dim tensor of box bounds, where `inf` (`-inf`) means
          that the respective dimension is unbounded from above (below).
      interior_point: A `d x 1`-dim Tensor representing a point in the
          (relative) interior of the polytope. If omitted, determined
          automatically by solving a Linear Program.
  
  Warning: The vertex enumeration performed in this algorithm can become
  extremely costly if there are a large number of inequalities. Similarly,
  the triangulation can get very expensive in high dimensions. Only use
  this algorithm for moderate dimensions / moderately complex constraint sets.
  An alternative is the `HitAndRunPolytopeSampler`.
docstr_tok: ["Initialize","DelaunayPolytopeSampler",".","Args",":","inequality_constraints",":","Tensors","`","(","A",",","b",")","`","describing","inequality","constraints","`","A","@","x","<","=","b","`",",","where","`","A","`","is","a","`","n_ineq_con","x","d","`","-dim","Tensor","and","`","b","`","is","a","`","n_ineq_con","x","1","`","-dim","Tensor",",","with","`","n_ineq_con","`","the","number","of","inequalities","and","`","d","`","the","dimension","of","the","sample","space",".","equality_constraints",":","Tensors","`","(","C",",","d",")","`","describing","the","equality","constraints","`","C","@","x","=","d","`",",","where","`","C","`","is","a","`","n_eq_con","x","d","`","-dim","Tensor","and","`","d","`","is","a","`","n_eq_con","x","1","`","-dim","Tensor","with","`","n_eq_con","`","the","number","of","equalities",".","bounds",":","A","`","2","x","d","`","-dim","tensor","of","box","bounds",",","where","`","inf","`","(","`","-inf","`",")","means","that","the","respective","dimension","is","unbounded","from","above","(","below",")",".","interior_point",":","A","`","d","x","1","`","-dim","Tensor","representing","a","point","in","the","(","relative",")","interior","of","the","polytope",".","If","omitted",",","determined","automatically","by","solving","a","Linear","Program",".","Warning",":","The","vertex","enumeration","performed","in","this","algorithm","can","become","extremely","costly","if","there","are","a","large","number","of","inequalities",".","Similarly",",","the","triangulation","can","get","very","expensive","in","high","dimensions",".","Only","use","this","algorithm","for","moderate","dimensions","\/","moderately","complex","constraint","sets",".","An","alternative","is","the","`","HitAndRunPolytopeSampler","`","."]
code: def __init__(
      self,
      inequality_constraints: Optional[Tuple[Tensor, Tensor]] = None,
      equality_constraints: Optional[Tuple[Tensor, Tensor]] = None,
      bounds: Optional[Tensor] = None,
      interior_point: Optional[Tensor] = None,
  ) -> None:
      r"""Initialize DelaunayPolytopeSampler.
  
      Args:
          inequality_constraints: Tensors `(A, b)` describing inequality
              constraints `A @ x <= b`, where `A` is a `n_ineq_con x d`-dim
              Tensor and `b` is a `n_ineq_con x 1`-dim Tensor, with `n_ineq_con`
              the number of inequalities and `d` the dimension of the sample space.
          equality_constraints: Tensors `(C, d)` describing the equality constraints
              `C @ x = d`, where `C` is a `n_eq_con x d`-dim Tensor and `d` is a
              `n_eq_con x 1`-dim Tensor with `n_eq_con` the number of equalities.
          bounds: A `2 x d`-dim tensor of box bounds, where `inf` (`-inf`) means
              that the respective dimension is unbounded from above (below).
          interior_point: A `d x 1`-dim Tensor representing a point in the
              (relative) interior of the polytope. If omitted, determined
              automatically by solving a Linear Program.
  
      Warning: The vertex enumeration performed in this algorithm can become
      extremely costly if there are a large number of inequalities. Similarly,
      the triangulation can get very expensive in high dimensions. Only use
      this algorithm for moderate dimensions / moderately complex constraint sets.
      An alternative is the `HitAndRunPolytopeSampler`.
      """
      super().__init__(
          inequality_constraints=inequality_constraints,
          equality_constraints=equality_constraints,
          bounds=bounds,
          interior_point=interior_point,
      )
      # shift coordinate system to be anchored at x0
      new_b = self.b - self.A @ self.x0
      if self.new_A.shape[-1] < 2:
          # if the polytope is in dim 1 (i.e. a line segment) Qhull won't work
          tshlds = new_b / self.new_A
          neg = self.new_A < 0
          self.y_min = tshlds[neg].max()
          self.y_max = tshlds[~neg].min()
          self.dim = 1
      else:
          # Qhull expects inputs of the form A @ x + b <= 0, so we need to negate here
          halfspaces = (
              torch.cat([self.new_A, -new_b], dim=-1).cpu().numpy()
          )
          vertices = HalfspaceIntersection(
              halfspaces=halfspaces,
              interior_point=np.zeros(self.new_A.shape[-1]),
          ).intersections
          self.dim = vertices.shape[-1]
          try:
              delaunay = Delaunay(vertices)
          except ValueError as e:
              if "Points cannot contain NaN" in str(e):
                  raise ValueError("Polytope is unbounded.")
              raise e  # pragma: no cover
          polytopes = torch.from_numpy(
              np.array(
                  [delaunay.points[s] for s in delaunay.simplices]
              ),
          ).to(self.A)
          volumes = torch.stack(
              [torch.det(p[1:] - p[0]).abs() for p in polytopes]
          )
          self._polytopes = polytopes
          self._p = volumes / volumes.sum()
  
imports: from __future__ import annotations
  from abc import ABC, abstractmethod
  from contextlib import contextmanager
  from typing import Any, Generator, Iterable, List, Optional, Tuple, TYPE_CHECKING
  import numpy
  import scipy
  import torch
  from botorch.exceptions.errors import BotorchError
  from botorch.sampling.qmc import NormalQMCEngine
  from botorch.utils.transforms import unnormalize
  from scipy.spatial import Delaunay, HalfspaceIntersection
  from torch import LongTensor, Tensor
  from torch.quasirandom import SobolEngine
label_desc: Use image node_id 1 to create a new DelaunayPolytopeSampler object from inherited base classes: PolytopeSampler with example: obj = DelaunayPolytopeSampler(inequality_constraints, equality_constraints, bounds, interior_point)