import math


def pyramid_sizes(init_size, a_output_size, b_output_size):
    """
    Determine appropriate resolutions for all levels of an image pyramid.

    @param init_size Max width/height of the lowest resolution of the pyramid.
    @param a_output_size Size (w,h) of the exemplar image (ai) of the highest
    resolution of the pyramid.
    @param b_output_size Size (w,h) of the synthesized image (bi) of the
    highest resolution of the pyramid.
    @return Sizes of all pyramid levels from lowest to highest resolution.

    Examples:
        >>> pyramid_sizes(32, (158,239), (345,287))
        [((21, 32), (45, 38)), ((42, 64), (90, 76)), ((84, 128),
         (180, 152)), ((158, 239), (345, 287))]
    """
    if a_output_size[0] < a_output_size[1]:
        y = init_size
        x = int(math.floor(init_size * a_output_size[0] / a_output_size[1]))
    else:
        x = init_size
        y = int(math.floor(init_size * a_output_size[1] / a_output_size[0]))

    a = int(math.ceil(1.0 * b_output_size[0] * x / a_output_size[0]))
    b = int(math.ceil(1.0 * b_output_size[1] * y / a_output_size[1]))
    result = []

    while x < a_output_size[0] and y < a_output_size[1]:
        result.append(((x,y), (a,b)))
        x *= 2
        y *= 2
        a *= 2
        b *= 2

    assert(a >= b_output_size[0])
    assert(b >= b_output_size[1])
    assert(a//2 < b_output_size[0])
    assert(b//2 < b_output_size[1])

    result.append((a_output_size, b_output_size))
    return result