code: def columnwise_clamp(
      X: Tensor,
      lower: Optional[Union[float, Tensor]] = None,
      upper: Optional[Union[float, Tensor]] = None,
      raise_on_violation: bool = False,
  ) -> Tensor:
      r"""Clamp values of a Tensor in column-wise fashion (with support for t-batches).
  
      This function is useful in conjunction with optimizers from the torch.optim
      package, which don't natively handle constraints. If you apply this after
      a gradient step you can be fancy and call it "projected gradient descent".
      This funtion is also useful for post-processing candidates generated by the
      scipy optimizer that satisfy bounds only up to numerical accuracy.
  
      Args:
          X: The `b x n x d` input tensor. If 2-dimensional, `b` is assumed to be 1.
          lower: The column-wise lower bounds. If scalar, apply bound to all columns.
          upper: The column-wise upper bounds. If scalar, apply bound to all columns.
          raise_on_violation: If `True`, raise an exception when the elments in `X`
              are out of the specified bounds (up to numerical accuracy). This is
              useful for post-processing candidates generated by optimizers that
              satisfy imposed bounds only up to numerical accuracy.
  
      Returns:
          The clamped tensor.
      """
      if lower is None and upper is None:
          return X
  
      if lower is not None:
          lower = torch.as_tensor(lower).expand_as(X).to(X)
  
      if upper is not None:
          upper = torch.as_tensor(upper).expand_as(X).to(X)
          if lower is not None and (lower > upper).any():
              raise ValueError(
                  "Lower bounds cannot exceed upper bounds."
              )
  
      out = X.clamp(lower, upper)
      if raise_on_violation and not X.allclose(out):
          raise BotorchError("Original value(s) are out of bounds.")
  
      return out
  
file_path: botorch/botorch/optim/utils/acquisition_utils.py
imports: from __future__ import annotations
  from typing import Dict, Optional, Union
  from warnings import warn
  import torch
  from botorch.acquisition.acquisition import AcquisitionFunction
  from botorch.exceptions.errors import BotorchError
  from botorch.exceptions.warnings import BotorchWarning
  from botorch.models.gpytorch import ModelListGPyTorchModel
  from torch import Tensor
label_desc: Use image node_id 1 for calling a global function with example usage: columnwise_clamp(X, lower, upper, raise_on_violation) and returns: out, X