ยง Computing the smith normal form
import numpy as np
from numpy import *
import math
def row_for_var(xs, vi: int):
NEQNS, NVARS = xs.shape
for r in range(vi, NVARS):
if xs[r][vi] != 0: return r
def 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 sols
xs = 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)