import torch

def simulate_observations_NB(ground_truth_weights, ground_truth_hyperparameters):
    """
    Simulate observations based on the ground truth weights and hyperparameters.
    The observations are generated by adding Gaussian noise to the ground truth weights.
    The noise is scaled by the noise hyperparameters for each feature.  
    Args:
        ground_truth_weights (torch.Tensor): The ground truth weights of shape (L, D).
        ground_truth_hyperparameters (dict): A dictionary containing the hyperparameters for the GP.
            It should contain the keys 'noise' for the noise hyperparameters.
    Returns:
        xsamples (torch.Tensor): The simulated observations of shape (L, D).    
    """
    # Extract the number of samples and features
    L, D = ground_truth_weights.shape

    # Initialize the observations
    xsamples = torch.zeros(L, D)  # Initialize the xsamples tensor
    # Generate the observations
    # For each feature, add Gaussian noise to the ground truth weights
    for d in range(D):
        xsamples[:, d] = ground_truth_weights[:, d] + ground_truth_hyperparameters['noise'][d] * torch.randn(L)
    return xsamples