Skip to content

Commit

Permalink
Added rref.
Browse files Browse the repository at this point in the history
  • Loading branch information
nrubin29 committed Oct 5, 2017
1 parent 32ecc1b commit 1cd9c6d
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 34 deletions.
7 changes: 5 additions & 2 deletions calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Calculator:
def __init__(self):
self.vrs = {}

def evaluate(self, eqtn: str) -> Value:
def evaluate(self, eqtn: str, verbose=True) -> Value:
for e in eqtn.split(';'):
root, remaining_tokens = self._match(self._tokenize(e), 'idt')

Expand All @@ -25,7 +25,10 @@ def evaluate(self, eqtn: str) -> Value:

if isinstance(res, Value):
ast.ast.value = res
print(ast)

if verbose:
print(ast)

return res

elif isinstance(res, dict):
Expand Down
1 change: 1 addition & 0 deletions common.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __repr__(self):
(r'trans', 'OPR'),
(r'cof', 'OPR'),
(r'inv', 'OPR'),
(r'rref', 'OPR'),
(r'[a-zA-Z_]+', 'IDT'),
(r'=', 'EQL'),
(r'\+', 'ADD'),
Expand Down
65 changes: 64 additions & 1 deletion rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def pow(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:


def opr(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.Number, {'sqrt': math.sqrt, 'exp': math.exp, 'det': det, 'trans': trans, 'cof': cof, 'adj': adj, 'inv': inv}[tokens[0].value](tokens[1].value.value))
return Value(Type.Number, {'sqrt': math.sqrt, 'exp': math.exp, 'det': det, 'trans': trans, 'cof': cof, 'adj': adj, 'inv': inv, 'rref': rref}[tokens[0].value](tokens[1].value.value))


def neg(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
Expand Down Expand Up @@ -93,6 +93,69 @@ def inv(matrix: List[List[float]]):
return [[cell * multiplier for cell in row] for row in adj(matrix)]


def rref(matrix: List[List[float]]):
mat = copy.deepcopy(matrix)
row = 0
col = 0

def count_leading_zeroes(row):
for i in range(len(row)):
if row[i] != 0:
return i

return len(row)

# Sort the matrix by the number of 0s in each row with the most 0s going to the bottom.
mat = sorted(mat, key=count_leading_zeroes)

# print(mat)

while row < len(mat) and col < len(mat[row]):
# print(row, mat)

# If there is a leading 0, move column over but remain on the same row.
if mat[row][col] == 0:
col += 1
continue

# Divide each cell in the row by the first cell to ensure that the row starts with a 1.
mat[row] = [cell / mat[row][col] for cell in mat[row]]

# Multiply all lower rows as needed.
for i in range(row + 1, len(mat)):
multiplier = -mat[i][col] / mat[row][col]
mat[i] = [cell + (mat[row][c] * multiplier) for c, cell in enumerate(mat[i])]

row += 1
col += 1

row = len(mat) - 1
col = len(mat[row]) - 1

# print('going back up', row, col)

while row > 0:
# If we have a 0 at this point, we don't need to go back up for this row.
if mat[row][col] == 0:
row -= 1
col -= 1
continue

for i in range(row - 1, -1, -1):
multiplier = -mat[i][col] / mat[row][col]

# print('multiplier', multiplier)

mat[i] = [cell + (mat[row][c] * multiplier) for c, cell in enumerate(mat[i])]

# print('it is now', mat[i])

row -= 1
col -= 1

return mat


calc_map = {
'add': add,
'mul': mul,
Expand Down
85 changes: 54 additions & 31 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@
import random
import unittest

import sympy

from calculator import Calculator


def evaluate(eqtn: str):
print(eqtn)
def evaluate(eqtn: str, verbose=True):
if verbose:
print(eqtn)

calc = Calculator()
res = calc.evaluate(eqtn)
print(res, '\n' + '-' * 50)
res = calc.evaluate(eqtn, verbose)

if verbose:
print(res, '\n' + '-' * 50)

return res.value


Expand Down Expand Up @@ -99,33 +106,49 @@ def runTest(self):

class MatrixTests(unittest.TestCase):
def runTest(self):
self.assertEqual(evaluate('[1,2]'), [[1.0, 2.0]])
self.assertEqual(evaluate('det([1,2,3|4,5,6|7,8,8])'), 3.0)

self.assertEqual(evaluate('[1,2|4,5]'), [[1.0, 2.0], [4.0, 5.0]])
self.assertEqual(evaluate('trans([1,2|4,5])'), [[1.0, 4.0], [2.0, 5.0]])

self.assertEqual(evaluate('inv([1,4,7|3,0,5|-1,9,11])'), [[45/8, -19/8, -5/2], [19/4, -9/4, -2], [-27/8, 13/8, 3/2]])

self.assertEqual(evaluate('[1,0,0|0,1,0|0,0,1]'), [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])

self.assertEqual(evaluate('[1,0,0,0|0,1,0,0|0,0,1,0|0,0,0,1]'), [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])
self.assertEqual(evaluate('det([1,3,5,7|2,4,6,8|9,7,5,4|8,6,5,9])'), 2.0)

self.assertEqual(evaluate('cof([1,2,3|0,4,5|1,0,6])'), [[24, 5, -4], [-12, 3, 2], [-2, -5, 4]])

# Since we have floating-point issues, we have to test each value individually.
calc = evaluate('inv([1,2,3|0,4,5|1,0,6])')
ans = [[12/11, -6/11, -1/11], [5/22, 3/22, -5/22], [-2/11, 1/11, 2/11]]

for row in range(len(calc)):
for col in range(len(calc)):
self.assertAlmostEqual(calc[row][col], ans[row][col])

# for _ in range(10):
# mat = [[random.randint(1, 100) for _ in range(10)] for _ in range(10)]
# mat_str = '[' + '|'.join([','.join(map(str, line)) for line in mat]) + ']'
# self.assertEqual(evaluate(mat_str), mat)
# self.assertEqual(evaluate('[1,2]'), [[1.0, 2.0]])
# self.assertEqual(evaluate('det([1,2,3|4,5,6|7,8,8])'), 3.0)
#
# self.assertEqual(evaluate('[1,2|4,5]'), [[1.0, 2.0], [4.0, 5.0]])
# self.assertEqual(evaluate('trans([1,2|4,5])'), [[1.0, 4.0], [2.0, 5.0]])
#
# self.assertEqual(evaluate('inv([1,4,7|3,0,5|-1,9,11])'), [[45/8, -19/8, -5/2], [19/4, -9/4, -2], [-27/8, 13/8, 3/2]])
#
# self.assertEqual(evaluate('[1,0,0|0,1,0|0,0,1]'), [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
#
# self.assertEqual(evaluate('[1,0,0,0|0,1,0,0|0,0,1,0|0,0,0,1]'), [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])
# self.assertEqual(evaluate('det([1,3,5,7|2,4,6,8|9,7,5,4|8,6,5,9])'), 2.0)
#
# self.assertEqual(evaluate('cof([1,2,3|0,4,5|1,0,6])'), [[24, 5, -4], [-12, 3, 2], [-2, -5, 4]])
#
# # Since we have floating-point issues, we have to test each value individually.
# calc = evaluate('inv([1,2,3|0,4,5|1,0,6])')
# print(calc)
# ans = [[12/11, -6/11, -1/11], [5/22, 3/22, -5/22], [-2/11, 1/11, 2/11]]
#
# for row in range(len(calc)):
# for col in range(len(calc)):
# self.assertAlmostEqual(calc[row][col], ans[row][col])

# self.assertEqual(evaluate('rref([1,2,3|4,5,6|7,8,8])'), [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
# self.assertEqual(evaluate('rref([1,2,4|4,7,6|7,1,8])'), [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
self.assertEqual(evaluate('rref([1,2,3|4,5,6|4,5,6])'), [[1, 0, -1], [0, 1, 2], [0, 0, 0]])
# self.assertEqual(evaluate('rref([1,2,3|4,5,6|7,8,9])'), [[1, 0, -1], [0, 1, 2], [0, 0, 0]])

for r_dim in range(3, 10):
print(r_dim)

for _ in range(10):
mat = [[random.randint(0, 100) for _ in range(r_dim)] for _ in range(r_dim)]
mat_str = '[' + '|'.join([','.join(map(str, line)) for line in mat]) + ']'

# print('*****<')
# print(sympy.Matrix(mat))
# print(sympy.Matrix(evaluate('rref({})'.format(mat_str), False)))
# print(sympy.Matrix(mat).rref()[0])
# print('>*****')

self.assertTrue(sympy.Matrix(evaluate('rref({})'.format(mat_str), False)).equals(sympy.Matrix(mat).rref()[0]))


class RandomTests(unittest.TestCase):
Expand Down

0 comments on commit 1cd9c6d

Please sign in to comment.