# Edit this example, then press Run. Reset restores the published version.

def require(condition, message):
    if not condition:
        raise AssertionError(message)


def multiply(a, b):
    return tuple(tuple(sum(x*y for x, y in zip(row, column))
                       for column in zip(*b)) for row in a)


def apply(a, vector):
    return tuple(sum(x*y for x, y in zip(row, vector)) for row in a)


def add_matrices(matrices):
    return tuple(tuple(sum(a[i][j] for a in matrices)
                       for j in range(len(matrices[0][0])))
                 for i in range(len(matrices[0])))


def add_vectors(vectors):
    return tuple(map(sum, zip(*vectors)))


def packets():
    x = (2, 3)
    p = (((1, 0), (0, 0)), ((0, 0), (0, 1)))
    identity, zero = ((1, 0), (0, 1)), ((0, 0), (0, 0))
    t = ((1, 2), (3, 4))
    require(add_matrices(p) == identity, 'Packets must sum to the identity')
    for j in range(2):
        for i in range(2):
            require(multiply(p[j], p[i]) == (p[i] if i == j else zero),
                    'Packet multiplication identity failed')
    # Rows are target packets and columns are source packets.
    blocks = tuple(multiply(multiply(p[j], t), p[i])
                   for j in range(2) for i in range(2))
    require(add_matrices(blocks) == t, 'Block reconstruction failed')
    direct = apply(t, x)
    rebuilt = add_vectors(tuple(apply(b, x) for b in blocks))
    missing = add_vectors(tuple(apply(b, x) for b in blocks[:-1]))
    require(direct == rebuilt == (8, 18), 'Unexpected reconstructed result')
    require(missing == (8, 6) and missing != direct, 'Missing-block control failed')
    return '\n'.join([
        f'Input: {x}',
        f'Packet parts: {tuple(apply(q, x) for q in p)}',
        f'Block contributions: {tuple(apply(b, x) for b in blocks)}',
        f'Direct result: {direct}',
        f'Reconstructed result: {rebuilt}',
        f'Without the final block: {missing}',
        'PASS: packets',
    ])


print(packets())
