def _simple_transform_with_constraint(
    sorted_graph: List[Tensor],
    matchFunc: Callable[[Tensor], bool],
    replaceFunc: Callable[[Tensor], Union[Tensor, List[Tensor]]],
) -> List[Tensor]:
    """
    Replace ops in sorted_graph that match constraint provided by matchFunc.
    Op to be replaced is determined by matchFunc, which if true, we call replaceFunc to substitute the tensor away.


    Parameters
    ----------
    sorted_graph : List[Tensor]
        original AIT graph

    matchFunc : Callable(Tensor) -> bool
        A function that returns whether or not the operator needs to be substituted

    replaceFunc  : Callable(Tensor) -> Tensor
        A function that return the resulting tensor that replaces the original one.

    Returns
    ----------
    List[Tensor]
        AIT graph after transformation
    """

    new_sorted_graph = []
    transformed = False
    for tensor in sorted_graph:
        if matchFunc(tensor):
            new_tensors = replaceFunc(tensor)
            if isinstance(new_tensors, Tensor):
                new_sorted_graph.append(new_tensors)
            else:
                new_sorted_graph.extend(new_tensors)

            transformed = True
        else:
            new_sorted_graph.append(tensor)

    if not transformed:
        return sorted_graph
    return sanitize_sorted_graph(new_sorted_graph)
Replace ops in sorted_graph that match constraint provided by matchFunc.
Op to be replaced is determined by matchFunc, which if true, we call replaceFunc to substitute the tensor away.


Parameters
----------
sorted_graph : List[Tensor]
original AIT graph

matchFunc : Callable(Tensor) -> bool
A function that returns whether or not the operator needs to be substituted

replaceFunc  : Callable(Tensor) -> Tensor
A function that return the resulting tensor that replaces the original one.

Returns
----------
List[Tensor]
AIT graph after transformation
python/aitemplate/compiler/transform/transform_special_ops.py