code: def make_scipy_linear_constraints(
      shapeX: torch.Size,
      inequality_constraints: Optional[
          List[Tuple[Tensor, Tensor, float]]
      ] = None,
      equality_constraints: Optional[
          List[Tuple[Tensor, Tensor, float]]
      ] = None,
  ) -> List[ScipyConstraintDict]:
      r"""Generate scipy constraints from torch representation.
  
      Args:
          shapeX: The shape of the torch.Tensor to optimize over (i.e. `(b) x q x d`)
          inequality constraints: A list of tuples (indices, coefficients, rhs),
              with each tuple encoding an inequality constraint of the form
              `\sum_i (X[indices[i]] * coefficients[i]) >= rhs`, where
              `indices` is a single-dimensional index tensor (long dtype) containing
              indices into the last dimension of `X`, `coefficients` is a
              single-dimensional tensor of coefficients of the same length, and
              rhs is a scalar.
          equality constraints: A list of tuples (indices, coefficients, rhs),
              with each tuple encoding an inequality constraint of the form
              `\sum_i (X[indices[i]] * coefficients[i]) == rhs` (with `indices`
              and `coefficients` of the same form as in `inequality_constraints`).
  
      Returns:
          A list of dictionaries containing callables for constraint function
          values and Jacobians and a string indicating the associated constraint
          type ("eq", "ineq"), as expected by `scipy.minimize`.
  
      This function assumes that constraints are the same for each input batch,
      and broadcasts the constraints accordingly to the input batch shape. This
      function does support constraints across elements of a q-batch if the
      indices are a 2-d Tensor.
  
      Example:
          The following will enforce that `x[1] + 0.5 x[3] >= -0.1` for each `x`
          in both elements of the q-batch, and each of the 3 t-batches:
  
          >>> constraints = make_scipy_linear_constraints(
          >>>     torch.Size([3, 2, 4]),
          >>>     [(torch.tensor([1, 3]), torch.tensor([1.0, 0.5]), -0.1)],
          >>> )
  
          The following will enforce that `x[0, 1] + 0.5 x[1, 3] >= -0.1` where
          x[0, :] is the first element of the q-batch and x[1, :] is the second
          element of the q-batch, for each of the 3 t-batches:
  
          >>> constraints = make_scipy_linear_constraints(
          >>>     torch.size([3, 2, 4])
          >>>     [(torch.tensor([[0, 1], [1, 3]), torch.tensor([1.0, 0.5]), -0.1)],
          >>> )
      """
      constraints = []
      if inequality_constraints is not None:
          for indcs, coeffs, rhs in inequality_constraints:
              constraints += _make_linear_constraints(
                  indices=indcs,
                  coefficients=coeffs,
                  rhs=rhs,
                  shapeX=shapeX,
                  eq=False,
              )
      if equality_constraints is not None:
          for indcs, coeffs, rhs in equality_constraints:
              constraints += _make_linear_constraints(
                  indices=indcs,
                  coefficients=coeffs,
                  rhs=rhs,
                  shapeX=shapeX,
                  eq=True,
              )
      return constraints
  
imports: from __future__ import annotations
  from functools import partial
  from typing import Callable, Dict, List, Optional, Tuple, Union
  import numpy
  import torch
  from botorch.exceptions.errors import CandidateGenerationError, UnsupportedError
  from scipy.optimize import Bounds
  from torch import Tensor
label_desc: Use image node_id 2 for calling a global function with example usage: make_scipy_linear_constraints(shapeX, inequality_constraints, equality_constraints) and returns: constraints