def gradient_of_rmse(y_hat, y, Xn):
    """ 
    Returns the gradient of the Root Mean Square error with respect to the 
    parameters of the linear model that generated the prediction `y_hat'. 
    Hence, y_hat should have been generated by a linear process of the form
    Xn.T.dot(theta)

    Args:
        
       y_hat (np.array of shape N,): The predictions of the linear model
       y (np.array of shape N,): The "ground-truth" values.

    Returns:
        The RMSE between y_hat and y
    """
        
    N = y.shape[0]
    assert N > 0, ('At least one sample is required in order to compute the '
                  'RMSE loss')
   
    losses = y - y_hat
    gradient = - 2 * Xn.T.dot(losses) / N

    return gradient