Compare commits
No commits in common. "master" and "7ab770e3f6cb45f038aa0f54a967b931f750d507" have entirely different histories.
master
...
7ab770e3f6
23
README.md
23
README.md
@ -1,23 +1,2 @@
|
|||||||
# 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??
|
|
||||||
@ -1,18 +1,6 @@
|
|||||||
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) :
|
||||||
@ -24,11 +12,7 @@ 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
|
||||||
@ -36,66 +20,38 @@ 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 (inmat(rowcol) == a*b)
|
return (sp.Matrix(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
|
||||||
try : d = sp.nsimplify(input("What is the determinant of this matrix?: "))
|
return (det == 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):
|
||||||
# return bool based on if input equals inverse of matrix
|
det = a.det()
|
||||||
print("What is the inverse of this matrix?")
|
if det != 0 :
|
||||||
return (inmat(rowcol) == a.inv())
|
# 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())
|
||||||
|
|
||||||
# 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" :
|
||||||
@ -106,56 +62,24 @@ 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 :
|
||||||
a = genmatrix(rowcol, intmax, dif)
|
# generate a random matrices
|
||||||
b = genmatrix(rowcol, intmax, dif)
|
a = sp.randMatrix(rowcol, rowcol, 0, intmax)
|
||||||
if t == "triang" :
|
b = sp.randMatrix(rowcol, rowcol, 0, intmax)
|
||||||
while True :
|
|
||||||
# generate matrices with smaller integers
|
# if determinant non-zero, radnom value less than difficulty, set a to its inverse
|
||||||
a = genmatrix(rowcol, intmax//rowcol, dif)
|
if a.det() != 0 and random.random() <= dif :
|
||||||
# ensure a is invertible
|
a = a.inv()
|
||||||
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) :
|
||||||
@ -165,7 +89,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", str(datetime.timedelta(seconds=round(tictoc))))
|
print("Correct! You have solved", count, "problems in %.2f seconds" %tictoc)
|
||||||
break
|
break
|
||||||
else :
|
else :
|
||||||
# print failure message
|
# print failure message
|
||||||
@ -173,5 +97,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, diag, triang) ")
|
t = input("What do you want to practice? (mult, det, inv, eig) ")
|
||||||
practice(t)
|
practice(t)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user