def test_keep_unidentical_dequantize_quantize(
        self, is_zp_present, is_axis_present, is_shifted_zp_present
    ):
        """
        Input graph:
            input -> quantize0 -> dequantize1(scale1, zp1) -> quantize1(scale2, zp2) -> dequantize2 -> add -> quantize2 -> dequantize3 -> output

        Nothing changes when dequantize1 and quantize1 have different parameters
        """

        SHAPE = (2, 3, 5)
        scale, zero_point, axis = self.generate_scale_zp_axis(SHAPE, is_zp_present, is_axis_present)

        @mb.program(input_specs=[mb.TensorSpec(shape=SHAPE, dtype=types.fp32)])
        def prog(x):
            # quantize input
            quantized_0 = mb.quantize(
                input=x, scale=scale, zero_point=zero_point, axis=axis, output_dtype="int8"
            )
            # non-redundant dequantize-quantize pair
            # this pattern can emerge from a (future) graph pass
            dequantized_1 = mb.dequantize(
                input=quantized_0, scale=scale, zero_point=zero_point, axis=axis
            )
            if is_zp_present:
                # input graph:
                #     dequantize -> add(y=const) -> quantize
                # output graph:
                #     dequantize -> quantize(zero_point += const / scale)
                if is_shifted_zp_present:
                    shifted_zero_point = (
                        (zero_point + 1.0).astype(np.int8)
                        if is_axis_present
                        else np.int8(zero_point + 1.0)
                    )
                    quantized_1 = mb.quantize(
                        input=dequantized_1,
                        scale=scale,
                        zero_point=shifted_zero_point,
                        axis=axis,
                        output_dtype="int8",
                    )
                else:
                    quantized_1 = mb.quantize(
                        input=dequantized_1, scale=scale, axis=axis, output_dtype="int8"
                    )
            else:
                # input graph:
                #     dequantize(zero_point=0) -> mul(y=const) -> quantize(zero_point=0)
                # output graph:
                #     dequantize(zero_point=0) -> quantize(scale /= const, zero_point=0)
                quantized_1 = mb.quantize(
                    input=dequantized_1, scale=scale / 2.0, axis=axis, output_dtype="int8"
                )
            # dequantize-op-quantize sandwich
            dequantized_2 = mb.dequantize(
                input=quantized_1, scale=scale, zero_point=zero_point, axis=axis
            )
            y = mb.add(x=dequantized_2, y=dequantized_2)
            quantized_2 = mb.quantize(input=y, scale=0.1, output_dtype="int8")
            # dequantize output
            dequantized_3 = mb.dequantize(input=quantized_2, scale=0.1)
            return dequantized_3

        prev_prog, _, _ = apply_pass_and_basic_check(
            prog, "common::dequantize_quantize_pair_elimination"
        )
        assert get_op_types_in_program(prev_prog) == [
            "quantize",
            "dequantize",
            "quantize",
            "dequantize",
            "add",
            "quantize",
            "dequantize",
        ]
        # nothing gets eliminated
        assert get_op_types_in_program(prog) == [
            "quantize",
            "dequantize",
            "quantize",
            "dequantize",
            "add",
            "quantize",
            "dequantize",
        ]

        Input graph:
            input -> quantize0 -> dequantize1(scale1, zp1) -> quantize1(scale2, zp2) -> dequantize2 -> add -> quantize2 -> dequantize3 -> output

        Nothing changes when dequantize1 and quantize1 have different parameters
        
coremltools/converters/mil/mil/passes/tests/test_quantization_passes.py