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)

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}')