def METHOD_NAME(params, model_cls, minimal_state, empty_logger):
    # Initialize input tensor
    input = torch.rand((32, 5))
    if 'smoothing' in params:
        smoothing, update_interval = params['smoothing'], params['update_interval']
        algorithm = EMA(half_life=None, smoothing=smoothing, update_interval=update_interval)
    else:
        half_life, update_interval = params['half_life'], params['update_interval']
        algorithm = EMA(half_life=half_life, update_interval=update_interval)
    state = minimal_state
    state.model = model_cls()
    state.batch = (input, torch.Tensor())
    # Start EMA
    algorithm.ema_model = EMAParameters(state.model)
    # Check if ema correctly calculated smoothing
    update_interval = Time.from_timestring(params['update_interval'])
    if 'half_life' in params:
        half_life = Time.from_timestring(params['half_life'])
        smoothing = np.exp(-np.log(2) * (update_interval.value / half_life.value))
        np.testing.assert_allclose(np.asarray(smoothing), np.asarray(algorithm.smoothing))
    # Fake a training update by replacing state.model after ema grabbed it.
    original_model = copy.deepcopy(state.model)
    state.model = model_cls()
    training_updated_model = copy.deepcopy(state.model)
    # Do the EMA update
    state.timestamp = Timestamp()
    if update_interval.unit == TimeUnit.BATCH:
        state.timestamp._batch = update_interval
        algorithm.apply(Event.BATCH_END, state, empty_logger)
    elif update_interval.unit == TimeUnit.EPOCH:
        state.timestamp._epoch = update_interval
        algorithm.apply(Event.EPOCH_END, state, empty_logger)
    else:
        raise ValueError(f'Invalid time string for parameter half_life')
    # Check if EMA correctly computed the average.
    validate_ema(state.model, original_model, algorithm.ema_model, algorithm.smoothing)
    ema_updated_model = copy.deepcopy(algorithm.ema_model)
    # Check if the EMA model is swapped in for testing
    algorithm.apply(Event.EVAL_START, state, empty_logger)
    validate_model(state.model, ema_updated_model)
    # Check if the training model is swapped back in for training
    algorithm.apply(Event.EVAL_END, state, empty_logger)
    validate_model(state.model, training_updated_model)