0

If I had two matrices matrix_a = [[a, b], [c, d]], and matrix_b = [[w, x], [y, z]] and I wished to find the following matrix matrix_c = [[aw + cy, ax + cz], [bw + dy, bx + dz]] how could I do this, not only for this case but for arbitrary sizes of matrix_a and matrix_b:
a) most simply using only list comphrehensions
b) most simply using a function which took the two matrices matrix_a and matrix_b as input, and returned matrix_c
c) and/or an otherwise pythonic manner?

The following code is my current solution.

matrix_a = [[1, 1], [2, 1]]
matrix_b = [[25, 1.5], [30, 2.7]]

# so we should obtain matrix_c = [[85, 6.9], [55, 4.2]]

transposed_matrix_a =[list(i) for i in zip(*matrix_a)]

matrix_c = []
for i in range(len(matrix_a[0])):
    def matrix_element(function, number):
        return [function(number)*matrix_b[number][i] for i in range(len(
            matrix_b[0]))]
        
    def t_matrix_a_element(x):
        return transposed_matrix_a[i][x]

    c_vector = [matrix_element(t_matrix_a_element, i) for i in range(len(
        transposed_matrix_a[0]))]
    matrix_c.append([sum(i) for i in zip(*c_vector)])

print(matrix_c)

EDIT: To be explicit the desired computation would be:
matrix_c = [[aw + cy, ax + cz], [bw + dy, bx + dz]]
matrix_c = [[1 x 25 + 2 x 30, 1 x 1.5 + 2 x 2.7], [1 x 25 + 1 x 30, 1 x 1.5 + 1 x 2.7]]
matrix_c = [[85, 6.9], [55, 4.2]]

and not the product:
[[aw + by, ax + bz], [cw + dy, cx + dz]]

deSelby
  • 3
  • 2
  • Your code really calculates `[[85, 6.9], [55, 4.2]]`, but I think it is not `[[aw + ay, bx + bz], [cw + cy, dx + dz]]`, that would be `[[55, 4.2], [110, 4.2]]`. – tevemadar Jan 21 '21 at 11:48
  • @tevemadar Apologies yes, I got that muddled up, I've edited the question now, it's matirx_c = [[aw + cy, ax + cz], [bw + dy, bx + dz]] NOT matrix_c = [[aw + ay, bx + bz], [cw + cy, dx + dz]]. Thanks. – deSelby Jan 21 '21 at 14:11

5 Answers5

1

Try this for non-numpy: (believe it's more Pythonic ... ;-) -than numpy version)

def matrix_mul(A, B):
    zip_b = list(zip(*B))
    return [[sum(a * b for a, b in zip(row_a, col_b))
                 for col_b in zip_b]
            for row_a in A]

# one-liner
""" result = [[ sum(a*b for a,b in zip(X_row,Y_col))
                        for Y_col in zip(*Y)]
              for X_row in X]
                    
"""
Daniel Hao
  • 4,922
  • 3
  • 10
  • 23
  • Thank you this indeed seems Pythonic and is exactly the sort of concise code I had in mind... however both solutions in this code return [[55, 4.2], [80, 5.7]] whereas the desired output is [[85, 6.9], [55, 4.2]] . I think that you have computed [[bw + dy, bx + dz], [cw + dy, cx + dz]] and not [[aw + cy, ax + cz], [bw + dy, bx + dz]]. – deSelby Jan 21 '21 at 21:02
  • Thanks for the comments. But if you check the matrix multiplications formula, the answer is correct then. Please double check - https://www.emathhelp.net/calculators/linear-algebra – Daniel Hao Jan 21 '21 at 22:37
  • Thanks for getting back to me, I went to the link you said and chose matrix multiplication, which returns [[55, 4.2], [80, 5.7]] the same as your code. But the question is not to compute the product of matrix_a and matrix_b, it's to compute matrix_c = [[aw + cy, ax + cz], [bw + dy, bx + dz]]. The product is [[aw + by, ax + bz], [cw + dy, cx + bz]]. – deSelby Jan 22 '21 at 12:54
0

For the (c) case you can simply use the numpy module.

import numpy as np

a = np.array([[1, 1], [2, 1]])
b = np.array([[25, 1.5], [30, 2.7]])

print(a @ b)

[[55. ,  4.2],
 [80. ,  5.7]]
javadr
  • 310
  • 2
  • 12
0

Try the following:

def transpose(matrix):
    # if you just want to iterate over the 
    # transposed matrix, you can just
    # return zip(*matrix)
    return list(map(list, zip(*matrix)))

matrix_c = []

for row_a in matrix_a:
    row_c= []
    for val_a, row_b in zip(row_a, transpose(matrix_b)):
        val_c = sum(val_a * val_b for val_b in row_b)
        row_c.append(val_c)
    matrix_c.append(row_c)

print(result)

# [[55, 4.2], [110, 4.2]]

Another way, though it is manual, and can not be automated, but just in case:

>>> [[a, b], [c, d]], [[w, x], [y, z]] = matrix_a, matrix_b

>>> matrix_c = [[a*w + a*y, b*x + b*z], [c*w + c*y, d*x + d*z]]

>>> matrix_c
[[55, 4.2], [110, 4.2]]
Sayandip Dutta
  • 15,602
  • 4
  • 23
  • 52
  • Thank you, but I asked the question incorrectly and what I meant to ask is different if you'd care to look again? I meant matirx_c = [[aw + cy, ax + cz], [bw + dy, bx + dz]] NOT matrix_c = [[aw + ay, bx + bz], [cw + cy, dx + dz]]. Creating a function called transpose as you suggest is more readable I'll do that from now on. – deSelby Jan 21 '21 at 14:17
0

Another solution to the question which is totally based on list comprehension:

import numpy as np

#mat_a = [[1, 1], [2, 1]]
#mat_b = [[25, 1.5], [30, 2.7]]
mat_a = np.random.random((3,4))
mat_b = np.random.random((4,5))

def matMul(A, B):
    return [list(map(lambda x:sum([i*j for i,j in x]), [list(zip(row, col)) for row in A for col in [list(i) for i in zip(*B)]]))[s*len(B[0]):s*len(B[0])+len(B[0])] for s in range(len(A)) ]

print(mat_a @ mat_b)
for row in matMul(mat_a, mat_b):
    print(row)
javadr
  • 310
  • 2
  • 12
0
matrix_a = [[a, b], [c, d]]
matrix_b = [[w, x], [y, z]]
matrix_c = [[aw + cy, ax + cz], [bw + dy, bx + dz]]

abcd and wxyz are not very helpful, especially when someone wants to generalize the task, it's better rewritten with indices, something like

A = [a b] = [A11 A12],   B = [w x] = [B11 B12]
    [c d]   [A21 A22]        [y z]   [B21 B22]

C = [a*w+c*y  a*x+c*z] = [A11*B11+A21*B21  A11*B12+A21*B22]
    [b*w+d*y  b*x+d*z]   [A12*B11+A22*B21  A12*B12+A22*B22]

then there is any chance for observations like

Cij
C11 = A11*B11+A21*B21 = Sum Ak_*Bk_ for k=1,2 and _ could be either i or j
C12 = A11*B12+A21*B22 = Sum Aki*Bkj for k=1,2
C21 = A12*B11+A22*B21 = Sum Aki*Bkj for k=1,2
C22 = A12*B12+A22*B22 = Sum Ak_*Bk_ for k=1,2
Cij = Sum Aki*Bkj

something you probably knew, though went ahead with plucking our eyes out with that abcdwxyz monstrosity instead.

And that's a matrix multiplication, just not a simple A*B, but AT*B.
Then you can fetch a multiplying code from Matrix Multiplication in pure Python? for example, and write

matrix_a = [[1, 1], [2, 1]]
#matrix_a = [[1, 2], [3, 4]]
matrix_b = [[25, 1.5], [30, 2.7]]

transposed_matrix_a =[list(i) for i in zip(*matrix_a)]
transposed_matrix_b =[list(i) for i in zip(*matrix_b)]

print([[sum(ele_a*ele_b for ele_a, ele_b in zip(row_a, col_b)) 
        for col_b in transposed_matrix_b] for row_a in transposed_matrix_a])

a,b,c,d=sum(matrix_a,[])
w,x,y,z=sum(matrix_b,[])
print(a*w+c*y,a*x+c*z)
print(b*w+d*y,b*x+d*z)

Will produce

[[85, 6.9], [55, 4.2]]
85 6.9
55 4.2

(the commented 1,2,3,4 matrix is there for verification purposes, as the original one has a lot of 1s inside and certain indexing issues could go unnoticed)

tevemadar
  • 12,389
  • 3
  • 21
  • 49