I added to the code linked above and made it into an @interact that takes one all the way to reduced echelon form:
(a formatting issue is having one of the @interacts not in the code box, and messing with the indentation a bit. Be sure to copy-paste the hanging @interact and indent in the nested one.)
@interact
def _(row = slider([1..10], label='rows', default = 3) , col = slider([1..10], label='columns', default = 3)):
@interact(layout=dict(top=[['M', 'b']]))
def gauss_method(b= random_matrix(QQ,nrows = row, ncols = 1, algorithm='echelonizable', rank = 1), M=random_matrix(QQ,nrows = row, ncols = col, algorithm='echelonizable', rank = min(row,col)),rescale_leading_entry=True ):
M=M.augment(b, subdivide = True)
N=copy(M)
N=N.rref()
num_rows=M.nrows()
num_cols=M.ncols()
print("Reduced echelon form:")
show(N)
print("Steps")
show(M)
col = 0 # all cols before this are already done
for row in range(0,num_rows):
# ?Need to swap in a nonzero entry from below
while (col < num_cols
and M[row][col] == 0):
for i in M.nonzero_positions_in_column(col):
if i > row:
print " R",row+1,"\;\circlearrowright \; R",i+1
M.swap_rows(row,i)
show(M)
break
else:
col += 1
if col >= num_cols:
break
# Now guaranteed M[row][col] != 0
if (rescale_leading_entry
and M[row][col] != 1):
print "",1/M[row][col],"R",row+1
M.rescale_row(row,1/M[row][col])
show(M)
change_flag=False
for changed_row in range(row+1,num_rows):
if M[changed_row][col] != 0:
change_flag=True
factor=-1*M[changed_row][col]/M[row][col]
print "",factor," R",changed_row+1,"+R",changed_row
M.add_multiple_of_row(changed_row,row,factor)
if change_flag:
show(M)
col +=1
print "Above is the echelon form, let's keep cruising to get the reduced echelon form"
for changed_row in range(1,num_rows):
for row in range(0,changed_row):
factor = -1*M[row][changed_row]
print "",factor," R",changed_row+1,"+R",row+1
M.add_multiple_of_row(row,changed_row,factor)
show(M)