from typing import Callable


def linear_schedule(
    initial_value: float, final_value: float, end: float = 0
) -> Callable[[float], float]:
    """
    Linear learning rate schedule.

    :param initial_value: Initial learning rate.
    :param final_value: Final learning rate
    :param end: Progress remaining where final value will be reached.
    :return: schedule that computes
        current learning rate depending on remaining progress
    """
    assert 0 < end < 1

    def func(progress_remaining: float) -> float:
        """
        Progress will decrease from 1 (beginning) to 0.

        :param progress_remaining:
        :return: current learning rate
        """
        if progress_remaining < end:
            lr = final_value
        else:
            x0 = end
            x1 = 1
            y0 = final_value
            y1 = initial_value
            a = (y1 - y0) / (x1 - x0)
            b = y1 - a * x1

            lr = a * progress_remaining + b
        return lr

    return func