"""Literal Python conversion of table8_3.m."""

import argparse

import numpy as np


def table8_3(icase=2, sizes=None):
    # well-conditioned:  icase=1
    # ill-conditioned: icase=2

    if sizes is None:
        sizes = [100, 500, 1000, 2000, 4000]

    print("\n n     QR-QcRc     Q-Qc     R-Rc   (Qc^T)Qc-I    kappa ")

    for ins, n in enumerate(sizes, start=1):
        # find random Q
        Q1, R1 = np.linalg.qr(np.random.rand(n, n))

        # find random R
        Rp = np.random.rand(n, n)
        for j in range(n - 1):
            Rp[j + 1:n, j] = 0
        if icase == 2:
            # ill-condtioned matrix
            Rp = Rp + 2 * np.eye(n)
        elif icase == 1:
            # well-conditioned matrix
            Rp = Rp + n * np.eye(n)

        A = Q1 @ Rp
        Q, R = np.linalg.qr(A)

        # given QR, find equivalent with positive diagonals in R
        itest = 0
        for i in range(n):
            if R[i, i] < 0:
                R[i, i] = -R[i, i]
                Q[:, i] = -Q[:, i]
                itest = itest + 1
                if i < n - 1:
                    R[i, i + 1:n] = -R[i, i + 1:n]
        # R

        con = np.linalg.cond(A, np.inf)
        e1 = np.linalg.norm(Q1 @ Rp - Q @ R, np.inf) / np.linalg.norm(A, np.inf)
        e2 = np.linalg.norm(Q1 - Q, np.inf) / np.linalg.norm(Q1, np.inf)
        e3 = np.linalg.norm(Rp - R, np.inf) / np.linalg.norm(Rp, np.inf)

        # format for book
        print(
            f"{n:d} & {e1:5.1e}  & {e2:5.1e} & {e3:5.1e}  & "
            f"{np.linalg.norm(Q.T @ Q - np.eye(n), np.inf):5.1e}  & {con:5.0e}"
        )

        # format for lecture
        # print(f'{n:d}   {e1:5.1e}   {e2:5.1e}   {e3:5.1e}   '
        #       f'{np.linalg.norm(Q.T@Q-np.eye(n),np.inf):5.1e}   {con:5.1e}')

    print()


def main():
    parser = argparse.ArgumentParser(description="Python conversion of table8_3.m")
    parser.add_argument("--icase", type=int, choices=[1, 2], default=2)
    parser.add_argument(
        "--sizes",
        type=int,
        nargs="*",
        default=None,
        help="Optional matrix sizes. The original defaults are 100 500 1000 2000 4000.",
    )
    args = parser.parse_args()
    table8_3(icase=args.icase, sizes=args.sizes)


if __name__ == "__main__":
    main()
