import torch


def compute_quantile_loss_instance_wise(outputs: torch.Tensor,
                                        targets: torch.Tensor,
                                        desired_quantiles: torch.Tensor) -> torch.Tensor:
    """
    This function compute the quantile loss separately for each sample,time-step,quantile.

    Parameters
    ----------
    outputs: torch.Tensor
        The outputs of the model [num_samples x num_horizons x num_quantiles].
    targets: torch.Tensor
        The observed target for each horizon [num_samples x num_horizons].
    desired_quantiles: torch.Tensor
        A tensor representing the desired quantiles, of shape (num_quantiles,)

    Returns
    -------
    losses_array: torch.Tensor
        a tensor [num_samples x num_horizons x num_quantiles] containing the quantile loss for each sample,time-step and
        quantile.
    """

    # compute the actual error between the observed target and each predicted quantile
    errors = targets.unsqueeze(-1) - outputs
    # Dimensions:
    # errors: [num_samples x num_horizons x num_quantiles]

    # compute the loss separately for each sample,time-step,quantile
    losses_array = torch.max((desired_quantiles - 1) * errors, desired_quantiles * errors)
    # Dimensions:
    # losses_array: [num_samples x num_horizons x num_quantiles]

    return losses_array