import numpy as np


def table4_10(max_iterations=100000):
    # orthogonal iteration

    # error tolerance
    tol = 1e-6

    err = 10 * tol

    # matrix
    n = 10
    A = np.zeros((n, n))
    a = 3
    for i in range(n):
        A[i, i] = a
    A[n - 1, 0] = 1
    A[0, n - 1] = 1

    B = np.random.rand(n, n)
    Q, R = np.linalg.qr(B)
    eigens0 = np.ones(n)
    k = 0
    while err > tol:
        if k >= max_iterations:
            raise RuntimeError("Maximum number of iterations reached before convergence.")
        k = k + 1
        B = A @ Q
        Q, R = np.linalg.qr(B)
        eigens = np.zeros(n)
        for ic in range(n):
            eigens[ic] = np.dot(Q[:, ic], A @ Q[:, ic]) / np.dot(Q[:, ic], Q[:, ic])
        err = np.linalg.norm((eigens - eigens0) / eigens, np.inf)
        eigens0 = eigens.copy()
        print(
            f"\\, {k:d} \\, &\\,\\, {eigens[0]:12.8f} \\,\\,&\\,\\, "
            f"{eigens[1]:12.8f} \\,\\,&\\,\\, {eigens[6]:12.8f} \\,\\,&\\,\\,   "
            f"{eigens[n - 1]:12.8f} \\\\\\hline "
        )
        if err < tol:
            break


if __name__ == "__main__":
    table4_10()
