class_docstr: Base class for samplers that sample points from a polytope.
  
  :meta private:
class_docstr_tok: ["Base","class","for","samplers","that","sample","points","from","a","polytope",".",":","meta","private",":"]
docstr: 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 above (below).
      interior_point: A `d x 1`-dim Tensor presenting a point in the
          (relative) interior of the polytope. If omitted, determined
          automatically by solving a Linear Program.
docstr_tok: ["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","above","(","below",")",".","interior_point",":","A","`","d","x","1","`","-dim","Tensor","presenting","a","point","in","the","(","relative",")","interior","of","the","polytope",".","If","omitted",",","determined","automatically","by","solving","a","Linear","Program","."]
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"""
      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 above (below).
          interior_point: A `d x 1`-dim Tensor presenting a point in the
              (relative) interior of the polytope. If omitted, determined
              automatically by solving a Linear Program.
      """
      if inequality_constraints is None:
          if bounds is None:
              raise BotorchError(
                  "PolytopeSampler requires either inequality constraints or bounds."
              )
          A = torch.empty(
              0,
              bounds.shape[-1],
              dtype=bounds.dtype,
              device=bounds.device,
          )
          b = torch.empty(
              0, 1, dtype=bounds.dtype, device=bounds.device
          )
      else:
          A, b = inequality_constraints
      if bounds is not None:
          # add inequality constraints for bounds
          # TODO: make sure there are not deduplicate constraints
          A2, b2 = _convert_bounds_to_inequality_constraints(
              bounds=bounds
          )
          A = torch.cat([A, A2], dim=0)
          b = torch.cat([b, b2], dim=0)
      self.A = A
      self.b = b
      self.equality_constraints = equality_constraints
  
      if equality_constraints is not None:
          self.C, self.d = equality_constraints
          U, S, Vh = torch.linalg.svd(self.C)
          r = torch.nonzero(S).size(0)  # rank of matrix C
          self.nullC = Vh[r:, :].transpose(
              -1, -2
          )  # orthonormal null space of C,
          # satisfying # C @ nullC = 0 and nullC.T @ nullC = I
          # using the change of variables x=x0+nullC*y,
          # sample y satisfies A*nullC*y<=b-A*x0.
          # the linear constraint is automatically satisfied as x0 satisfies it.
      else:
          self.C = None
          self.d = None
          self.nullC = torch.eye(
              self.A.size(-1), dtype=self.A.dtype, device=self.A.device
          )
  
      self.new_A = (
          self.A @ self.nullC
      )  # doesn't depend on the initial point
  
      # initial point for the original, not transformed, problem
      if interior_point is not None:
          if self.feasible(interior_point):
              self.x0 = interior_point
          else:
              raise ValueError("The given input point is not feasible.")
      else:
          self.x0 = self.find_interior_point()
  
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 PolytopeSampler object from inherited base classes: ABC with example: obj = PolytopeSampler(inequality_constraints, equality_constraints, bounds, interior_point)