code: def _process_dynamic_shapes(
      f: Callable,
      args: Tuple[Any, ...],
      kwargs: Optional[Dict[str, Any]] = None,
      dynamic_shapes: Optional[
          Union[Dict[str, Any], Tuple[Any]]
      ] = None,
  ) -> Optional[List[Constraint]]:
      from torch._dynamo.exc import UserError, UserErrorType
  
      if dynamic_shapes is None or len(dynamic_shapes) == 0:
          return None
  
      kwargs = kwargs if kwargs is not None else {}
  
      from collections.abc import Mapping, Sequence
  
      def tree_zip(combined_args, dynamic_shapes):
          if isinstance(combined_args, (tuple, list)):
              if not isinstance(dynamic_shapes, Sequence):
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Expected dynamic_shapes of a {type(combined_args)} to be a Sequence, "
                      f"got {dynamic_shapes} instead",
                  )
              if len(combined_args) != len(dynamic_shapes):
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Expected {dynamic_shapes} to have {len(combined_args)} items",
                  )
              for i, shape in enumerate(dynamic_shapes):
                  yield from tree_zip(combined_args[i], shape)
          elif isinstance(combined_args, dict):
              if not isinstance(dynamic_shapes, Mapping):
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Expected dynamic_shapes of a {type(combined_args)} to be a Mapping, "
                      f"got {dynamic_shapes} instead",
                  )
              if len(combined_args) != len(dynamic_shapes):
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Expected {dynamic_shapes} to have {len(combined_args)} items",
                  )
              for k, shape in dynamic_shapes.items():
                  yield from tree_zip(combined_args[k], shape)
          elif dataclasses.is_dataclass(combined_args):
              if not type(dynamic_shapes) == type(combined_args):
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Expected dynamic_shapes of a {type(combined_args)} to be a {type(combined_args)}, "
                      f"got {dynamic_shapes} instead",
                  )
              for f in dataclasses.fields(combined_args):
                  yield from tree_zip(
                      getattr(combined_args, f.name),
                      getattr(dynamic_shapes, f.name),
                  )
          elif isinstance(combined_args, torch.Tensor):
              yield (combined_args, dynamic_shapes)
          else:
              if dynamic_shapes is not None:
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Expected dynamic_shapes of a {type(combined_args)} to be None, "
                      f"got {dynamic_shapes} instead",
                  )
  
      def to_constraint(dim, tensor, i):
          constraint = dynamic_dim(tensor, i, debug_name=dim.__name__)
          if dim.min != 2:
              constraint = constraint >= dim.min
          if dim.max != sys.maxsize - 1:
              constraint = constraint <= dim.max
          return constraint
  
      from collections import defaultdict
  
      symbols = defaultdict(list)
      bounds: Dict[str, Tuple[int, int]] = {}
  
      def check_same_bounds(dim):
          if dim.__name__ in symbols:
              min_, max_ = bounds[dim.__name__]
              if dim.min != min_ or dim.max != max_:
                  this_ = _Dim.readable(dim.__name__, min_, max_)
                  that_ = _Dim.readable(dim.__name__, dim.min, dim.max)
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Found different definitions {this_} and {that_} "
                      f"for the same symbolic dimension {dim}!",
                  )
  
          else:
              bounds[dim.__name__] = (dim.min, dim.max)
  
      def update_symbols(tensor, shape):
          if isinstance(shape, dict):
              for i, dim in shape.items():
                  if isinstance(dim, _Dim):
                      check_same_bounds(dim)
                      symbols[dim.__name__].append(
                          to_constraint(dim, tensor, i)
                      )
                  else:
                      if dim is not None:
                          raise UserError(
                              UserErrorType.INVALID_INPUT,
                              f"Unexpected item #{i} ({dim}) in dynamic_shape {shape} of Tensor, "
                              "try None instead",
                          )
          elif isinstance(shape, (tuple, list)):
              for i, dim in enumerate(shape):
                  if isinstance(dim, _Dim):
                      check_same_bounds(dim)
                      symbols[dim.__name__].append(
                          to_constraint(dim, tensor, i)
                      )
                  else:
                      if dim is not None:
                          raise UserError(
                              UserErrorType.INVALID_INPUT,
                              f"Unexpected item #{i} ({dim}) in dynamic_shape {shape} of Tensor, "
                              "try None instead",
                          )
          else:
              if shape is not None:
                  raise UserError(
                      UserErrorType.INVALID_INPUT,
                      f"Unexpected dynamic_shape {shape} of Tensor, "
                      "try None instead",
                  )
  
      import inspect
  
      if isinstance(f, ExportedProgram):
          f = f.module()
      signature = (
          inspect.signature(f.forward)
          if isinstance(f, torch.nn.Module)
          else inspect.signature(f)
      )
      combined_args = signature.bind(*args, **kwargs).arguments
  
      # This means user didn't specify dynamic shapes with argument names.
      combined_args = combined_args if isinstance(dynamic_shapes, Mapping) else list(combined_args.values())  # type: ignore[assignment]
      for tensor, shape in tree_zip(combined_args, dynamic_shapes):
          update_symbols(tensor, shape)
  
      constraints = []
      for dynamic_dims in symbols.values():
          primary, *others = dynamic_dims
          if others:
              for other in others:
                  constraints.append(primary == other)
          else:
              constraints.append(primary)
  
      return constraints
  
imports: import builtins
  import dataclasses
  import inspect
  import math
  import sys
  import weakref
  from collections import defaultdict
  from typing import Any, Callable, Dict, List, Optional, Tuple, TYPE_CHECKING, Union
  import torch
  from torch._subclasses.fake_tensor import FakeTensor
  from .exported_program import ExportedProgram
label_desc: Use image node_id 5 for calling a global function with example usage: _process_dynamic_shapes(f, args, kwargs, dynamic_shapes) and returns: constraints, None, constraint