def test_dequant_first(self, input_shape, dequant_first):
        """
        When dequant_first is True, the quantized lut ops representation will be reordered to follow
            lut(int8) -> constexpr_blockwise_shift_scale -> lut(fp16) -> constexpr_lut_to_dense -> dense(fp16).
        When dequant_first is False, the quantized lut ops representation will be reordered to follow
            lut(int8) -> constexpr_lut_to_dense -> dense(int8) -> constexpr_blockwise_shift_scale -> dense(fp16)
        """

        @mb.program(
            input_specs=[mb.TensorSpec(shape=input_shape, dtype=types.fp16)],
            opset_version=ct.target.iOS18,
        )
        def prog(x):
            quantized_lut_weight1, quantized_lut_weight2 = self._construct_weights_with_two_orders(
                weight_shape=(8, input_shape[-1])
            )
            output1 = mb.linear(x=x, weight=quantized_lut_weight1)
            output2 = mb.linear(x=x, weight=quantized_lut_weight2)
            return mb.add(x=output1, y=output2)

        from unittest import mock

        from coremltools.converters.mil.mil.passes.defs.optimize_quantization import (
            canonicalize_quantized_lut_pattern,
        )

        with mock.patch.object(canonicalize_quantized_lut_pattern, "_DEQUANT_FIRST", dequant_first):
            prev_prog, _, block = apply_pass_and_basic_check(
                prog, "common::canonicalize_quantized_lut_pattern", skip_essential_scope_check=True
            )

        assert get_op_types_in_program(prev_prog) == [
            "constexpr_lut_to_dense",
            "constexpr_blockwise_shift_scale",
            "constexpr_blockwise_shift_scale",
            "constexpr_lut_to_dense",
            "linear",
            "linear",
            "add",
        ]
        dequant_ops = prog.functions["main"].find_ops(op_type="constexpr_blockwise_shift_scale")
        lut_ops = prog.functions["main"].find_ops(op_type="constexpr_lut_to_dense")
        assert len(dequant_ops) == 2
        assert len(lut_ops) == 2
        if dequant_first:
            for dequant_op in dequant_ops:
                assert dequant_op.outputs[0].child_ops[0].op_type == "constexpr_lut_to_dense"
            for lut_op in lut_ops:
                assert lut_op.outputs[0].child_ops[0].op_type == "linear"
        else:
            for lut_op in lut_ops:
                assert lut_op.outputs[0].child_ops[0].op_type == "constexpr_blockwise_shift_scale"
            for dequant_op in dequant_ops:
                assert dequant_op.outputs[0].child_ops[0].op_type == "linear"

        self._verify_numerical(prev_prog, prog, block, input_shape)

        When dequant_first is True, the quantized lut ops representation will be reordered to follow
            lut(int8) -> constexpr_blockwise_shift_scale -> lut(fp16) -> constexpr_lut_to_dense -> dense(fp16).
        When dequant_first is False, the quantized lut ops representation will be reordered to follow
            lut(int8) -> constexpr_lut_to_dense -> dense(int8) -> constexpr_blockwise_shift_scale -> dense(fp16)
        
coremltools/converters/mil/mil/passes/tests/test_quantization_passes.py