code: def restore_elements_from_packed_bits(
      packed_values: np.ndarray,
      nbits: int,
      element_num: int,
      are_packed_values_signed: bool = False,
  ) -> np.ndarray:
      """
      Restore elements from packed bits. Requires values that are packed by starting with the
      least significant bit (LSB) and moving upward to the most significant bit (MSB), which is the
      method used in `pack_elements_into_bits`.
  
      are_packed_values_signed: Indicates if the packed_values were packed from signed integers. If
          True, the n-bit number unpacked from packed_values will be interpreted as signed integers,
          and the returned ndarray will have dtype np.int8. Otherwise, np.uint8 will be used.
      """
      if len(packed_values.shape) != 1:
          raise NotImplementedError(
              f"Only support 1-rank packed_values. But got {len(packed_values.shape)}"
          )
  
      if packed_values.dtype == np.int8:
          # As np.unpackbits only supports uint8, need to convert first.
          packed_values = packed_values.astype(np.uint8)
      elif packed_values.dtype != np.uint8:
          raise NotImplementedError(
              f"Only support int8 or uint8 packed_values, but got {packed_values.dtype}"
          )
  
      bitarray = np.unpackbits(packed_values, bitorder="little")
      pad_required = bitarray.size % nbits != 0
      if pad_required:
          bitarray = np.concatenate(
              [bitarray, np.zeros(nbits - bitarray.size % nbits)]
          ).astype(bitarray.dtype)
          if bitarray.size % nbits != 0:
              raise ValueError(
                  f"The length of bitarray ({bitarray.size}) should be divisible by "
                  f"nbits ({nbits})."
              )
      bitarray = bitarray.reshape(-1, nbits)[:element_num, :]
      # The np.packbits doesn't work well for signed int if we feed `bitarray` to it directly.
      # For example, the original signed int is -6, which is packed as 1010 for 4-bit representation,
      # and here `bitarray` is [[0, 1, 0, 1]], where the value will be interpreted as 10 (b'1010')
      # by np.packbits.
      # To make np.packbits work correctly, we need to repeat the sign bit. For example, 1010 will
      # become 11111010, where np.packbits can correctly handle and after converting to int8 it's -6.
      if are_packed_values_signed:
          # Repeat the sign bit to make uint8 to int8 works.
          bitarray = np.repeat(
              bitarray, [1] * (nbits - 1) + [8 - nbits + 1], axis=1
          )
      restored_elements = np.packbits(
          bitarray, bitorder="little", axis=-1
      ).reshape(-1)
      if are_packed_values_signed:
          restored_elements = restored_elements.astype(np.int8)
      return restored_elements
  
imports: import math
  import numbers
  from typing import List, Tuple
  import numpy
  from coremltools.converters.mil.mil import Builder
  from coremltools.converters.mil.mil import Var, get_new_symbol, types
  from coremltools.converters.mil.mil.ops.defs.iOS15.elementwise_unary import cast
  from coremltools.converters.mil.mil.types import builtin_to_string, promote_dtypes
  from coremltools.converters.mil.mil.types.symbolic import is_symbolic
label_desc: Use image node_id 15 for calling a global function with example usage: restore_elements_from_packed_bits(packed_values, nbits, element_num, are_packed_values_signed) and returns: restored_elements