Compare commits

...

11 Commits

2 changed files with 120 additions and 23 deletions

View File

@ -1,2 +1,23 @@
# 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 time
import datetime
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
def inmat(rowcol) :
@ -12,7 +24,11 @@ def inmat(rowcol) :
mat[i]=input().split(" ")
for j in range(len(mat[i])) :
# convert list using nsimplify in order to take rational number symbolically
mat[i][j] = sp.nsimplify(mat[i][j])
try :
mat[i][j] = sp.nsimplify(mat[i][j])
except errs : return False
try : mat = sp.Matrix(mat)
except errs : return False
return mat
# multcheck function to check if two matrices are multiplied together
@ -20,38 +36,66 @@ def multcheck(a, b, rowcol, intmax) :
sp.pprint(b)
print("Multiply these two matrices 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
def detcheck(a, b, rowcol, intmax):
det = sp.det(a)
# 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
def invcheck(a, b, rowcol, intmax):
det = a.det()
if det != 0 :
# return bool based on if input equals inverse of matrix
print("What is the inverse of this matrix?")
return (sp.Matrix(inmat(rowcol)) == a.inv())
# return bool based on if input equals inverse of matrix
print("What is the inverse of this matrix?")
return (inmat(rowcol) == a.inv())
# eigcheck function to check if the eigenvalues are correct
def eigcheck(a, b, rowcol, intmax):
eigs = a.eigenvals()
for i in range(len(eigs)) :
val = sp.nsimplify(input("Input eigenvalue: "))
if not (val in eigs and eigs[val] == sp.nsimplify(input("Input its algebraic multiplicity: "))) :
try :
val = sp.nsimplify(input("Input eigenvalue: "))
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
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
def practice(t) :
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
if t == "mult" :
@ -62,24 +106,56 @@ def practice(t) :
f = invcheck
elif t == "eig" :
f = eigcheck
elif t == "diag" :
f = diagcheck
elif t == "triang" :
f = triangcheck
else :
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
tic = time.perf_counter()
# infinite loop of practice
while True :
# generate a random matrices
a = sp.randMatrix(rowcol, rowcol, 0, intmax)
b = sp.randMatrix(rowcol, rowcol, 0, 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()
a = genmatrix(rowcol, intmax, dif)
b = genmatrix(rowcol, intmax, dif)
if t == "triang" :
while True :
# generate matrices with smaller integers
a = genmatrix(rowcol, intmax//rowcol, dif)
# 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
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)
# if return of function is True
if f(a, b, rowcol, intmax) :
@ -89,7 +165,7 @@ def practice(t) :
# increment count
count += 1
# 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
else :
# print failure message
@ -97,5 +173,5 @@ def practice(t) :
continue
# 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)