class_docstr: This transform works for each ``const`` op if:
  
  - ``_is_deprecated=True`` and the ``op_selector`` returns ``True``.
  - ``_is_deprecated=False`` and the ``const`` value size ``> weight_threshold``.
  
  The transform performs the following:
  
  - A linear look-up table (LUT) with 2\ :sup:`nbits` entries is created with values represented by indexing into this LUT.
  - If ``fake_compression=False``, compressed value is encoded using the ``constexpr_lut_to_dense`` op.
  - If ``fake_compression=True``,  compressed value is decompressed and then encoded using the ``const`` op.
  - Old ``const`` op is replaced by a newly created operation.
class_docstr_tok: ["This","transform","works","for","each","``","const","``","op","if",":","-","``","_is_deprecated=True","``","and","the","``","op_selector","``","returns","``","True","``",".","-","``","_is_deprecated=False","``","and","the","``","const","``","value","size","``",">","weight_threshold","``",".","The","transform","performs","the","following",":","-","A","linear","look-up","table","(","LUT",")","with","2\\",":","sup",":","`","nbits","`","entries","is","created","with","values","represented","by","indexing","into","this","LUT",".","-","If","``","fake_compression=False","``",",","compressed","value","is","encoded","using","the","``","constexpr_lut_to_dense","``","op",".","-","If","``","fake_compression=True","``",",","compressed","value","is","decompressed","and","then","encoded","using","the","``","const","``","op",".","-","Old","``","const","``","op","is","replaced","by","a","newly","created","operation","."]
docstr: Calculate look-up-table (LUT) and indices.
code: def _get_lut_and_indices(
      val: np.ndarray,
      mode: str,
      nbits: Optional[int],
      lut_function: Optional[Callable],
  ) -> Tuple[np.ndarray, np.ndarray]:
      """Calculate look-up-table (LUT) and indices."""
  
      def compress_kmeans(val, nbits):
          lut, indices = _get_kmeans_lookup_table_and_weight(nbits, val)
          lut = lut.astype(val.dtype)
          indices = indices.astype(np.uint8)
          return lut, indices
  
      def compress_uniform(val, nbits):
          val = val.flatten()
          val_min = np.amin(val)
          val_max = np.amax(val)
          scale = (val_max - val_min) / ((1 << nbits) - 1)
          indices = np.round(
              ((val - val_min) / (val_max - val_min))
              * ((1 << nbits) - 1)
          ).astype(np.uint8)
          lut = np.array(range(0, 1 << nbits)) * scale + val_min
          lut = lut.astype(val.dtype)
          return lut, indices
  
      def compress_unique(val, nbits):
          val = val.flatten()
          unique_vals = np.unique(val).tolist()
          if len(unique_vals) > 1 << nbits:
              msg = "Too many unique values {} in the weight. Couldn't represented in {} bits.".format(
                  len(unique_vals), nbits
              )
              raise ValueError(msg)
          lut = [0] * (1 << nbits)
          lut[: len(unique_vals)] = unique_vals
          indices = np.zeros((len(val),))
          for i, k in enumerate(lut[: len(unique_vals)]):
              indices += (i + 1) * (val == k).astype(np.int32)
          indices = indices - 1
          assert (
              len(np.where(indices == -1)[0]) == 0
          ), "weight must be corresponding to one existing indice"
  
          lut = np.array(lut).astype(val.dtype)
          indices = indices.astype(np.uint8)
          return lut, indices
  
      if mode == "KMEANS":
          lut, indices = compress_kmeans(val, nbits)
      elif mode == "UNIFORM":
          lut, indices = compress_uniform(val, nbits)
      elif mode == "UNIQUE":
          if nbits is None:
              nbits = palettize_weights._get_nbits_for_unique_mode(
                  val, palettize_weights._SUPPORTED_NBITS
              )
          lut, indices = compress_unique(val, nbits)
      else:
          if mode != "CUSTOM":
              raise AssertionError(f"Invalid mode {mode}")
          lut, indices = lut_function(val)
  
      return lut, indices
  
imports: from typing import Callable, Optional, Tuple
  import numpy
  from tqdm import tqdm
  from coremltools import _logger
  from coremltools.converters.mil._deployment_compatibility import AvailableTarget
  from coremltools.converters.mil.backend.mil.load import should_use_weight_file
  from coremltools.converters.mil.mil import Builder
  from coremltools.converters.mil.mil import Operation, Program, types
  from coremltools.converters.mil.mil.block import is_current_opset_version_compatible_with
  from coremltools.converters.mil.mil.ops.defs._utils import pack_elements_into_bits
  from coremltools.converters.mil.mil.ops.defs.iOS16 import constexpr_affine_dequantize, constexpr_lut_to_dense, constexpr_sparse_to_dense
  from coremltools.converters.mil.mil.passes.defs.quantization import AbstractQuantizationPass
  from coremltools.converters.mil.mil.passes.helper import block_context_manager
  from coremltools.converters.mil.mil.passes.pass_registry import register_pass
  from coremltools.converters.mil.mil.types.type_mapping import nptype_from_builtin
  from coremltools.models.neural_network.quantization_utils import _get_kmeans_lookup_table_and_weight
  from coremltools.optimize.coreml._config import OpLinearQuantizerConfig, OpMagnitudePrunerConfig, OpPalettizerConfig, OpThresholdPrunerConfig, OptimizationConfig
label_desc: Use image node_id 3 for calling the palettize_weights obj's underlying member method code with example usage: obj._get_lut_and_indices(val, mode, nbits, lut_function) and returns: lut,  indices, lut,  indices, lut,  indices, lut,  indices