-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatrices.py
607 lines (572 loc) · 31.2 KB
/
matrices.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
import decimal
import errors # our custom class for handling errors
import itertools # required for zip_longest function
import numbers # required to check number type
from math import factorial
class Matrix(object):
""" Basic matrix class
Has numeric decimal type of values
"""
def __init__(self, list_of_lists, rows=None, columns=None,):
""" Matrix initialization method
"list_of_lists" parameter should look like this: [[1, 2, 3], [4, 5, 6]] or in another form:
[[1, 2, 3],
[4, 5, 6]] (in this particular case matrix with 2 rows and 3 columns will be initialize)
number of lists - it's "m" matrix's parameter (which represent rows)
number of elements in each list - it's "n" matrix's parameter and represent columns
"""
# if we didn't initialize number of rows and columns explicitly - calculate them using len() function
if rows is None:
try:
self.m = len(list_of_lists)
except TypeError:
raise errors.WrongInputType("Should be list of lists type: [[],[]]")
else:
self.m = rows
if columns is None:
for arg in list_of_lists: # this is redundant check
try:
self.n = len(arg)
except TypeError:
raise errors.WrongInputType("Should be list of lists type: [[],[]]")
else:
self.n = columns
self.A = []
self._matrix_input_checker(list_of_lists)
# Here we initialize matrix A with parameter list_of_lists
for column in list_of_lists:
temp_arg = []
for arg in column:
if not isinstance(arg, decimal.Decimal):
temp_arg.append(decimal.Decimal(repr(arg))) # transformation values in list_of_lists to Decimal
else:
temp_arg.append(arg)
self.A.append(temp_arg)
def __iter__(self):
""" Here we make our matrix iterable by implementing __iter__ method"""
for row in self.A:
yield row
def _matrix_input_checker(self, input_matrix):
""" Private method for checking inputted data to be relevant type and in same dimension
"""
# checker for list of lists type: [[]]
try:
if not (all(isinstance(column, list) for column in input_matrix)):
raise errors.WrongInputType("You should pass a list of lists like this: [[arg]]")
except TypeError:
raise errors.WrongInputType("You should pass a list of lists like this: [[arg]]")
# checking if inputted matrix has valid dimensions (if rows == m)
# print("Number of rows: {}".format(len(input_matrix)))
try:
if self.m != len(input_matrix):
raise errors.WrongDimension("Wrong number of columns for initialization")
except TypeError:
raise errors.WrongInputType("You should pass a list of lists like this: [[arg]]")
# Checking values in inputted matrix for numeric type
for row in input_matrix:
# Checking for relevant number of columns
# print("Number of columns: {}: ".format(len(row)))
if self.n != len(row):
raise errors.WrongDimension("Wrong number of rows for initialization")
for num in row:
if not isinstance(num, numbers.Number):
raise errors.WrongElementType("Should be a numeric type!")
def is_zero_matrix(self):
""" Checking if matrix is a Null matrix (consisting of zeros)
return True if so
"""
for column in self.A:
for arg in column:
if arg != 0:
return False
return True
def is_square_matrix(self):
""" Checking if matrix is square matrix: m=n"""
if self.m == self.n:
return True
else:
return False
def is_diagonal_matrix(self):
""" Checking if matrix is a diagonal matrix: has all elements equal to zero (except of main diagonal)
We presume, that diagonal matrix has to be also a square matrix
"""
if self.is_square_matrix():
for i in range(0, self.m):
for j in range(0, self.n):
if self.A[i][j] == 0 and i == j:
return False
if self.A[i][j] != 0 and i != j:
return False
return True
else:
# Here we raised an error because non square matrices doesnt have main diagonal, so we explicitly warned
# users about needs of square type matrix, but we rewrote it to return just False
return False
# raise errors.WrongInputType("Need a square matrix here")
def is_identity_matrix(self):
""" Checking if matrix is identity matrix: diagonal square matrix, where all elements of the main
diagonal equals to one. Return True if so
"""
# it's one way to implement this method, but better example will be 'is_diagonal_matrix' implementation
if self.is_diagonal_matrix():
i = 0
j = 0
for columns in self.A:
for arg in columns:
if arg != 1 and i == j:
return False
j += 1
i += 1
j = 0
return True
else:
return False # Just returning False here but could be an error like in commented code below
# raise errors.WrongInputType("Not diagonal matrix cant be identity matrix")
def matrix_is_equal(self, matrix_for_compare):
""" Method for comparing two matrices. If they equal - it will return True, otherwise - False
Parameter 'matrix_for_compare' is an instance of Matrix() class.
One matrix is equal to another if all of their components(elements) are equal
"""
if not isinstance(matrix_for_compare, Matrix):
raise errors.WrongInputType("Input parameter should be a Matrix type")
# both matrices should have same dimensions
if self.m != matrix_for_compare.m:
return False
if self.n != matrix_for_compare.n:
return False
for column1, column2 in zip(self.A, matrix_for_compare):
for arg1, arg2 in zip(column1, column2):
if arg1 != arg2:
return False
return True
def matrix_transposition(self):
""" This method will Transpose matrix self.A and return new transposed matrix """
# here we creating zero matrix with n columns and m rows
transpose_list = [[0 for x in range(self.m)] for y in range(self.n)]
# this is how transposition works: a[i][j] == at[j][i], where at - transpose matrix
for columns, i in zip(self.A, range(0, self.m)):
for arg, j in zip(columns, range(0, self.n)):
transpose_list[j].pop(i) # need to remove 0 from position before inserting real value
transpose_list[j].insert(i, arg) # if 0 not removed - it will shifted position and expand matrix
# print(transpose_list)
return Matrix(transpose_list)
def matrix_is_transpose(self, matrix_for_compare):
""" Here we checking if matrix self.A is transpose to matrix_for_compare
Returning True if so"""
if not isinstance(matrix_for_compare, Matrix):
raise errors.WrongInputType("Input parameter should be a Matrix type")
if self.m != matrix_for_compare.n:
return False
if self.n != matrix_for_compare.m:
return False
if self.matrix_is_equal(matrix_for_compare.matrix_transposition()):
return True
return False
def matrix_addition(self, matrix_for_add):
""" This method will add 'matrix_for_add' to the self.A matrix and return results in form of new Matrix.
Note, that 'matrix_for_add' need to be a Matrix() type. Also, to add one matrix to another,
they both need to have same dimensions
"""
if not isinstance(matrix_for_add, Matrix):
raise errors.WrongInputType("matrix_for_add parameter should be a Matrix() type")
if self.m != matrix_for_add.m:
raise errors.WrongDimension("Matrices doesnt have same number of rows")
if self.n != matrix_for_add.n:
raise errors.WrongDimension("Matrices should have same number of columns")
list_matrix_add = []
for rows1, rows2 in zip(self.A, matrix_for_add):
temp_list = []
for arg1, arg2 in zip(rows1, rows2):
temp_list.append(arg1 + arg2)
list_matrix_add.append(temp_list)
return Matrix(list_matrix_add)
def add_number(self, number):
""" This method will add a scalar 'number' to the current matrix.
Actually, following matrices theory: there is no such operation as 'adding a scalar to the matrix',
but, in our case, we considering a scalar to be a matrix filled with the same number(parameter 'number').
Also, this 'scalar' matrix will have same dimensions as a matrix, we performing addition operation on.
Method returning a new Matrix()"""
# first, checking if 'number' is a numeric type:
if not isinstance(number, numbers.Number):
raise errors.WrongElementType("Parameter 'number' should be a numeric type!")
if not isinstance(number, decimal.Decimal):
number = decimal.Decimal(repr(number)) # need to convert (if) float value to decimal
addition_matrix = []
for rows in self.A:
temp_list = []
for arg in rows:
temp_list.append(arg+number)
addition_matrix.append(temp_list)
return Matrix(addition_matrix)
def subtract_number(self, number):
""" This method will subtract a scalar parameter 'number' from the current matrix.
For more information - check add_number doc_string.
Returning value - new Matrix() class """
return self.add_number(number * (-1)) # well, subtraction it's an addition where number has an opposite sign
def multiply_by_number(self, number, precision=2):
""" Method for scalar multiplication matrix A by parameter 'number'(should be a numeric type)
For multiply matrix by some number, we actually need to multiply all her elements by this number
After we done with multiplication, a new matrix will be returned
'precision' parameter is optional and will point to a number or positions after '.' symbol
precision should be a positive, integer type number"""
if not isinstance(number, numbers.Number):
raise errors.WrongInputType("Parameter 'number' should be a numeric type!")
# converting number to decimal format for consistence
if not isinstance(number, decimal.Decimal):
number_dec = decimal.Decimal(repr(number))
else:
number_dec = number
precision = self._precision_check(precision)
return_list = []
for rows in self.A:
temp_list = []
for arg in rows:
try:
temp_list.append((arg*number_dec).quantize(decimal.Decimal(str((10**-precision)))))
except decimal.InvalidOperation:
raise errors.WrongDimension("This is to much. Try to low down precision value")
return_list.append(temp_list)
return Matrix(return_list)
def _precision_check(self, pres):
""" Private method for checking input for precision value"""
# method get a general check in test_14 of TestMatrix() class
if not isinstance(pres, int):
raise errors.WrongInputType("Precision should be an integer number")
return abs(pres)
def matrix_subtraction(self, matrix_for_subtract):
""" This method will subtract incoming matrix(parameter 'matrix_for_subtract' which is Matrix type)
from self.A matrix. Code for this class is similar(actually the same) as for matrix_addition method,
except when we need add arg2 to agg1 - we subtract it. Method could be implemented as call of
matrix_addition with 'matrix_for add' multiplied by '-1'(check the commented code)"""
# return self.matrix_addition(matrix_for_subtract.multiply_by_number(-1))
if not isinstance(matrix_for_subtract, Matrix):
raise errors.WrongInputType("matrix_for_subtract parameter should be a Matrix() type")
if self.m != matrix_for_subtract.m:
raise errors.WrongDimension("Matrices doesnt have same number of rows")
if self.n != matrix_for_subtract.n:
raise errors.WrongDimension("Matrices should have same number of columns")
list_matrix_subtract = []
for rows1, rows2 in zip(self.A, matrix_for_subtract):
temp_list = []
for arg1, arg2 in zip(rows1, rows2):
temp_list.append(arg1 - arg2)
list_matrix_subtract.append(temp_list)
return Matrix(list_matrix_subtract)
def divide_by_number(self, number, precision=2):
""" Dividing matrix self.A by 'number' and returning new matrix
Basically, we need to call multiply_by_number method with income parameter: 1/number """
precision = self._precision_check(precision)
number_for_division = decimal.Decimal(1/number).quantize(decimal.Decimal(str(10**-precision)))
return self.multiply_by_number(number_for_division, precision=precision)
def matrix_multiplication(self, matrix_for_multiplication):
""" Method for multiplying two matrices. Input parameter 'matrix_for_multiplication' should be Matrix()
type. Also, input matrix should have same number of rows as number of columns in self.A matrix.
In another words: self.n == matrix_for_multiplication.m """
if not isinstance(matrix_for_multiplication, Matrix):
raise errors.WrongInputType("matrix_for_multiplication should be a Matrix() type")
if self.n != matrix_for_multiplication.m:
raise errors.WrongDimension("Matrices dimensions not compatible")
multiplication_list = []
# c[i][k] = sum(a[i][j]*b[j][k])
for rows in self.A:
temp_list = []
for i in range(0, matrix_for_multiplication.n):
temp = 0
for arg1, rows2 in itertools.zip_longest(rows, matrix_for_multiplication):
temp += arg1*rows2[i]
temp_list.append(temp)
multiplication_list.append(temp_list)
return Matrix(multiplication_list)
def matrix_determinant(self, precision=2):
""" This method calculate determinant of the matrix, using elementary rows manipulation:
first - we'll transform our matrix to upper triangular form and then - multiplied her main diagonal elements
between themselves to get a determinant
'precision' parameter it's number of positions after '.' symbol. It use default roundup from decimal
method getcontext().rounding. (recommending rounding=ROUND_HALF_EVEN, which is a default)"""
if not self.is_square_matrix(): # checking if matrix instance is a square matrix
raise errors.WrongDimension("Determinant can be computed only for square matrix")
precision = self._precision_check(precision)
det = decimal.Decimal(1) # initializing variable for determinant
if self.m == 1:
det = self.A[0][0] # for square matrix with one row determinant is equal to her single element
elif self.m == 2: # for rank 2 matrix we will use common formula
det = self.A[0][0]*self.A[1][1] - self.A[0][1]*self.A[1][0]
else:
transform_matrix = [] # creating temporary matrix for transformation operations
for rows in self.A:
transform_matrix.append(rows)
for i in range(0, self.m):
for j in range(0, self.m):
# need to transform all transform_matrix[j][i] elements to 0(except j =< i element)
if j == i and transform_matrix[i][j] == 0:
if i == (self.m - 1):
return 0
else:
for k in range(i+1, self.m):
if transform_matrix[k][i] != 0:
# swapping rows of transform_matrix,
# so we position non zero element on main diagonal
temp = transform_matrix.pop(i)
temp2 = transform_matrix.pop(k-1)
transform_matrix.insert(i, temp2)
transform_matrix.insert(k, temp)
det *= (-1) # switching determinant sight
break
if transform_matrix[k][i] == 0 and k == (self.m - 1) and transform_matrix[i][j] == 0:
return 0 # we have 0 on main diagonal, so determinant equal to 0
if i == j and transform_matrix[i][j] != 0:
det *= transform_matrix[i][i]
if j < i:
continue
if j > i and transform_matrix[j][i] != 0:
# we need to subtract a multiplied by scalar transform_matrix i-row from j-row
# so element [j][i] will be equal to zero
temp_scalar = transform_matrix[j][i]/transform_matrix[i][i]
temp_list = []
for arg1, arg2 in zip(transform_matrix[i], transform_matrix[j]):
temp_list.append(arg2 - arg1*temp_scalar)
transform_matrix.pop(j) # deleting old j-row
transform_matrix.insert(j, temp_list) # inserting new, transformed j-row
# 10^-2 will be equal to 0.01(to positions after '.') and so on
try:
det = det.quantize(decimal.Decimal(str(10**-precision)))
except decimal.InvalidOperation:
raise errors.WrongDimension("This is to much. Try to low down precision value")
return det
def matrix_inverse(self, precision=3):
""" Here we will try to find an inverse matrix to self.A using Gauss-Jordan method(elementary row operation)
The return type of 'matrix_inverse' is a Matrix()"""
if not self.is_square_matrix(): # checking if matrix instance is a square matrix
raise errors.WrongDimension("Matrix should be a square to compute her inverse")
if self.matrix_determinant() == 0:
raise errors.WrongInputType("Determinant is Zero. This matrix doesnt have inverse matrix")
precision = self._precision_check(precision)
# we will need an instance of identity matrix for this method
identity_matrix = IdentityMatrix(self.m)
# unpacking into list of lists:
inverse_matrix = []
matrix_for_manipulations = []
for rows1, rows2 in zip(identity_matrix, self.A):
temp1 = []
temp2 = []
for arg1, arg2 in zip(rows1, rows2):
temp1.append(arg1)
temp2.append(arg2)
inverse_matrix.append(temp1)
matrix_for_manipulations.append(temp2)
# first, we will transform 'matrix_for_manipulations' to upper triangular form
# also, we will duplicate all elementary row operations on 'inverse_matrix'
for i in range(0, self.m):
for j in range(0, self.m):
# here we 'eliminate' zeroes on a main diagonal
if i == j and matrix_for_manipulations[i][j] == 0:
# we are not checking for special occasions with whole row or column equal to zero
# since in that case determinant would be a zero, and we already know that it's not true
for k in range(i+1, self.m):
if matrix_for_manipulations[k][i] != 0:
# switching rows in matrices
first_temp1 = matrix_for_manipulations.pop(i)
first_temp2 = matrix_for_manipulations.pop(k-1)
matrix_for_manipulations.insert(i, first_temp2)
matrix_for_manipulations.insert(k, first_temp1)
# duplicated operations for identity matrix
first_temp3 = inverse_matrix.pop(i)
first_temp4 = inverse_matrix.pop(k-1)
inverse_matrix.insert(i, first_temp4)
inverse_matrix.insert(k, first_temp3)
if j < i:
continue
if j > i and matrix_for_manipulations[j][i] != 0:
# here we need to subtract multiplied by scalar 'i' element from 'j' element,
# so as a result we will get '0' on a position beneath main diagonal([i][i])
# the 'scalar' can be found by dividing [j][i] element by [i][i] element
temp_scalar1 = matrix_for_manipulations[j][i]/matrix_for_manipulations[i][i]
# now we use our 'precision' for scalars:
try:
temp_scalar1 = temp_scalar1.quantize(decimal.Decimal(str(10**-precision)))
temp_list1 = []
temp_list2 = []
for arg1, arg2, arg3, arg4 in zip(matrix_for_manipulations[i], matrix_for_manipulations[j],
inverse_matrix[i], inverse_matrix[j]):
temp_list1.append((arg2 - (arg1*temp_scalar1)).quantize(decimal.Decimal(str(10**-precision))))
temp_list2.append((arg4 - arg3*temp_scalar1).quantize(decimal.Decimal(str(10**-precision))))
except decimal.InvalidOperation:
raise errors.WrongDimension("This is to much. Try to low down precision value")
# here we replacing row [j] with new, modified row
matrix_for_manipulations.pop(j)
matrix_for_manipulations.insert(j, temp_list1)
# and same thing for future inverse matrix
inverse_matrix.pop(j)
inverse_matrix.insert(j, temp_list2)
# so, yeah, now we have upper triangular matrix
# print('*'*45)
# for row in matrix_for_manipulations:
# print(row)
# print('*'*45)
# next step it's to start from lower right conner([self.m][self.m]) and move up, multiplying each row by
# appropriate number(inverse one in this situation), so we would get a '1' on a diagonal
# Also, we need to 'eliminate' all others number, which are not on main diagonal
for i in range(self.m - 1, -1, -1):
# making '1' on diagonal
temp_scalar2 = decimal.Decimal(1)/matrix_for_manipulations[i][i]
try:
temp_scalar2 = temp_scalar2.quantize(decimal.Decimal(str(10**-precision)))
temp_list1 = []
temp_list2 = []
for arg1, arg2 in zip(matrix_for_manipulations[i], inverse_matrix[i]):
temp_list1.append((arg1*temp_scalar2).quantize(decimal.Decimal(str(10**-precision))))
temp_list2.append((arg2*temp_scalar2).quantize(decimal.Decimal(str(10**-precision))))
except decimal.InvalidOperation:
raise errors.WrongDimension("This is to much. Try to low down precision value")
matrix_for_manipulations.pop(i)
matrix_for_manipulations.insert(i, temp_list1)
inverse_matrix.pop(i)
inverse_matrix.insert(i, temp_list2)
for k in range(i-1, -1, -1):
if matrix_for_manipulations[k][i] != 0:
temp_scalar3 = matrix_for_manipulations[k][i]/matrix_for_manipulations[i][i]
try:
temp_scalar3 = temp_scalar3.quantize(decimal.Decimal(str(10**-precision)))
second_temp_list1 = []
second_temp_list2 = []
for ar1, ar2, ar3, ar4 in zip(matrix_for_manipulations[i], matrix_for_manipulations[k],
inverse_matrix[i], inverse_matrix[k]):
second_temp_list1.append((ar2 - ar1*temp_scalar3).quantize(decimal.Decimal(str(10**-precision))))
second_temp_list2.append((ar4 - ar3*temp_scalar3).quantize(decimal.Decimal(str(10**-precision))))
except decimal.InvalidOperation:
raise errors.WrongDimension("This is to much. Try to low down precision value")
matrix_for_manipulations.pop(k)
matrix_for_manipulations.insert(k, second_temp_list1)
inverse_matrix.pop(k)
inverse_matrix.insert(k, second_temp_list2)
# print('*'*90)
# for row in matrix_for_manipulations:
# print(row)
# print('*'*90)
return Matrix(inverse_matrix)
def _matrix_determinant(self):
""" Here we will compute a determinant for square matrix self.A recursively
It's a good example 'how not to do this'
Better to use this for 3 and less dimensions matrix (or up to 6 dimensions; for calculating 8 dimensional
matrix this method will need several minutes)"""
if not self.is_square_matrix():
raise errors.WrongDimension("Determinant can be computed only for square matrix")
det = 0
if self.m == 1:
det = self.A[0][0]
elif self.m == 2:
det = self.A[0][0]*self.A[1][1] - self.A[0][1]*self.A[1][0]
elif self.m == 3:
det = self.A[0][0]*self.A[1][1]*self.A[2][2] + self.A[0][1]*self.A[1][2]*self.A[2][0] +\
self.A[1][0]*self.A[2][1]*self.A[0][2] - self.A[2][0]*self.A[1][1]*self.A[0][2] -\
self.A[1][0]*self.A[0][1]*self.A[2][2] - self.A[2][1]*self.A[1][2]*self.A[0][0]
else:
det += self._matrix_determinant_n(self.A)
return det/factorial(self.m - 3) # for 'some reason' we have deviation = (n-3)! where n - matrix dimension
return det
def _matrix_determinant_n(self, matrix_n):
""" Private method, that supposed to calculate determinant for n-dimensional matrix recursively
Its used in _matrix_determinant method, when dimension of matrix greater than 3"""
det = 0
dimension = len(matrix_n)
if dimension == 3:
det = Matrix(matrix_n)._matrix_determinant()
while dimension > 3:
for i in range(0, len(matrix_n)):
temp_matrix_list = []
for rows, k in zip(matrix_n, range(0, len(matrix_n))):
temp = []
if k == 0:
continue
for arg, l in zip(rows, range(0, len(matrix_n))):
if l == i:
continue
temp.append(arg)
temp_matrix_list.append(temp)
new_matrix_n = temp_matrix_list
det += (matrix_n[0][i])*self._matrix_determinant_n(new_matrix_n)*(-1)**i
dimension -= 1
return det
# def __getitem__(self, item):
# return self.A
def matrix_unpack(self):
""" Method for unpacking class instance of Matrix() into list of lists: [[],[]]
Returning type - list """
# TODO: need to add option for unpacking into float list and other formats
matrix_list = []
for rows in self.A:
matrix_list.append(rows)
return matrix_list
def matrix_show(self):
""" Simple method for printing a matrix
(Will be updated soon)
"""
for row in self.A:
print(row)
# redefining standard operators
def __add__(self, other):
if isinstance(other, Matrix):
return self.matrix_addition(other)
elif isinstance(other, numbers.Number):
return self.add_number(other)
else:
raise errors.GeneralMatrixError("Not supported operation or operand type!")
def __sub__(self, other):
if isinstance(other, Matrix):
return self.matrix_subtraction(other)
elif isinstance(other, numbers.Number):
return self.subtract_number(other)
else:
raise errors.GeneralMatrixError("Not supported operation or operand type!")
def __mul__(self, other):
if isinstance(other, Matrix):
return self.matrix_multiplication(other)
elif isinstance(other, numbers.Number):
return self.multiply_by_number(other)
else:
raise errors.GeneralMatrixError("Not supported operation or operand type!")
def __truediv__(self, other):
if isinstance(other, numbers.Number):
return self.divide_by_number(other)
else:
raise errors.GeneralMatrixError("Not supported operation or operand type!")
class ZeroMatrix(Matrix):
""" class for initialization zero matrix
rows - number of rows in the future matrix
columns - number of columns in the future matrix
Also, you can populate matrix with same number just by explicitly defining parameter 'number'.
For example: if you need a 3x2 matrix, where all elements equal to 4, use ZeroMatrix with optional
parameter 'number=4' - ZeroMatrix(3, 2, number=4)
"""
def __init__(self, rows, columns, number=0):
self.zero_matrix = []
if not isinstance(number, numbers.Number):
raise errors.WrongElementType("Parameter 'number' should be a numeric type!")
self.n = number
try:
for i in range(0, rows):
temp = []
for j in range(0, columns):
temp.append(self.n)
self.zero_matrix.append(temp)
except TypeError:
raise errors.WrongInputType("Columns and rows should be an integer type")
super().__init__(columns=columns, rows=rows, list_of_lists=self.zero_matrix)
class IdentityMatrix(Matrix):
""" class for initialization an identity matrix: square, diagonal matrix where main diagonal consist of '1'
'dimension' parameter represent dimension of a matrix or(in another words) number of columns/rows
"""
def __init__(self, dimension):
self.identity_matrix = []
try:
for i in range(0, dimension):
temp = []
for j in range(0, dimension):
if i == j:
temp.append(1)
else:
temp.append(0)
self.identity_matrix.append(temp)
except TypeError:
raise errors.WrongInputType("Dimension should be an integer type")
super(IdentityMatrix, self).__init__(columns=dimension, rows=dimension, list_of_lists=self.identity_matrix)