def grad(self, X, *params):
        """
        Return the gradient of the basis function for each parameter.

        Parameters
        ----------
        X : ndarray
            (N, d) array of observations where N is the number of samples, and
            d is the dimensionality of X.
        *params : optional
            parameter aguments, these are the parameters of the concatenated
            bases `in the order` they were concatenated.

        Returns
        -------
        list or ndarray :
            this will be a list of ndarrays if there are multiple parameters,
            or just an ndarray if there is a single parameter. The ndarrays can
            have more than two dimensions (i.e. tensors of rank > 2), depending
            on the dimensions of the basis function parameters. If there are
            *no* parameters, ``[]`` is returned.
        """
        # Establish a few dimensions
        N = X.shape[0]
        D = self.get_dim(X)
        endinds = self.__base_locations(X)  # for the Padding indices
        args = list(params)

        # Generate structured gradients with appropriate zero padding
        def make_dPhi(i, g):

            # Pad the gradient with respect to the total basis dimensionality
            dPhi_dim = (N, D) if g.ndim < 3 else (N, D, g.shape[2])
            dPhi = np.zeros(dPhi_dim)
            dPhi[:, endinds[i]:endinds[i + 1]] = g

            return dPhi

        # Get gradients from each basis
        for i, base in enumerate(self.bases):

            # evaluate gradient and deal with multiple parameter gradients by
            # keeping track of the basis index
            g, args, sargs = base._grad_popargs(X, *args)

            for gg in atleast_tuple(g):
                if len(gg) == 0:
                    continue
                yield make_dPhi(i, gg)
Return the gradient of the basis function for each parameter.

        Parameters
        ----------
        X : ndarray
            (N, d) array of observations where N is the number of samples, and
            d is the dimensionality of X.
        *params : optional
            parameter aguments, these are the parameters of the concatenated
            bases `in the order` they were concatenated.

        Returns
        -------
        list or ndarray :
            this will be a list of ndarrays if there are multiple parameters,
            or just an ndarray if there is a single parameter. The ndarrays can
            have more than two dimensions (i.e. tensors of rank > 2), depending
            on the dimensions of the basis function parameters. If there are
            *no* parameters, ``[]`` is returned.