code: def to_movement_ops(
      st: ShapeTracker,
  ) -> List[Tuple[MovementOps, Tuple]]:
      to_apply: List[Tuple[MovementOps, Tuple]] = []
      for i, v in enumerate(st.views):
          real_shape = (
              tuple(y - x for x, y in v.mask) if v.mask else v.shape
          )
          offset = v.offset + sum(
              st * (s - 1)
              for s, st in zip(real_shape, v.strides)
              if st < 0
          )
          real_offset = offset + (
              sum(x * st for (x, _), st in zip(v.mask, v.strides))
              if v.mask
              else 0
          )
          real_real_shape = [
              s for s, st in zip(real_shape, v.strides) if st
          ]
          strides: List[Node | int] = [
              abs(st) if isinstance(st, int) else st
              for st in v.strides
              if st
          ]
          buffer_size = (
              sum(
                  (s - 1) * st
                  for s, st in zip(real_real_shape, strides)
              )
              + 1
          )
          if i:
              buffer_size = prod(st.views[i - 1].shape) - real_offset
  
          def sort_by_strides(shape, strides):
              return sorted(
                  zip(shape, strides),
                  key=lambda k: (k[1], -k[0]),
                  reverse=True,
              ), sorted(
                  range(len(strides)),
                  key=lambda k: (strides[k], -real_real_shape[k]),
                  reverse=True,
              )
  
          ordered_shape_strides, order = sort_by_strides(
              real_real_shape, strides
          )
          to_apply.extend(
              [
                  (MovementOps.RESHAPE, (-1,)),
                  (
                      MovementOps.SHRINK,
                      ((real_offset, real_offset + buffer_size),),
                  ),
              ]
          )
          if strides:
              if (
                  ordered_shape_strides[0][0]
                  * ordered_shape_strides[0][1]
              ) - buffer_size > 0:
                  to_apply.append(
                      (
                          MovementOps.PAD,
                          (
                              (
                                  0,
                                  (
                                      ordered_shape_strides[0][0]
                                      * ordered_shape_strides[0][1]
                                  )
                                  - buffer_size,
                              ),
                          ),
                      )
                  )
              for i, shape_stride in enumerate(ordered_shape_strides):
                  if (
                      i < len(ordered_shape_strides) - 1
                      and shape_stride[1]
                      < ordered_shape_strides[i + 1][0]
                      * ordered_shape_strides[i + 1][1]
                  ):
                      remaining_buffer = (
                          ordered_shape_strides[i - 1][1]
                          if i > 0
                          else buffer_size
                      )
                      to_apply.append(
                          (
                              MovementOps.EXPAND,
                              (
                                  shape_stride[0],
                                  *(
                                      s[0]
                                      for s in ordered_shape_strides[:i]
                                  ),
                                  remaining_buffer,
                              ),
                          )
                      )
                      to_apply.append(
                          (
                              MovementOps.PERMUTE,
                              (*range(1, i + 1), 0, i + 1),
                          )
                      )
                      to_apply.append(
                          (
                              MovementOps.RESHAPE,
                              (
                                  *(
                                      s[0]
                                      for s in ordered_shape_strides[:i]
                                  ),
                                  shape_stride[0] * remaining_buffer,
                              ),
                          )
                      )
                      to_apply.append(
                          (
                              MovementOps.PAD,
                              (
                                  *((0, 0) for _ in range(i)),
                                  (
                                      0,
                                      shape_stride[0] * shape_stride[1],
                                  ),
                              ),
                          )
                      )
                      to_apply.append(
                          (
                              MovementOps.RESHAPE,
                              (
                                  *(
                                      s[0]
                                      for s in ordered_shape_strides[
                                          : i + 1
                                      ]
                                  ),
                                  remaining_buffer + shape_stride[1],
                              ),
                          )
                      )
                      ordered_shape_strides[i] = (
                          ordered_shape_strides[i][0],
                          remaining_buffer + shape_stride[1],
                      )
                  else:
                      to_apply.append(
                          (
                              MovementOps.SHRINK,
                              (
                                  *(
                                      (0, s[0])
                                      for s in ordered_shape_strides[:i]
                                  ),
                                  (
                                      0,
                                      shape_stride[0] * shape_stride[1],
                                  ),
                              ),
                          )
                      )
                      to_apply.append(
                          (
                              MovementOps.RESHAPE,
                              (
                                  *[
                                      s[0]
                                      for s in ordered_shape_strides[
                                          : i + 1
                                      ]
                                  ],
                                  shape_stride[1],
                              ),
                          )
                      )
              to_apply.extend(
                  [
                      (
                          MovementOps.SHRINK,
                          (
                              *[
                                  (0, s[0])
                                  for s in ordered_shape_strides
                              ],
                              (0, 1),
                          ),
                      ),
                      (
                          MovementOps.RESHAPE,
                          tuple(s[0] for s in ordered_shape_strides),
                      ),
                  ]
              )
              if order != list(range(len(order))):
                  to_apply.append(
                      (
                          MovementOps.PERMUTE,
                          tuple(
                              order.index(i)
                              for i in range(len(strides))
                          ),
                      )
                  )
          to_apply.append(
              (
                  MovementOps.RESHAPE,
                  tuple(
                      s if st else 1
                      for s, st in zip(real_shape, v.strides)
                  ),
              )
          )
          if any(i < 0 for i in v.strides):
              to_apply.append(
                  (
                      MovementOps.STRIDE,
                      tuple(-1 if st < 0 else 1 for st in v.strides),
                  )
              )
          # then, we apply pre expand pads
          if v.mask is not None:
              pre_expand_pads = tuple(
                  (x, s - y) if st != 0 else (0, 0)
                  for (x, y), s, st in zip(v.mask, v.shape, v.strides)
              )
              post_expand_pads = tuple(
                  (x, s - y) if st == 0 else (0, 0)
                  for (x, y), s, st in zip(v.mask, v.shape, v.strides)
              )
              if any(x != (0, 0) for x in pre_expand_pads):
                  to_apply.append((MovementOps.PAD, pre_expand_pads))
                  real_shape = tuple(
                      x + s[0] + s[1]
                      for x, s in zip(real_shape, pre_expand_pads)
                  )
          # then, we do any expands
          if any(
              s != 1 and st == 0 for s, st in zip(real_shape, v.strides)
          ):
              to_apply.append((MovementOps.EXPAND, real_shape))
          # lastly, we apply post expand pads
          if v.mask is not None and any(
              x != (0, 0) for x in post_expand_pads
          ):
              to_apply.append((MovementOps.PAD, post_expand_pads))
  
      scratch_st = make_scratch_st(st)
      ret = []
      seen = (
          {}
      )  # {shapetracker: list of mops to generate that shapetracker}
      for mop_arg in to_apply:
          scratch_st = apply_mop(scratch_st, mop_arg)
          if scratch_st in seen:
              ret = seen[scratch_st][:]
          else:
              ret.append(mop_arg)
              seen[scratch_st] = ret[:]
  
      return ret
  
file_path: tinygrad/extra/to_movement_ops.py
imports: from tqdm import tqdm
  import itertools
  from collections import defaultdict
  from typing import List, Tuple, DefaultDict
  from extra.optimization.helpers import load_worlds, ast_str_to_ast
  from tinygrad.ops import MovementOps, BufferOps, LazyOp
  from tinygrad.helpers import prod
  from tinygrad.shape.shapetracker import ShapeTracker
  from tinygrad.shape.symbolic import sym_infer, Node
label_desc: Use image node_id 3 for calling a global function with example usage: to_movement_ops(st) and returns: ret, sorted,  sorted