Compare commits

...

11 Commits

2 changed files with 120 additions and 23 deletions

View File

@ -1,2 +1,23 @@
# LinAlg-Practice # LinAlg-Practice
TUI program to practice linear algebra computations (multiplications, determinants, inverses, eigenvalues, etc). Written in python by leveraging the sympy library. TUI program to practice linear algebra computations (multiplications, determinants, inverses, eigenvalues, etc). Written in python by leveraging the sympy library.
## Usage
To use: run the program with your favourite python interpreter
```sh
python linalg-practice.py
```
You will be prompted for selecting which settings you want to use
## Features
* Multiplication of two matrices
* Determinant computation
* Inverse computation
* Eigenvalue computation
* Finding diagonalisations
* Finding triangularisations
## Planned:
* Linear systems
* Row-echelon form
* GUI??

View File

@ -1,6 +1,18 @@
import sympy as sp import sympy as sp
import time import time
import datetime
import random import random
import readline
errs = (ValueError, TypeError)
def genmatrix(rowcol, intmax, dif) :
# generate a random matrices
a = sp.randMatrix(rowcol, rowcol, -intmax, intmax)
# if determinant non-zero, radnom value less than difficulty, set a to its inverse
if a.det() != 0 and random.random() <= dif :
a = a.inv()
return a
# in function to take arbitrary matrix input from user # in function to take arbitrary matrix input from user
def inmat(rowcol) : def inmat(rowcol) :
@ -12,7 +24,11 @@ def inmat(rowcol) :
mat[i]=input().split(" ") mat[i]=input().split(" ")
for j in range(len(mat[i])) : for j in range(len(mat[i])) :
# convert list using nsimplify in order to take rational number symbolically # convert list using nsimplify in order to take rational number symbolically
try :
mat[i][j] = sp.nsimplify(mat[i][j]) mat[i][j] = sp.nsimplify(mat[i][j])
except errs : return False
try : mat = sp.Matrix(mat)
except errs : return False
return mat return mat
# multcheck function to check if two matrices are multiplied together # multcheck function to check if two matrices are multiplied together
@ -20,38 +36,66 @@ def multcheck(a, b, rowcol, intmax) :
sp.pprint(b) sp.pprint(b)
print("Multiply these two matrices together") print("Multiply these two matrices together")
# return bool based on if input equals the two matrices multiplied together # return bool based on if input equals the two matrices multiplied together
return (sp.Matrix(inmat(rowcol)) == a*b) return (inmat(rowcol) == a*b)
# detcheck function to check if the determinant of the matrix is correct # detcheck function to check if the determinant of the matrix is correct
def detcheck(a, b, rowcol, intmax): def detcheck(a, b, rowcol, intmax):
det = sp.det(a) det = sp.det(a)
# return bool based on if input equals determinant # return bool based on if input equals determinant
return (det == sp.nsimplify(input("What is the determinant of this matrix?: "))) try : d = sp.nsimplify(input("What is the determinant of this matrix?: "))
except errs : return False
return (det == d)
# invcheck function to check if the inverse of the matrix is correct # invcheck function to check if the inverse of the matrix is correct
def invcheck(a, b, rowcol, intmax): def invcheck(a, b, rowcol, intmax):
det = a.det()
if det != 0 :
# return bool based on if input equals inverse of matrix # return bool based on if input equals inverse of matrix
print("What is the inverse of this matrix?") print("What is the inverse of this matrix?")
return (sp.Matrix(inmat(rowcol)) == a.inv()) return (inmat(rowcol) == a.inv())
# eigcheck function to check if the eigenvalues are correct # eigcheck function to check if the eigenvalues are correct
def eigcheck(a, b, rowcol, intmax): def eigcheck(a, b, rowcol, intmax):
eigs = a.eigenvals() eigs = a.eigenvals()
for i in range(len(eigs)) : for i in range(len(eigs)) :
try :
val = sp.nsimplify(input("Input eigenvalue: ")) val = sp.nsimplify(input("Input eigenvalue: "))
if not (val in eigs and eigs[val] == sp.nsimplify(input("Input its algebraic multiplicity: "))) : algm = sp.nsimplify(input("Input its algebraic multiplicity: "))
except errs : return False
if not (val in eigs and eigs[val] == algm) :
# return false if the eigenvalue not in dictionary and wrong alg multiplicity # return false if the eigenvalue not in dictionary and wrong alg multiplicity
return False return False
return True return True
def diagcheck(a, b, rowcol, intmax):
return (a.diagonalize()[1] == inmat(rowcol))
# pascalmat function to generate pascal matrices (used for generating unimodular matrices)
def pascalmat(n) :
mat = []
# generate rows of binomial coefficients
for i in range(n) :
mat.append(sp.binomial_coefficients_list(i) + [0]*(n-1-i))
mat = sp.Matrix(mat)
# make a lower triangular pascal matrix
lmat = mat.transpose()
rand = random.random()
# randomly pick either lower or upper triangular pascal matrix
if rand <= 1/2 :
mat = lmat
return mat
def triangcheck(a, b, rowcol, intmax) :
print("Input triangularised matrix,")
T = inmat(rowcol)
print("Input basis change matrix (from standard basis)")
P_inv = inmat(rowcol)
# check if P_inv is invertible
if P_inv.det() == 0 : return False
# return false if T is not upper triangular and not similar to the original matrix
return (T.is_upper and a == P_inv.inv()*T*P_inv)
# practice function # practice function
def practice(t) : def practice(t) :
count = 0 count = 0
rowcol = int(input("What size of matrix do you want to practice with? "))
intmax = int(input("What maximum size of integer do you want the matrix to be made out of? "))
dif = float(input("What difficulty (probability for a matrix of rational values between 0, 1) do you want? "))
# choose the function of the program that you want # choose the function of the program that you want
if t == "mult" : if t == "mult" :
@ -62,24 +106,56 @@ def practice(t) :
f = invcheck f = invcheck
elif t == "eig" : elif t == "eig" :
f = eigcheck f = eigcheck
elif t == "diag" :
f = diagcheck
elif t == "triang" :
f = triangcheck
else : else :
exit() exit()
while True :
try :
rowcol = abs(int(input("What size of matrix do you want to practice with? ")))
intmax = abs(int(input("What maximum size of integer do you want the matrix to be made out of? ")))
dif = float(input("What difficulty (probability for a matrix of rational values between 0, 1) do you want? "))
break
except errs:
continue
# initialise time measurement # initialise time measurement
tic = time.perf_counter() tic = time.perf_counter()
# infinite loop of practice # infinite loop of practice
while True : while True :
# generate a random matrices a = genmatrix(rowcol, intmax, dif)
a = sp.randMatrix(rowcol, rowcol, 0, intmax) b = genmatrix(rowcol, intmax, dif)
b = sp.randMatrix(rowcol, rowcol, 0, intmax) if t == "triang" :
while True :
# if determinant non-zero, radnom value less than difficulty, set a to its inverse # generate matrices with smaller integers
if a.det() != 0 and random.random() <= dif : a = genmatrix(rowcol, intmax//rowcol, dif)
a = a.inv() # ensure a is invertible
if a.det() == 0 : continue
# find a non-fractional upper trianagular matrix (ensures triangularisability)
c = a.LUdecompositionFF()[3]
croots = {k: k for k in sp.roots(c.charpoly()) if k not in sp.roots(c.charpoly(), filter='Z')}
# make sure only integer roots and c is not diagonalisable
if not (len(croots) != 0 or c.is_diagonalizable()) :
a = c
pmat = pascalmat(rowcol)
# multiply by a pascal matrix to get a similar matrix with nice numbers
a = pmat.inv()*a*pmat
if a.is_upper: continue
break
# infinite loop until user succeeds # infinite loop until user succeeds
while True : while True :
# if diagcheck, make sure the matrix is diagonalizable
if t == "diag" :
while not a.is_diagonalizable :
a = genmatrix(rowcol, intmax, dif)
if t == "inv" :
while a.det() == 0 :
a = genmatrix(rowcol, intmax, dif)
sp.pprint(a) sp.pprint(a)
# if return of function is True # if return of function is True
if f(a, b, rowcol, intmax) : if f(a, b, rowcol, intmax) :
@ -89,7 +165,7 @@ def practice(t) :
# increment count # increment count
count += 1 count += 1
# print success message # print success message
print("Correct! You have solved", count, "problems in %.2f seconds" %tictoc) print("Correct! You have solved", count, "problems in", str(datetime.timedelta(seconds=round(tictoc))))
break break
else : else :
# print failure message # print failure message
@ -97,5 +173,5 @@ def practice(t) :
continue continue
# take input from user on the type of practice they want to do # take input from user on the type of practice they want to do
t = input("What do you want to practice? (mult, det, inv, eig) ") t = input("What do you want to practice? (mult, det, inv, eig, diag, triang) ")
practice(t) practice(t)