1# tiny class to hold a 2x2 matrix
class Matrix2x2:
    def __init__(self, m00, m01, m10, m11):
        self.m00 = m00
        self.m01 = m01
        self.m10 = m10
        self.m11 = m11

# multiply two 2x2 matrices
def multiply(a, b):
    return Matrix2x2(
        a.m00 * b.m00 + a.m01 * b.m10,  # top-left
        a.m00 * b.m01 + a.m01 * b.m11,  # top-right
        a.m10 * b.m00 + a.m11 * b.m10,  # bottom-left
        a.m10 * b.m01 + a.m11 * b.m11   # bottom-right
    )

# raise a matrix to the power n using binary exponentiation
def matrix_pow(base, n):
    result = Matrix2x2(1, 0, 0, 1)  # start with identity matrix
    while n > 0:
        if n % 2 == 1:  # if n is odd, multiply once
            result = multiply(result, base)
        base = multiply(base, base)  # square the base
        n //= 2  # integer division
    return result

# get nth fibonacci number using matrix exponentiation
def fibonacci_matrix(n):
    if n == 0:
        return 0  # edge case
    base = Matrix2x2(1, 1, 1, 0)  # Fibonacci Q-matrix
    result = matrix_pow(base, n - 1)
    return result.m00  # top-left is F(n)

# print first n fibonacci numbers
if __name__ == "__main__":
    n = 50
    for i in range(n):
        print(fibonacci_matrix(i), end=" ")
    print()
