Skip to content

Commit

Permalink
Objected Oriented Matrix Operations of exisiting code
Browse files Browse the repository at this point in the history
  • Loading branch information
rahulranjansah committed Apr 14, 2024
1 parent b6a102b commit 7106b39
Showing 1 changed file with 297 additions and 0 deletions.
297 changes: 297 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
from sympy import Matrix, latex, pprint, init_printing, shape
init_printing(use_unicode=True)

class MatrixInputValidator:
@staticmethod
def validate_positive_input(prompt):
"""Decorator to validate positive integer inputs."""
def decorator(func):
def wrapper(*args, **kwargs):
while True:
value = input(prompt)
try:
value = int(value)
if value > 0:
return func(value, *args, **kwargs)
else:
print("Please enter a positive integer.")
except ValueError:
print("Invalid input. Please enter an integer.")
return wrapper
return decorator

@validate_positive_input("No. of unique matrices undergoing operations: ")
def get_matrix_count(value):
return value

@validate_positive_input("No. of rows: ")
def get_rows(value):
return value

@validate_positive_input("No. of columns: ")
def get_columns(value):
return value

class MatrixBuilder:
def __init__(self):
self.matrices = []

def create_matrix(self, rows, columns):
matrix = []
for i in range(rows):
row = []
for j in range(columns):
entry = input(f"Enter value for Row {i+1}, Column {j+1}: ")
row.append(entry)
matrix.append(row)
return Matrix(matrix)

# def add_matrices(self, matrix1, matrix2):
# return matrix1 + matrix2

# def subtract_matrices(self, matrix1, matrix2):
# return matrix1 - matrix2

# def multiply_matrices(self, matrix1, matrix2):
# return matrix1 * matrix2

def build_matrix(self):
matrix_count = MatrixInputValidator.get_matrix_count()
for _ in range(matrix_count):
rows = MatrixInputValidator.get_rows()
columns = MatrixInputValidator.get_columns()
matrix = self.create_matrix(rows, columns)
self.matrices.append(matrix)
return self.matrices

def display_matrix(self):
for en_matrix in enumerate(self.matrices):
pprint(en_matrix)

class MatrixOperations:
def __init__(self, builder):
self.builder = builder

def add_subtract_matrix(self):
"""
Sum/Subtracts n numbers a*b matrix with same dimensions together
Additional feature for latex support
"""
matrix_list = self.builder.matrices
matrix_num = int(input("How many matrix participates in operation? "))
latex_operation = []

# first index defines what is the dimension of matrix after operation
first_index = int(input("Left-most matrix index: "))
first_matrix = matrix_list[first_index]

latex_operation.append(first_matrix)
# empty matrix initialize, print index on screen, and rows cols initialize
operation_sum_sub = first_matrix

for _ in range(matrix_num - 1):
index = int(input("Index of matrix to the right: "))
operation_type = input("What operation? Add[A] Subtract[S]:: ").upper().strip()

# check dimensions of the matrix
if (matrix_list[index].rows == first_matrix.rows
and matrix_list[index].cols == first_matrix.cols):

if operation_type == "A":
operation_sum_sub += matrix_list[index]
latex_operation.append("+")
latex_operation.append(matrix_list[index])

elif operation_type == "S":
operation_sum_sub -= matrix_list[index]
latex_operation.append("-")
latex_operation.append(matrix_list[index])

else:
raise ValueError("Dimension out of range")

else:
raise ValueError("Error Row and Column input")

pprint(latex_operation)
pprint(operation_sum_sub)

return operation_sum_sub, latex_operation

def dot_product_matrix(self):
"""
Dot product of n numbers of a*b matrix with proper dimension
Latex based output with intermediate steps and final solution
"""
matrix_list = self.builder.matrices
matrix_num = int(input("How many matrix participates in operation? "))

# latex print of all matrix
for matrix in matrix_list:
with open("output.txt", "a", encoding="utf-8") as output_file:
output_file.write("$"+ latex(matrix) + "$\n")

with open("output.txt", "a", encoding="utf-8") as output_file:
output_file.write(r"\\By law of commutativity, dot product of matrices right to left, \\")

# first index defines what is the dimension of matrix after operation
initialize_product = matrix_list[int(input("Which will be your Rightmost matrix: "))]

# intermediate method print
for _ in range(matrix_num-1):

index = int(input("Inner matrix index: "))

# intermediate steps
steps = ["="]
outer_product = initialize_product.T
_, symbol_count = outer_product.shape
outer_product = outer_product.tolist()
i = 0

for element in outer_product:
for atom, column in zip(element, range(matrix_list[index].cols)):
step = str(latex(atom)) + str(latex(matrix_list[index].col(column)))
steps.append(step)
i += 1
if i % symbol_count != 0:
steps.append("+")
else:
steps.append("\\hspace{0.5cm}")
print()

# check dimensions of the matrix

if matrix_list[index].cols == initialize_product.rows:
initialize_product = matrix_list[index]*(initialize_product)
else:
print("Dimension out of range")

for _ in steps:
with open("output.txt", "a", encoding="utf-8") as output_file:
output_file.write("\n$" + str(_) + "$")

print(steps)

return initialize_product

def reducedref_matrix(self):
matrix_list = self.builder.matrices
index = int(input("Index of the matrix to rref:: "))
rref_matrix = matrix_list[index]
rref_matrix_row, rref_matrix_col = shape(rref_matrix)
_, pivot = rref_matrix.rref()

# RREFing even when we have a first row starts at zero (latex left) by row-swap
if rref_matrix[0,0] == 0:
for i in range(rref_matrix_row):
if rref_matrix[i,0] != 0:
holder = rref_matrix[0,:]
rref_matrix[0,:] = rref_matrix[i,:]
rref_matrix[i,:] = holder
else:
continue

with open("rref.tex", "w", encoding="utf-8") as output_file:
output_file.write("$$"+ latex(rref_matrix) + "$$\n")

for i in range(min(rref_matrix_row, rref_matrix_col)):
if rref_matrix[i,i] == 0:
pass
else:
with open("rref1.tex", "a", encoding="utf-8") as output_file:
output_file.write(f"$$\\frac{(1)}{({rref_matrix[i,i]})} R_{{{i+1}}} \\rightarrow R_{{{i+1}}}$$\n")
rref_matrix[i, :] = (rref_matrix[i,:]/rref_matrix[i,i])

# if you want to have REF forms only then,
# if j >= i

for j in range(rref_matrix_row):
if j == i:
pass
else:
# Write the operation to the LaTeX file
with open("rref1.tex", "a", encoding="utf-8") as output_file:
output_file.write(f"$$R_{{{j+1}}} - ({rref_matrix[j,i]}) \\cdot R_{{{i+1}}} \\rightarrow R_{{{j+1}}}$$\n")

rref_matrix[j,:] = rref_matrix[j,:] - (rref_matrix[j,i]*rref_matrix[i,:])
with open("rref1.tex", "a", encoding="utf-8") as output_file:
# output_file.write("$\\longrightarrow$\n")
output_file.write("$$"+ latex(rref_matrix) + "$$\n")

with open("rref1.tex", "a", encoding="utf-8") as output_file:
# output_file.write("$\\longrightarrow$\n")
output_file.write(f"$$Pivot:"+ str(pivot) + "$$\n")

def rowef_matrix(self):
matrix_list = self.builder.matrices
index = int(input("Index of the matrix to rref:: "))
ref_matrix = matrix_list[index]
ref_matrix_row, ref_matrix_col = shape(ref_matrix)
_, pivot = ref_matrix.rref()

with open("rref.tex", "w", encoding="utf-8") as output_file:
output_file.write("$$"+ latex(ref_matrix) + "$$\n")

for i in range(min(ref_matrix_row, ref_matrix_col)):
with open("rref1.tex", "a", encoding="utf-8") as output_file:
output_file.write(f"$$\\frac{(1)}{({ref_matrix[i,i]})} R_{{{i+1}}} \\rightarrow R_{{{i+1}}}$$\n")
ref_matrix[i, :] = (ref_matrix[i,:]/ref_matrix[i,i])

for j in range(ref_matrix_row):
if j >= i:
pass
else:
# Write the operation to the LaTeX file
with open("rref1.tex", "a", encoding="utf-8") as output_file:
output_file.write(f"$$R_{{{j+1}}} - ({ref_matrix[j,i]}) \\cdot R_{{{i+1}}} \\rightarrow R_{{{j+1}}}$$\n")

ref_matrix[j,:] = ref_matrix[j,:] - (ref_matrix[j,i]*ref_matrix[i,:])
with open("rref1.tex", "a", encoding="utf-8") as output_file:
# output_file.write("$\\longrightarrow$\n")
output_file.write("$$"+ latex(ref_matrix) + "$$\n")

with open("rref1.tex", "a", encoding="utf-8") as output_file:
# output_file.write("$\\longrightarrow$\n")
output_file.write(f"$$Pivot:"+ str(pivot) + "$$\n")

class OperationKey:
def __init__(self, builder):
self.builder = builder
self.operations = MatrixOperations(builder)

def choosekey(self):
key = input("Choose Operation Key SUM/SUBTRACT or PRODUCT or RREF or REF [S/P/RR/R]:: ").upper().strip()
if key in (["S", "P", "RR", "R"]):
if key == "S":
self.operations.add_subtract_matrix()
elif key == "P":
self.operations.dot_product_matrix()
elif key == "RR":
self.operations.reducedref_matrix()
elif key == "R":
self.operations.rowef_matrix()
else:
print("Wrong Key")

def main():

builder = MatrixBuilder()
builder.build_matrix()
builder.display_matrix()

MatrixOperations(builder)
operartionkey = OperationKey(builder)
operartionkey.choosekey()



# result, latex_operation = operations.add_subtract_matrix()
# pprint(latex_operation)
# pprint(result)

# dot_product = operations.dot_product_matrix()
# pprint(dot_product)

if __name__ == "__main__":
main()

0 comments on commit 7106b39

Please sign in to comment.