File: matrix-code.py
"""
a numerically-inclined student asked for examples related to
matrix processing (in the core language, not using NumPy which
has better built-in support for vector and matrix processing);
the following is a quick tour through some simple matrix code,
showing equivalents coded in for loops and list comprehensions;
requires Python 2.7 for some tests, one line works in 3.X only;
"""
######################################################################################
# Vectors: 1D lists (added mar-12-11)
######################################################################################
L = [1, 2, 3, 4, 5, 6]
M = [7, 8, 9, 10, 11, 12]
#-------------------------------------------------------------
# (L ** 2): print squares of all in one vector: 1 4 9 16 25 36
#-------------------------------------------------------------
for i in range(len(L)):
print(L[i] ** 2)
for x in L: # simpler, probably faster
print(x ** 2)
# ---3.X only---
list( map(print, (x ** 2 for x in L)) ) # 3.X print(), map() generator
#------------------------------------------------------------
# (N = L ** 2): make new result vector: [1, 4, 9, 16, 25, 36]
#------------------------------------------------------------
N = [x ** 2 for x in L] # list comprehension
print(N)
N = []
for x in L: # manual loop: often slower
N.append(x ** 2)
print(N)
N = list(map((lambda x: x ** 2), L)) # map: need list() in 3.X only
print(N)
#
# other: generators produce results on demand
#
G = (x ** 2 for x in L) # generator expression
print(list(G)) # list() requests results
def gensquares(L): # generator function
for x in L:
yield x ** 2
print(list(gensquares(L))) # list() requests results
#
# other: set and dict comprehensions (3.X, 2.7)
#
print({x ** 2 for x in L}) # set: {1, 36, 9, 16, 25, 4} in 3.X, set(...) in 2.X
print({x: x ** 2 for x in L}) # dict: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36}
#--------------------------------------------------------------
# (L + M): print pairwise sums of two vectors: 8 10 12 14 16 18
#--------------------------------------------------------------
for i in range(len(L)):
print(L[i] + M[i])
for (x, y) in zip(L, M): # zip is a generator in 3.X
print(x + y)
#----------------------------------------------------------------------
# (N = L + M): create new pairwise sums vector: [8, 10, 12, 14, 16, 18]
#----------------------------------------------------------------------
N = []
for i in range(len(L)): N.append(L[i] + M[i])
print(N)
N = []
for (x, y) in zip(L, M): N.append(x + y) # zip is a generator in 3.X
print(N)
N = [L[i] + M[i] for i in range(len(L))]
print(N)
N = [x + y for (x, y) in zip(L, M)]
print(N)
#
# other similar ops
#
print([x * y for (x, y) in zip(L, M)]) # [7, 16, 27, 40, 55, 72]
print([y / x for (x, y) in zip(L, M)]) # [7.0, 4.0, 3.0, 2.5, 2.2, 2.0] (3.X)
print([y // x for (x, y) in zip(L, M)]) # [7, 4, 3, 2, 2, 2]
print(list( map((lambda x, y: x * y), L, M) )) # [7, 16, 27, 40, 55, 72]
######################################################################################
# Matrixes: 2D lists (original code)
######################################################################################
def init():
global M, N # reset state for new tests
M = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
N = [[10, 20, 30],
[40, 50, 60],
[70, 80, 90]]
#---------------------------------------------------------------
# (M ** 2): print squares of one matrix: 1 4 9 16 25 36 49 64 81
#---------------------------------------------------------------
init()
for i in range(3):
for j in range(3):
print(M[i][j] ** 2)
for row in M:
for col in row: # generalized
print(col ** 2)
#----------------------------------------------------------------------------
# (M **= 2): in-place matrix squares: [[1, 4, 9], [16, 25, 36], [49, 64, 81]]
#----------------------------------------------------------------------------
init()
for i in range(3):
for j in range(3):
M[i][j] **= 2
print(M)
init()
for i in range(len(M)): # generalized
for j in range(len(M[i])):
M[i][j] **= 2
print(M)
#-------------------------------------------------------------------
# similar, but make new 1D vector: [1, 4, 9, 16, 25, 36, 49, 64, 81]
#-------------------------------------------------------------------
init()
print( [col ** 2 for row in M for col in row] )
print( [M[i][j] ** 2 for i in range(len(M)) for j in range(len(M[i]))] )
#--------------------------------------------------------------------------------
# (X = M ** 2): new 2D matrix of squares: [[1, 4, 9], [16, 25, 36], [49, 64, 81]]
#--------------------------------------------------------------------------------
X = []
for i in range(len(M)):
row = []
for j in range(len(M[i])):
row.append(M[i][j] ** 2)
X.append(row)
print(X)
X = []
for row in M:
tmp = []
for col in row:
tmp.append(col ** 2)
X.append(tmp)
print(X)
#
# nest comprehensions for 2D data
#
print( [[M[i][j] ** 2 for j in range(len(M[i]))] for i in range(len(M))] )
print( [[col ** 2 for col in row] for row in M] )
#-------------------------------------------------------------------------------------
# (X = M + N): new matrix of pairwise sums: [[11, 22, 33], [44, 55, 66], [77, 88, 99]]
#-------------------------------------------------------------------------------------
X = []
for i in range(len(M)):
row = []
for j in range(len(M[i])):
row.append(M[i][j] + N[i][j])
X.append(row)
print(X)
X = []
for (row1, row2) in zip(M, N): # zip is a generator in 3.X
tmp = []
for (col1, col2) in zip(row1, row2):
tmp.append(col1 + col2)
X.append(tmp)
print(X)
#
# nest comprehensions for 2D data
#
print( [[M[i][j] + N[i][j] for j in range(3)] for i in range(3)] )
print( [[col1 + col2 for (col1, col2) in zip(row1, row2)] for (row1, row2) in zip(M, N)] )
# end