def from_mtx(file_in, file_out): """ Generates a binary file named file_out which represents the SparseMatrix generated from the .mtx file named file_in. """ file = open(file_in, "r") #Opening file_in in reading mode line = file.readline() #Reading the first line which is a comment line = file.readline( ) #Reading the second line which contains rowRank, colRank, and number of entries #Extracting rowRank and colRank line = line.split() rowRank = int(line[0]) colRank = int(line[1]) num_elem = int(line[2]) #Initializing a SparseMatrix A_sparse = SparseMatrix(rowRank, colRank) #Reading the remainder of the file_in file to complete the SparseMatrix for i in range(1, num_elem + 1): #Loop for reading till the end of file_in # Extracting the row, column, and the value of the element. line = file.readline() line = line.split() row_coord = int(line[0]) - 1 col_coord = int(line[1]) - 1 value = np.float64(line[2].strip("\n")) A_sparse.addElement(row_coord, col_coord, value) #Finished reading file_in file.close() #Creating a binary file and dumping the SparseMatrix A_sparse in it file = open(file_out, "wb") pickle.dump(A_sparse, file) file.close()
class WilkinsonTestPartI(unittest.TestCase): """ Test suite for part I, when ground truth is known. """ def setUp(self): self.A = [[1, 2, 0, 0, 3], [4, 5, 6, 0, 0], [0, 7, 8, 0, 9], [0, 0, 0, 10, 0], [11, 0, 0, 0, 12]] self.x = [[5], [4], [3], [2], [1]] self.x_full = FullMatrix(5, 1) self.A_full = FullMatrix(5, 5) self.A_sparse = SparseMatrix(5, 5) for i in range(5): self.x_full.addElement(i, 0, self.x[i][0]) for j in range(5): self.A_full.addElement(i, j, self.A[i][j]) self.A_sparse.addElement(i, j, self.A[i][j]) self.A_full.augment(self.x_full) self.A_sparse.augment(self.x_full) def test_rowPermute(self): self.A_full.rowPermute(0, 2) self.A_full.rowPermute(0, 4) self.A_sparse.rowPermute(0, 2) self.A_sparse.rowPermute(0, 4) self.assertTrue(norm2(self.A_full, self.A_sparse) == 0.0) def test_rowScale(self): self.A_full.rowScale(0, 3, 3) self.A_full.rowScale(4, 1, -4.4) self.A_sparse.rowScale(0, 3, 3) self.A_sparse.rowScale(4, 1, -4.4) self.assertTrue(norm2(self.A_full, self.A_sparse) == 0.0) def test_productAx(self): x = self.A_full.deaugment() self.A_sparse.deaugment() full = self.A_full.productAx(x) sparse = self.A_sparse.productAx(x) self.assertTrue(norm2(full, sparse) == 0.0) def test_combined(self): self.A_full.rowPermute(0, 2) self.A_full.rowPermute(0, 4) self.A_sparse.rowPermute(0, 2) self.A_sparse.rowPermute(0, 4) self.A_full.rowScale(0, 3, 3) self.A_full.rowScale(4, 1, -4.4) self.A_sparse.rowScale(0, 3, 3) self.A_sparse.rowScale(4, 1, -4.4) x = self.A_sparse.deaugment() self.A_full.deaugment() full = self.A_full.productAx(x) sparse = self.A_sparse.productAx(x) self.assertTrue(norm2(full, sparse) == 0.0)
for i in range (1,num_elem+1): #Loop for reading till the end of memplus.mtx #Print for every 1000 elements added if i%1000 == 0: print ("Added %d elements." %i) ''' Reading the file and extracting the row, column, and the value of the element. ''' line = file.readline() line = line.split() row_coord = int(line[0]) - 1 col_coord = int(line[1]) - 1 value = float(line[2].strip("\n")) A_sparse.addElement(row_coord,col_coord,value) #Finished reading the file file.close() print ("Added %d elements." %i) print ("SparseMatrix generation complete.") #Creating a binary file and dumping the SparseMatrix in it file = open("memplus_sparse.bin","wb") pickle.dump(A_sparse, file) file.close() ''' Verification of the binary file - Load the binary file and check the length
class Jacobi_Solver: """ An instance is a representation of the linear system to be solved using the Jacobi iterative method. """ def __init__(self, A, b, x0=0, tol=10**-9, max_iter=10**100): """ Initializes the matrix A, column matrix b, initial guess x0, tolerance, and maximum number of iterations max_iter. D_inv is the inverse of the diagonal matrix D obtained from the diagonal elements of A. R is the matrix obtained from (A - D) which is equivalent to (L+U) Db is the product obtained from the matrix multiplication of D_inv and b. """ self.A = copy.deepcopy(A) self.b = b self.n = A.colRank if x0 == 0: self.x0 = FullMatrix(self.n, 1) else: self.x0 = x0 self.tol = tol self.max_iter = max_iter self.D_inv = SparseMatrix(self.n, self.n) self.R = copy.deepcopy(A) for i in range(self.n): aii = A.retrieveElement(i, i) self.D_inv.addElement(i, i, 1 / aii) self.R.deleteElement(i, i) self.Db = self.D_inv.productAx(self.b) self.x = False def one_iter(self): """ One iteration of the Jacobi method. """ a = self.D_inv.productAx(self.R.productAx(self.x0)) x = FullMatrix(self.n, 1) for i in range(self.n): t = -1 * a.retrieveElement(i, 0) + self.Db.retrieveElement(i, 0) x.addElement(i, 0, t) return x def norm2(self, mat1, mat2): """ Calculates the second norm of [mat1 - mat2]. mat1: A matrix in either full or sparse format mat2: A matrix in either full or sparse format Returns: Frobenius second norm of the matrix (mat1 - mat2) """ result = 0 for i in range(mat1.rowRank): for k in range(mat2.colRank): a1 = mat1.retrieveElement(i, k) a2 = mat2.retrieveElement(i, k) s = (a1 - a2)**2 result += s return math.sqrt(result) def residual_norm(self): """ Calculates the normalized residual norm using self.x, self.A, and self.b. This must be called once the method solve has been called. """ b_calc = self.A.productAx(self.x) numerator = self.norm2(self.b, b_calc) denominator = 0 for i in range(self.b.rowRank): denominator += (self.b.retrieveElement(i, 0))**2 denominator = math.sqrt(denominator) return numerator / denominator def solve(self): """ Solves the sytem of linear equations using Jacobi iterative method without implementing any matrix preconditioning. """ num_iter = 1 while num_iter <= self.max_iter: x = self.one_iter() if self.norm2(x, self.x0) < self.tol: self.x = x break num_iter += 1 self.x0 = x self.x = x self.max_iter = num_iter