Skip to content

Commit

Permalink
Added QR factorization.
Browse files Browse the repository at this point in the history
  • Loading branch information
nrubin29 committed Dec 24, 2017
1 parent 669c861 commit 27d7f9d
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
1 change: 1 addition & 0 deletions common.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def _str(self, node, depth=0) -> str:
(r'solve', 'OPR'),
(r'eval', 'OPR'),
(r'ls', 'OPR'),
(r'qr', 'OPR'),
(r'[a-zA-Z_]+', 'IDT'),
(r'=', 'EQL'),
(r'\+', 'ADD'),
Expand Down
6 changes: 3 additions & 3 deletions rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import List

from common import Token
from vartypes import VariableValue, NumberValue, MatrixRowValue, MatrixValue, Value, OperatorBodyValue
from vartypes import VariableValue, NumberValue, MatrixRowValue, MatrixValue, Value, TupleValue


def flatten(l):
Expand Down Expand Up @@ -35,8 +35,8 @@ def mbd(values: List[Value], _) -> MatrixValue:
return MatrixValue(values)


def opb(values: List[Value], _) -> OperatorBodyValue:
return OperatorBodyValue(values)
def opb(values: List[Value], _) -> TupleValue:
return TupleValue(values)


def add(operands: List[Value], operator: Token) -> Value:
Expand Down
61 changes: 58 additions & 3 deletions vartypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ def exp(self):
def identity(self):
return MatrixValue([[1 if col is row else 0 for col in range(int(self.value))] for row in range(int(self.value))])

def zeroes(self, other):
return MatrixValue([[0 for _ in range(int(other.value))] for _ in range(int(self.value))])


class MatrixValue(Value):
def __init__(self, data):
Expand All @@ -123,13 +126,25 @@ def __init__(self, data):
def __str__(self):
return '[\n' + '\n'.join(['[' + ', '.join(map(lambda cell: str(round(cell, 5)), row)) + ']' for row in self.value]) + '\n]'

def sub(self, other):
if isinstance(other, MatrixValue):
if len(self.value) != len(other.value) or len(self.value[0]) != len(other.value[0]):
raise EvaluationException('Attempted to subtract two matrices of different dimensions')

return MatrixValue([[self.value[row][col] - other.value[row][col] for col in range(len(self.value[row]))] for row in range(len(self.value))])

raise EvaluationException('Cannot sub {} and {}'.format(self.type, other.type))

def mul(self, other):
if isinstance(other, NumberValue):
# Number * Matrix
# Matrix * Number
return MatrixValue([[cell * other.value for cell in row] for row in self.value])

elif isinstance(other, MatrixValue):
# Matrix * Matrix
if len(self.value[0]) != len(other.value):
raise EvaluationException('Cannot multiply matrices of dimensions {} and {}'.format((len(self.value), len(self.value[0])), (len(other.value), len(other.value[0]))))

result = [[0 for _ in range(len(other.value[0]))] for _ in range(len(self.value))]

for i in range(len(self.value)):
Expand All @@ -141,7 +156,15 @@ def mul(self, other):

else:
raise EvaluationException('Cannot mul {} and {}'.format(self.type, other.type))


def div(self, other):
if isinstance(other, NumberValue):
# Matrix / Number
return MatrixValue([[cell / other.value for cell in row] for row in self.value])

else:
raise EvaluationException('Cannot div {} and {}'.format(self.type, other.type))

def det(self):
return NumberValue(self._det(self.value))

Expand Down Expand Up @@ -207,6 +230,38 @@ def solve(self, other):
def ls(self, other):
return (self.trans().mul(self)).inv().mul(self.trans()).mul(other)

def norm(self):
return NumberValue(math.sqrt(sum([sum([col * col for col in row]) for row in self.value])))

def squeeze(self):
return MatrixValue([[cell for row in self.value for cell in row]])

def _col(self, col):
""" Isolates an individual column from the matrix """
return MatrixValue([[row[col]] for row in self.value])

def qr(self):
m = NumberValue(len(self.value))
n = NumberValue(len(self.value[0]))

Q = m.zeroes(m).value
R = n.zeroes(n).value

for j in range(n.value):
v = self._col(j)

for i in range(j):
R[i][j] = MatrixValue(Q)._col(i).trans().mul(self._col(j)).value[0][0]
v = v.squeeze().sub(MatrixValue(Q)._col(i).trans().mul(NumberValue(R[i][j])))

R[j][j] = v.norm().value

val = v.div(NumberValue(R[j][j])).squeeze().value[0]
for row in range(len(Q)):
Q[row][j] = val[row]

return TupleValue([Q, R])


class MatrixRowValue(Value):
def __init__(self, data):
Expand All @@ -219,7 +274,7 @@ def __init__(self, data):
self.value = data


class OperatorBodyValue(Value):
class TupleValue(Value):
def __init__(self, args: List):
super().__init__()

Expand Down

0 comments on commit 27d7f9d

Please sign in to comment.