code: def _make_functional(
      module: _torch.nn.Module,
      params_box: _typing.Sequence[
          _typing.Optional[_typing.List[_torch.Tensor]]
      ],
      params_offset: int,
      root_patched: _typing.Optional[_MonkeyPatchBase] = None,
  ) -> _typing.Tuple[
      int, _MonkeyPatchBase, _typing.Type[_MonkeyPatchBase]
  ]:
      if isinstance(module, _MonkeyPatchBase):
          raise ValueError(
              "Monkey-patching monkey-patched modules is untested uncharted "
              "territory, so we're going to assume it's done in error. If you "
              "are doing this intentionally and need this to be supported, "
              "contact the developers of this library."
          )
  
      param_names = list(
          name
          for name in module._parameters.keys()
          if module._parameters[name] is not None
      )
  
      _ModuleType: _typing.Type[_torch.nn.Module] = module.__class__
  
      # type checking of next line disabled as mypy is iffy with dynamic types
      class MonkeyPatched(_ModuleType, _MonkeyPatchBase):  # type: ignore
          _wrapped_name = type(module).__name__
  
          def __init__(self, original_params, root) -> None:
              _torch.nn.Module.__init__(self)
              _MonkeyPatchBase.__init__(self)
              self._root_ref = _weakref.ref(root) if root else None
  
              self._fast_params = None
              self._param_names = param_names
  
              self._original_params = original_params
  
              # for pretty printing
              self._parameters = _OrderedDict(
                  (name, _ParameterPlaceholder(name))
                  for name in self._param_names
              )
              self._modules: _typing.Dict[
                  str, _MonkeyPatchBase
              ] = _OrderedDict()
  
          @property
          def direct_submodule_call(self):
              return params_box[0] is None
  
          @property
          def is_root(self):
              return self._root_ref is None
  
          @property
          def root(self):
              if self.is_root:
                  return self
              else:
                  return self._root_ref()
  
          def __setattr__(self, name, value):
              def remove_from(*dicts):
                  for d in dicts:
                      if name in d:
                          del d[name]
  
              params = self.__dict__.get("_parameters")
              if params is not None and name in params:
                  if not isinstance(value, _torch.Tensor):
                      raise TypeError(
                          "Require Tensor as fast weights. "
                          "Got {}".format(_torch.typename(value))
                      )
  
                  if not self._being_modified_internally:
                      # Additional behaviour for when fast weights are being
                      # directly modified goes here:
                      old_value = self._parameters[name]
                      fast_params = self.root.fast_params[:]
                      if not fast_params:
                          raise Exception(
                              "Cannot assign parameters to patched module which "
                              "does not have implicit fast parameters."
                          )
                      replacement_index = _utils._find_param_in_list(
                          old_value, fast_params
                      )
                      fast_params[replacement_index] = value
                      self.update_params(fast_params)
  
                  # Change parameters in place, usually during boxed_forward pass
                  self._parameters[name] = value
              else:
                  modules = self.__dict__.get("_modules")
                  if isinstance(value, _torch.nn.Module):
                      if modules is None:
                          raise AttributeError(
                              "cannot assign module before Module.__init__() "
                              "call"
                          )
                      remove_from(
                          self.__dict__, self._parameters, self._buffers
                      )
                      modules[name] = value
                  elif modules is not None and name in modules:
                      if value is not None:
                          raise TypeError(
                              (
                                  "cannot assign '{}' "
                                  "as child module '{}'"
                                  "(torch.nn.Module or None expected)"
                              ).format(_torch.typename(value), name)
                          )
                      modules[name] = value
                  else:
                      buffers = self.__dict__.get("_buffers")
                      if buffers is not None and name in buffers:
                          if value is not None and not isinstance(
                              value, _torch.Tensor
                          ):
                              raise TypeError(
                                  "cannot assign '{}' as buffer '{}' "
                                  "(torch.Tensor or None expected)".format(
                                      _torch.typename(value), name
                                  )
                              )
                          buffers[name] = value
                      else:
                          object.__setattr__(self, name, value)
  
      MonkeyPatched.__name__ = "InnerFunctional" + type(module).__name__
      MonkeyPatched.__qualname__ = MonkeyPatched.__name__
  
      fmodule = MonkeyPatched(module.parameters(), root=root_patched)
  
      # If a root module hasn't been defined yet, this fmodule is the root
      if not root_patched:
          root_patched = fmodule
  
      # use 1 as dummy list item since we are only counting
      num_params = len(
          [1 for p in module._parameters.values() if p is not None]
      )
  
      # Copy over all attributes
      for name, attr in module.__dict__.items():
          if name in _internal_attrs:
              continue
          setattr(fmodule, name, attr)
  
      # Deal with "None"-style params
      with _modify_internally(fmodule):
          for name, attr in module.__dict__["_parameters"].items():
              if isinstance(attr, _torch.nn.Parameter):
                  continue
              else:
                  setattr(fmodule, name, attr)
  
      child_params_offset = params_offset + num_params
      for name, child in module._modules.items():
          child_params_offset, fchild, _ = _make_functional(
              child, params_box, child_params_offset, root_patched
          )
          fmodule._modules[name] = fchild
          setattr(fmodule, name, fchild)
  
      true_forward = type(module).forward
  
      def patched_forward(self, *args, params=None, **kwargs):
          if self.direct_submodule_call:
              # If submodule was called directly, run intialisation that happens
              # at top level call. If *full set of params* is provided here, it
              # will use those. If not, it will fall back on fast weights.
              # In the future, we should be able to support passing only the
              # submodule (+ children) weights here, but that's not simple.
              self.root._refill_params_box(params)
  
          with _modify_internally(self):
              for name, param in zip(
                  self._param_names,
                  params_box[0][
                      params_offset : params_offset + num_params
                  ],
              ):
                  setattr(self, name, param)
  
              # This snippet deals with torch.nn.{RNN,GRU,LSTM}
              if hasattr(self, "_flat_weights_names"):
                  self._flat_weights = [
                      self._parameters[wn]
                      for wn in self._flat_weights_names
                  ]
  
          # Call true_forward after some checks
          with _warnings.catch_warnings():
              # If running RNNs on GPU, surpress the warnings due to flattening
              # not happening here. Maybe we should raise a warning of our own?
              is_RNN = isinstance(module, _torch.nn.RNNBase)
              if is_RNN and _torch.cuda.is_available():
                  _warnings.simplefilter("ignore", category=UserWarning)
  
              return true_forward(self, *args, **kwargs)
  
      setattr(MonkeyPatched, "forward", patched_forward)
  
      def flatten_parameters(self):
          return  # no-op
  
      # This (hopefully) avoids trouble on GPU with torch.nn.{RNN,GRU,LSTM}
      if hasattr(module, "flatten_parameters"):
          setattr(
              MonkeyPatched, "flatten_parameters", flatten_parameters
          )
  
      return child_params_offset, fmodule, type(fmodule)
  
imports: import abc
  from collections import OrderedDict
  from contextlib import contextmanager
  import typing
  import weakref
  import warnings
  import torch
  from .None import utils
label_desc: Use image node_id 4 for calling a global function with example usage: _make_functional(module, params_box, params_offset, root_patched) and returns: child_params_offset,  fmodule,  type, unknown, unknown, true_forward, self, self