import random


def add_parameter_noise(cfg, noise_ratio):
    """
    Add noise to the hyperparameters of the Dynamic DropConnect model.
    This changes the input dictionary in-place.

    Args:
        cfg: Dictionary containing the configuration with all hyperparameters
        noise_ratio: Ratio of noise relative to magnitude of parameter base value

    Returns:
        Perturbed hyperparameter dictionary
    """
    # Add uniform noise scaled relative to magnitude of input float.
    def _add_relative_uniform_noise(x, noise_ratio):
        noise_range = noise_ratio * abs(x)
        return random.uniform(x - noise_range, x + noise_range)

    # Noise only applies to the hyperparemeters of the model that we tune
    cfg['prob_drift_down'] = _add_relative_uniform_noise(cfg['prob_drift_down'], noise_ratio)
    cfg['prob_drift_up'] = _add_relative_uniform_noise(cfg['prob_drift_up'], noise_ratio)
    cfg['prob_freeze'] = _add_relative_uniform_noise(cfg['prob_freeze'], noise_ratio)
    cfg['grad_threshold'] = _add_relative_uniform_noise(cfg['grad_threshold'], noise_ratio)

    return cfg