def test_linear_quantizer_compression_blockwise(
        self,
        nbits,
        signed,
        block_size,
        mode,
        source_dtype,
        data_range,
    ):
        """
        This test mainly follows the weights pattern in real life's ML models. However, when compressing
        weights to a small number of bits (such as 4-bit), the information loss is critical, which
        makes the numerical test hard. That's why we adjust the atol and rtol based on nbits and
        block_size values.
        For more comprehensive numerical tests, see `test_linear_quantizer_compression_blockwise_integer`.
        """
        original_data = np.random.uniform(data_range[0], data_range[1], (32, 64)).astype(
            source_dtype
        )

        compressed_params = quantization.linear_quantize_weights.blockwise_compress(
            original_data, nbits, mode, signed, block_sizes=[1, block_size]
        )
        decompressed_val = quantization.linear_quantize_weights.decompress(compressed_params)

        if nbits > 4 and block_size < 3:
            # When block size is small and nbits is large, the information loss is limited.
            atol, rtol = 1e-02, 1e-02
        elif nbits <= 2 and block_size >= 2:
            atol, rtol = 0.5, 0.5
        else:
            atol, rtol = 0.2, 0.2
        np.testing.assert_allclose(original_data, decompressed_val, rtol=rtol, atol=atol)

        This test mainly follows the weights pattern in real life's ML models. However, when compressing
        weights to a small number of bits (such as 4-bit), the information loss is critical, which
        makes the numerical test hard. That's why we adjust the atol and rtol based on nbits and
        block_size values.
        For more comprehensive numerical tests, see `test_linear_quantizer_compression_blockwise_integer`.
        
coremltools/test/optimize/coreml/test_passes.py