import numpy as npfrom numpy import *import mathdef row_for_var(xs, vi: int): NEQNS, NVARS = xs.shape for r in range(vi, NVARS): if xs[r][vi] != 0: return rdef elim_scale_factor(x: int, y: int): return (y, x)def smith_normal_form(xs, ys): NEQNS, NVARS = xs.shape assert(NEQNS == ys.shape[0]) for vi in range(NVARS): ri = row_for_var(xs, vi) if ri is None: return (f"unable to find non-zero row for variable: {vi}") print(f"-eliminating variable({vi}) using row ({ri}:{xs[ri]})") for r2 in range(NEQNS): if r2 == ri: continue (scale_ri, scale_r2) = elim_scale_factor(xs[ri][vi], xs[r2][vi]) print(f"-computing xs[{r2}] = {scale_r2}*xs[{r2}]:{xs[r2]} - {scale_ri}*xs[{ri}]:{xs[ri]}") xs[r2] = scale_r2 * xs[r2] - scale_ri * xs[ri] ys[r2] = scale_r2 * ys[r2] - scale_ri * ys[ri] print(f"-state after eliminating variable({vi})") print(f"xs:\n{xs}\n\nys:{ys}") sols = [None for _ in range(NVARS)] for vi in range(NVARS): r = row_for_var(xs, vi) if r is None: print(f"unable to find row for variable {vi}") return None assert(xs[r][vi] != 0) if ys[r] % xs[r][vi] != 0: print(f"unable to solve eqn for variable {vi}: xs:{xs[r]} = y:{ys[r]}") return None else: sols[vi] = ys[r] // xs[r][vi] for r in range(NEQNS): lhs = 0 for i in range(NVARS): lhs += xs[r][i] * sols[i] if lhs != ys[r]: print(f"-solution vector sols:{sols} cannot satisfy row xs[{r}] = ys[{r}]:{xs[r]} = {ys[i]}") return None return solsxs = np.asarray([[1, 1], [1, -1]])ys = np.asarray([10, 2])print("## CONSISTENT ##")out = smith_normal_form(xs,ys)print("xs:\n%s\n\nys:\n%s\n\nsoln:\n%s" % (xs, ys, out,))xs = np.asarray([[1, 1], [1, -1], [1, 2]])ys = np.asarray([10, 2, 14])print("## CONSISTENT OVER DETERMINED ##")out = smith_normal_form(xs,ys)print("xs:\n%s\n\nys:\n%s\n\nsoln:\n%s" % (xs, ys, out,))xs = np.asarray([[1, 1], [1, -1], [1, 2]])ys = np.asarray([10, 2, 14])print("## CONSISTENT UNDER DETERMINED ##")out = smith_normal_form(xs,ys)print("xs:\n%s\n\nys:\n%s\n\nsoln:\n%s" % (xs, ys, out,))xs = np.asarray([[1, 1], [1, -1], [1, 2]])ys = np.asarray([10, 2, 1])print("## INCONSISTENT (OVER DETERMINED) ##")out = smith_normal_form(xs,ys)xs = np.asarray([[1, -1], [1, 2], [1, 1]])ys = np.asarray([10, 2, 1])print("## INCONSISTENT (OVER DETERMINED) ##")out = smith_normal_form(xs,ys)xs = np.asarray([[1, 1], [1, -1]])ys = np.asarray([1, 0])print("## INCONSISTENT (SOLVABLE OVER Q NOT Z) ##")out = smith_normal_form(xs,ys)