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()