gt22 icon

Untitled

gt22 | PRO | 05/14/20 02:43:22 PM UTC | 0 ⭐ | 2722 👁️ | Never ⏰ | []
Python |

4.12 KB

|

None

|

0 👍

/

0 👎

import numpy as np
 
g = np.array([[1, 2, 1], [2, 1, 1], [1, 1, 1]])
f = np.array([[3, 4, 6], [5, 2, 4], [3, 3, 3]])
 
matr = np.concatenate([g.T, f.T], axis=1)
 
# matr = np.array([
#     [4, 2, 1, 2, 1, 1],
#     [1, 1, 1, 3, -1, 3],
#     [3, 2, 1, 3, 1, 2]
# ])
 
n, m = matr.shape
aug = 3
 
 
def swap(i, j):
    matr[i], matr[j] = matr[j].copy(), matr[i].copy()
    return f"\\vec{{ {i + 1} }} \\leftrightarrow \\vec {{ {j + 1} }}"
 
 
def multiply(i, k):
    matr[i] *= k
    return f"\\vec{{ {i + 1} }} \\to \\cdot {k}"
 
 
def divide(i, k):
    matr[i] //= k
    return f"\\vec{{ {i + 1} }} \\to /{k}"
 
 
def first_nonzero(i):
    for k in range(m):
        if matr[i, k] != 0:
            return k
    return -1
 
 
def subtract(i, reverse=False):
    r = first_nonzero(i)
    gen = range(i - 1, -1, -1) if reverse else range(i + 1, n)
    for j in gen:
        k = first_nonzero(i) if reverse else first_nonzero(j)
        if k == -1 or k > r:
            continue
        if matr[j, k] % matr[i, r] != 0:
            raise ValueError("Not divisible")
        matr[j] -= (matr[j, k] // matr[i, r]) * matr[i]
    return f"-k \\cdot \\vec {{ {i + 1} }}"
 
 
def matrix_to_latex(linebreak):
    latex = ""
    if not linebreak:
        latex += "&"
    else:
        latex += "&&"
    latex += "\\begin{bmatrix}\n\t" if aug == 0 else f"\\begin{{abmatrix}}[{m - aug}]{{{aug}}}\n\t"
    latex += "\\\\\n\t".join([" & ".join([str(k) for k in j]) for j in matr])
    latex += "\n\\end{bmatrix}" if aug == 0 else "\n\\end{abmatrix}"
    if linebreak:
        latex += "\\\\"
    return latex
 
 
def print_op(latex, linebreak):
    if linebreak:
        print("&&", end='')
    print(f"\\underset {{ {latex} }} {{\\sim}}\n{matrix_to_latex(linebreak)}")
    return not linebreak
 
 
def gauss_step(normalized_lines, linebreak):
    for i in range(n):
        k = first_nonzero(i)
        if k != -1 and matr[i, k] < 0:
            linebreak = print_op(multiply(i, -1), linebreak)
 
    nonzero_left = min(first_nonzero(i) for i in range(normalized_lines, n))
    line_to_raise = min(((matr[i, nonzero_left], i)
                        for i in range(normalized_lines, n) if matr[i, nonzero_left] != 0), default=(-1, -1))[1]
    if line_to_raise == -1:
        return n
    if line_to_raise != normalized_lines:
        linebreak = print_op(swap(normalized_lines, line_to_raise), linebreak)
    main_line = matr[normalized_lines]
    main_elem = main_line[nonzero_left]
    for i in range(normalized_lines + 1, n):
        cur_elem = matr[i, first_nonzero(i)]
        k = np.lcm(main_elem, cur_elem) // cur_elem
        if k != 1:
            linebreak = print_op(multiply(i, k), linebreak)
    linebreak = print_op(subtract(normalized_lines), linebreak)
    return 1, linebreak
 
 
def normalize_step(linebreak):
    for i in range(0, n):
        k = first_nonzero(i)
        gg = matr[i, k]
        for e in range(k, m):
            gg = np.gcd(gg, matr[i, e])
        if gg != 1:
            linebreak = print_op(divide(i, gg), linebreak)
            return True, linebreak
    for i in range(n-1, -1, -1):
        k = first_nonzero(i)
 
        if any(matr[e, k] != 0 for e in range(i - 1, -1, -1)):
            for e in range(i - 1, -1, -1):
                ll = np.lcm(matr[i, k], matr[e, k])
                if ll != matr[e, k]:
                    linebreak = print_op(multiply(e, ll // matr[e, k]), linebreak)
            linebreak = print_op(subtract(i, True), linebreak)
            return True, linebreak
    return False, linebreak
 
 
def gauss():
    print(matrix_to_latex(False))
    linebreak = True
    normalized_lines = 0
    while normalized_lines < n:
        lines_diff, linebreak_new = gauss_step(normalized_lines, linebreak)
        normalized_lines += lines_diff
        linebreak = linebreak_new
    return linebreak
 
 
def normalize(linebreak):
    while True:
        diff, linebreak_new = normalize_step(linebreak)
        if not diff:
            break
        linebreak = linebreak_new
 
 
def main():
    normalize(gauss())
 
 
if __name__ == '__main__':
    main()

Comments