def _try_match_and_transform_pattern_1(self, reduce_op, block) -> bool:
        """
        Identify the pattern:

        ``y = gamma * (x - mean) / sqrt(variance + epsilon) + beta``

        ``y = x * [gamma * rsqrt(variance + eps)] + (beta - mean * [gamma * rsqrt(variance + eps)])``

        .. code-block::

            x --> reduce_mean --> sub --> square --> reduce_mean --> add(epsilon) --> rsqrt
            |             |        ^                                                    |
            |             |        |                                                    V
            |-----------------------                                              mul (gamma)
            |             |                                                           |
            |             |                                                   --------|---------
            |             |                                                   |                |
            |             |                                                   |                V
            |             |---------------------------------------------------------------->  mul
            |                                                                 |                |
            |                                                                 V                |
            |--------------------------------------------------------------> mul               |
                                                                              |                V
                                                                              |              sub (beta) --> add --> [...]
                                                                              |                              ^
                                                                              |-------------------------------

        This pattern corresponds to either ``layer_norm`` or ``instance_norm``.

        It is ``instance_norm`` if all of the following are true:
            - ``input`` is rank 4.
            - ``axes`` of ``reduce_mean`` is ``[-2, -1]`` or ``[-3, -2]``
              (when ``[-3, -2]``, a channel first to channel last transpose would be inserted).
            - ``gamma`` and ``beta`` are rank 1, after ``squeeze``.

        It is ``layer_norm`` if all of the following are true:
            - ``axes`` is either ``[-1]``, ``[-1, -2]``, or ``[-1, -2, -3]``, and so on.
            - ``rank`` of ``gamma`` and ``beta`` is equal to the length of the ``axes``.

        """
        ops_to_remove = []
        root_var = reduce_op.x

        if root_var.shape is None:
            return False

        # check that root_var feeds into exactly 3 ops
        if len(list(root_var.child_ops)) != 3:
            return False
        if root_var.op is not None and not self._check_child_op_types(
            root_var.op, child_op_types=["reduce_mean", "sub", "mul"]
        ):
            return False

        # check 1st reduce_mean op
        if not self._check_reduce_op(reduce_op):
            return False
        ops_to_remove.append(reduce_op)

        # check 1st sub op
        if not self._check_child_op_types(reduce_op, ["sub", "mul"], check_order=False):
            return False
        child_ops_reduce_mean = list(reduce_op.outputs[0].child_ops)
        op_a = child_ops_reduce_mean[0]
        op_b = child_ops_reduce_mean[1]
        sub_op1 = op_a if op_a.op_type == "sub" else op_b
        if not (sub_op1.x == root_var and sub_op1.y == reduce_op.outputs[0]):
            return False
        ops_to_remove.append(sub_op1)

        # check square op
        square_op = self._try_get_child_op_type(sub_op1, "square")
        if square_op is None:
            return False
        ops_to_remove.append(square_op)

        # check second reduce mean
        reduce_op2 = self._try_get_child_op_type(square_op, "reduce_mean")
        if not self._check_reduce_op(reduce_op2):
            return False
        ops_to_remove.append(reduce_op2)

        # check add op (with epsilon)
        add_op1 = self._try_get_child_op_type(reduce_op2, "add")
        if add_op1 is None:
            return False
        epsilon_var = add_op1.y if add_op1.x == reduce_op2.outputs[0] else add_op1.x
        if epsilon_var.val is None or len(epsilon_var.val.shape) != 0:
            return False  # must be scalar
        ops_to_remove.append(add_op1)

        # check rsqrt
        rsqrt_op = self._try_get_child_op_type(add_op1, "rsqrt")
        if rsqrt_op is None:
            return False
        ops_to_remove.append(rsqrt_op)

        # check mul (gamma)
        mul_op1 = self._try_get_child_op_type(rsqrt_op, "mul")
        if mul_op1 is None:
            return False
        gamma_var = mul_op1.y if mul_op1.x == rsqrt_op.outputs[0] else mul_op1.x
        if gamma_var.val is None:
            return False
        ops_to_remove.append(mul_op1)

        # check 2 muls after the gamma mul
        if not self._check_child_op_types(mul_op1, ["mul", "mul"]):
            return False
        child_ops = list(mul_op1.outputs[0].child_ops)
        mul_op2 = child_ops[0]
        mul_op3 = child_ops[1]
        mul_op2_other_var = mul_op2.x if mul_op2.y == mul_op1.outputs[0] else mul_op2.y
        mul_op3_other_var = mul_op3.x if mul_op3.y == mul_op1.outputs[0] else mul_op3.y
        if not (
            (mul_op2_other_var == root_var and mul_op3_other_var == reduce_op.outputs[0])
            or (mul_op2_other_var == reduce_op.outputs[0] and mul_op3_other_var == root_var)
        ):
            return False
        if mul_op2_other_var == root_var:
            mul_root_op = mul_op2
            mul_mean_op = mul_op3
        else:
            mul_root_op = mul_op3
            mul_mean_op = mul_op2
        ops_to_remove.append(mul_mean_op)
        ops_to_remove.append(mul_root_op)

        # check sub with beta
        sub_op2 = self._try_get_child_op_type(mul_mean_op, "sub")
        if sub_op2 is None:
            return False
        if sub_op2.y != mul_mean_op.outputs[0]:
            return False
        beta_var = sub_op2.x
        if beta_var.val is None:
            return False
        ops_to_remove.append(sub_op2)

        # check last add op
        add_op2 = self._try_get_child_op_type(sub_op2, "add")
        if add_op2 is None:
            return False
        if not (add_op2.x == mul_root_op.outputs[0] or add_op2.y == mul_root_op.outputs[0]):
            return False
        ops_to_remove.append(add_op2)

        return self._try_apply_transform(
            reduce_op, block, gamma_var, beta_var, epsilon_var, add_op2, ops_to_remove
        )

        Identify the pattern:

        ``y = gamma * (x - mean) / sqrt(variance + epsilon) + beta``

        ``y = x * [gamma * rsqrt(variance + eps)] + (beta - mean * [gamma * rsqrt(variance + eps)])``

        .. code-block::

            x --> reduce_mean --> sub --> square --> reduce_mean --> add(epsilon) --> rsqrt
            |             |        ^                                                    |
            |             |        |                                                    V
            |-----------------------                                              mul (gamma)
            |             |                                                           |
            |             |                                                   --------|---------
            |             |                                                   |                |
            |             |                                                   |                V
            |             |---------------------------------------------------------------->  mul
            |                                                                 |                |
            |                                                                 V                |
            |--------------------------------------------------------------> mul               |
                                                                              |                V
                                                                              |              sub (beta) --> add --> [...]
                                                                              |                              ^
                                                                              |-------------------------------

        This pattern corresponds to either ``layer_norm`` or ``instance_norm``.

        It is ``instance_norm`` if all of the following are true:
            - ``input`` is rank 4.
            - ``axes`` of ``reduce_mean`` is ``[-2, -1]`` or ``[-3, -2]``
              (when ``[-3, -2]``, a channel first to channel last transpose would be inserted).
            - ``gamma`` and ``beta`` are rank 1, after ``squeeze``.

        It is ``layer_norm`` if all of the following are true:
            - ``axes`` is either ``[-1]``, ``[-1, -2]``, or ``[-1, -2, -3]``, and so on.
            - ``rank`` of ``gamma`` and ``beta`` is equal to the length of the ``axes``.

        
coremltools/converters/mil/mil/passes/defs/optimize_normalization.py