docs: def _parse_args_forward_mode(self, *args) -> Tuple[dict, dict]:
          """
          Parse input arguments used in forward mode differentiation.
          End result will be two arrays X and dX, each of shape (n) or (T, n)
          Allowed input shapes are:
          (1) ARRAY_N:    two arrays of size n
          (2) ARRAY_TxN:  two arrays of size Txn
          (3) DICT:       two dictionaries, each mapping variable names to values
          (4) ARGS:       a list of 2n values; n variables followed by n seeds
          (5) KWARGS:     a kwargs list (currently not supported)
          """
          # Types for arg_vars and arg_seed
          arg_vars: np.ndarray = {}
          arg_seed: np.ndarray = {}
          # Get the number of arguments and inputs
          argc: int = len(args)
          m: int = self.m
          # Check each type in turn
          # The most common case is two arguments were passed for the vars and seeds
          # They can both be numpy arrays or dicts
          if argc == 0:
              return (None, None)
          if argc == 1:
              # The lone argument
              arg = args[0]
              # Case zero: None
              if arg is None:
                  return (None, None)
              # Case one: a dict
              elif isinstance(arg, dict):
                  arg_vars = self._parse_var_dict(arg)
              # Case two: a scalar
              elif isinstance(arg, scalar_instance_types):
                  arg_vars = self._parse_var_scalar(arg)
              # Case three: a numpy array
              elif isinstance(arg, np.ndarray):
                  arg_vars = self._parse_var_array(arg)
              T_vars = self._check_forward_mode_input_dict(arg_vars)
              self.T = T_vars
              return (arg_vars, self._default_seed(arg_vars))
          if argc == 2:
              # Case one: a pair of dicts
              if isinstance(args[0], dict) and isinstance(args[1], dict):
                  arg_vars = self._parse_var_dict(args[0])
                  arg_seed = self._parse_seed_dict(args[1])
              # Case two: two scalars
              elif isinstance(args[0], scalar_instance_types) and isinstance(args[1], scalar_instance_types):
                  arg_vars = self._parse_var_scalar(args[0])
                  arg_seed = self._parse_var_scalar(args[1])
              # Case three: two numpy arrays
              elif isinstance(args[0], np.ndarray) and isinstance(args[1], np.ndarray):
                  arg_vars = self._parse_var_array(args[0])
                  arg_seed = self._parse_var_array(args[1])
              else:
                  raise ValueError(f'Input types must either be dict, scalar, or np.ndarray for Fluxion.parse_args.')
              T_vars = self._check_forward_mode_input_dict(arg_vars)
              T_seed = self._check_forward_mode_input_dict(arg_seed)
              self.T = T_vars
              if T_seed in (1,T_vars):
                  return (arg_vars, arg_seed)
              else:
                  raise ValueError(f'Bound variables in {args[0]} inconsistent with bound variables in {args[1]}')
  
          # If we reach here, we either got ARGS or KWARGS
          if argc == 2 * m:
              # Initialize X and dX in the correct shape
              X = np.array(args[0:m],dtype=np.float64)
              dX = np.array(args[m:2*m],dtype=np.float64)
              # Reevaluate the two arrays
              return self._parse_args_forward_mode(X, dX)
          # KWARGS not yet supported
          msg = f'argc={argc}'
          for arg in args:
              msg += f'{arg}'
          raise ValueError(f'Unrecognized input type for Fluxion.parse_args.  Details:\n{msg}')