code: def cast_to(x, to, saturate):  # noqa: PLR0911
      if x.dtype == bfloat16 and x.dtype.descr[0][0] == "bfloat16":
          if to == TensorProto.BFLOAT16:
              return x
          xr = x.ravel()
          xf = np.empty(xr.shape[0], dtype=np.float32)
          for i in range(xr.shape[0]):
              el = bfloat16_to_float32(xr[i])
              xf[i] = el
          dtype = tensor_dtype_to_np_dtype(to)
          return xf.astype(dtype).reshape(x.shape)
  
      f8 = {
          (
              float8e4m3fn,
              "e4m3fn",
              TensorProto.FLOAT8E4M3FN,
          ): float8e4m3_to_float32,
          (
              float8e4m3fnuz,
              "e4m3fnuz",
              TensorProto.FLOAT8E4M3FNUZ,
          ): lambda *args: float8e4m3_to_float32(*args, uz=True),
          (
              float8e5m2,
              "e5m2",
              TensorProto.FLOAT8E5M2,
          ): float8e5m2_to_float32,
          (
              float8e5m2fnuz,
              "e5m2fnuz",
              TensorProto.FLOAT8E5M2FNUZ,
          ): lambda *args: float8e5m2_to_float32(
              *args, fn=True, uz=True
          ),
      }
  
      for (dt, st, proto_type), cvt in f8.items():
          if x.dtype == dt and x.dtype.descr[0][0] == st:
              if to == proto_type:
                  return x
              xr = x.ravel()
              xf = np.empty(xr.shape[0], dtype=np.float32)
              for i in range(xr.shape[0]):
                  el = cvt(xr[i])
                  xf[i] = el
              dtype = tensor_dtype_to_np_dtype(to)
              return xf.astype(dtype).reshape(x.shape)
  
      if to == TensorProto.BFLOAT16:
          xf = x.astype(np.float32).ravel()
          y = np.empty(xf.shape, dtype=bfloat16).ravel()
          for i in range(y.shape[0]):
              el = float32_to_bfloat16(xf[i], truncate=True)  # type: ignore[assignment]
              y[i] = el
          return y.reshape(x.shape)
  
      i4 = [
          (uint4, "uint4", TensorProto.UINT4, False),
          (int4, "int4", TensorProto.INT4, True),
      ]
      for np_type, np_desc, tensor_type, signed in i4:
          if x.dtype == np_type and x.dtype.descr[0][0] == np_desc:
              if to == tensor_type:
                  return x
              to_type = tensor_dtype_to_np_dtype(to)
              return x.astype(to_type)
  
          if to == tensor_type:
              xf = x.astype(np.float32).ravel()
              y = np.empty(xf.shape, dtype=np_type).ravel()
              for i in range(y.shape[0]):
                  el = subbyte.float32_to_4bit_unpacked(
                      xf[i], signed=signed
                  )
                  y[i] = el
              return y.reshape(x.shape)
  
      f8back = {
          TensorProto.FLOAT8E4M3FN: (
              float8e4m3fn,
              lambda *args: float32_to_float8e4m3(
                  *args, saturate=saturate
              ),
          ),
          TensorProto.FLOAT8E4M3FNUZ: (
              float8e4m3fnuz,
              lambda *args: float32_to_float8e4m3(
                  *args, uz=True, saturate=saturate
              ),
          ),
          TensorProto.FLOAT8E5M2: (
              float8e5m2,
              lambda *args: float32_to_float8e5m2(
                  *args, saturate=saturate
              ),
          ),
          TensorProto.FLOAT8E5M2FNUZ: (
              float8e5m2fnuz,
              lambda *args: float32_to_float8e5m2(
                  *args, fn=True, uz=True, saturate=saturate
              ),
          ),
      }
      for dt, (npdt, cvt) in f8back.items():
          if to == dt:
              xf = x.astype(np.float32).ravel()
              y = np.empty(xf.shape, dtype=npdt).ravel()
              for i in range(y.shape[0]):
                  el = cvt(xf[i])  # type: ignore[assignment]
                  y[i] = el
              return y.reshape(x.shape)
  
      if to == TensorProto.STRING:
          return x.astype(np.str_)
  
      dtype = tensor_dtype_to_np_dtype(to)
      return x.astype(dtype)
  
file_path: onnx/onnx/reference/ops/op_cast.py
imports: import numpy
  from onnx import subbyte
  from onnx.helper import float32_to_bfloat16, float32_to_float8e4m3, float32_to_float8e5m2, tensor_dtype_to_np_dtype
  from onnx.numpy_helper import bfloat16_to_float32, float8e4m3_to_float32, float8e5m2_to_float32
  from onnx.onnx_pb import TensorProto
  from onnx.reference.custom_element_types import bfloat16, float8e4m3fn, float8e4m3fnuz, float8e5m2, float8e5m2fnuz, int4, uint4
  from onnx.reference.op_run import OpRun
label_desc: Use image node_id 1 for calling a global function with example usage: cast_to(x, to, saturate) and returns: x, xf, y, x, x, xf, x, y, y, x, x