def _get_nbits_for_unique_mode(
        val: np.ndarray,
        allowed_nbits: Tuple[int, ...],
        cluster_dim: int = 1,
        vector_axis: Optional[int] = None,
    ) -> int:
        """
        Try each nbit in allowed_nbits to find one that can represent number of unique values in val.

        If cluster_dim > 1, it's for vector palettization, where the unique means vector unique.
        The vector_axis is only effective for vector palettization, which indicates on which axis
        the vector is.

        Note that the values in `allowed_nbits` need to be in ascending order.
        """
        if cluster_dim == 1:
            val = val.flatten()
            unique_vals_num = len(np.unique(val))
        else:
            # Vector palettization where each cluster_dim elements form a vector on vector_axis.
            if vector_axis is None:
                raise ValueError("The `vector_axis` must be specified when cluster_dim > 1")
            val = np.swapaxes(val, -1, vector_axis).reshape((-1, cluster_dim))
            unique_vals_num = len(np.unique(val, axis=0))

        for nbits in allowed_nbits:
            if unique_vals_num <= 1 << nbits:
                return nbits
        raise ValueError(
            f"Unique values in weight cannot be represented by {allowed_nbits[-1]} "
            "bits palettization."
        )

        Try each nbit in allowed_nbits to find one that can represent number of unique values in val.

        If cluster_dim > 1, it's for vector palettization, where the unique means vector unique.
        The vector_axis is only effective for vector palettization, which indicates on which axis
        the vector is.

        Note that the values in `allowed_nbits` need to be in ascending order.
        
coremltools/optimize/coreml/_quantization_passes.py