def test_multiple_passes(self):
        """
        In this case, a program goes through two graph passes.
        And the resulting program should have scope information from both passes.
        """
        shape = (3, 5, 6, 7)

        @mb.program(input_specs=[mb.TensorSpec(shape=shape)])
        def prog(x):
            with mb.scope(
                ScopeInfo(source=ScopeSource.TORCHSCRIPT_MODULE_TYPE, data="module_1"),
            ):
                # dummy op
                x = mb.relu(x=x)

                # pattern for "merge_consecutive_transposes"
                x = mb.transpose(x=x, perm=[0, 2, 1, 3])

            with mb.scope(
                ScopeInfo(source=ScopeSource.TORCHSCRIPT_MODULE_TYPE, data="module_2"),
            ):
                x = mb.transpose(x=x, perm=[3, 2, 0, 1])

                # pattern for "fuse_layernorm_or_instancenorm"
                mean0 = mb.reduce_mean(x=x, axes=[2, 3], keep_dims=True)
                sub0 = mb.sub(x=x, y=mean0)
                sub1 = mb.sub(x=x, y=mean0)
                square = mb.square(x=sub0)
                mean1 = mb.reduce_mean(x=square, axes=[2, 3], keep_dims=True)
                add_eps = mb.add(x=mean1, y=1e-5)  # epsilon
                pow = mb.pow(x=add_eps, y=0.5)
                div = mb.real_div(x=sub1, y=pow)

            with mb.scope(
                ScopeInfo(source=ScopeSource.TORCHSCRIPT_MODULE_TYPE, data="module_3"),
            ):
                mul_gamma = mb.mul(x=np.random.rand(1, shape[1], 1, 1), y=div)
                return mb.add(x=np.random.rand(1, shape[1], 1, 1), y=mul_gamma)

        prog._add_essential_scope_source(ScopeSource.TORCHSCRIPT_MODULE_TYPE)

        apply_pass_and_basic_check(prog, "common::fuse_layernorm_or_instancenorm")
        apply_pass_and_basic_check(prog, "common::merge_consecutive_transposes")
        assert get_op_types_in_program(prog) == ["relu", "transpose", "instance_norm"]

        # the scope info in the relu op is not affected
        relu_op = prog.find_ops(op_type="relu")[0]
        assert len(relu_op.scopes) == 1
        assert relu_op.scopes[ScopeSource.TORCHSCRIPT_MODULE_TYPE] == ["module_1"]

        # the new transpose op has the scope information from the graph pass
        transpose_op = prog.find_ops(op_type="transpose")[0]
        assert len(transpose_op.scopes) == 2
        assert transpose_op.scopes[ScopeSource.COREMLTOOLS_GRAPH_PASS] == [
            "merge_consecutive_transposes"
        ]
        assert transpose_op.scopes[ScopeSource.TORCHSCRIPT_MODULE_TYPE] == ["module_2"]

        # the new instance_norm op has the scope information from the graph pass
        instance_norm_op = prog.find_ops(op_type="instance_norm")[0]
        assert len(instance_norm_op.scopes) == 2
        assert instance_norm_op.scopes[ScopeSource.COREMLTOOLS_GRAPH_PASS] == [
            "fuse_layernorm_or_instancenorm"
        ]
        assert instance_norm_op.scopes[ScopeSource.TORCHSCRIPT_MODULE_TYPE] == ["module_3"]

        In this case, a program goes through two graph passes.
        And the resulting program should have scope information from both passes.
        
coremltools/converters/mil/mil/passes/tests/test_passes.py