overlapping memory.
Finally, a helpful mental model for understanding functionalization
   is that most user pytorch programs are writting with the public
   torch API. When executed, torch operators are generally decomposed
   into our internal C++ "ATen" API. The logic for functionalization
   happens entirely at the level of ATen. Functionalization knows how
   to take every aliasing operator in ATen, and map it to its non-
   aliasing equivalent (e.g. "tensor.view({-1})" ->
   "at::view_copy(tensor, {-1})"), and how to take every mutating
   operator in ATen, and map it to its non-mutating equivalent (e.g.
   "tensor.add_(1)" -> "at::add(tensor, -1)"), while tracking aliases
   and mutations out-of-line to know when to fix things up.
   Information about which ATen operators are aliasing or mutating all
   comes from https://github.com/pytorch/pytorch/blob/master/aten/src
   /ATen/native/native_functions.yaml.