def block_simplify(self): """Try to combine scalar terms and remove additive identities, recursively. A fuller explanation is found in block_transform.block_simplify. """ from block_util import isscalar from block_transform import block_simplify A = block_simplify(self.A) B = block_simplify(self.B) if isscalar(A) and A == 0: return B if isscalar(B) and B == 0: return A return A + B
def block_collapse(self): """Create a block_mat of block_adds from a block_add of block_mats. See block_transform.block_collapse.""" from block_mat import block_mat from block_util import isscalar from block_transform import block_collapse, block_simplify A = block_collapse(self.A) B = block_collapse(self.B) # The self.__class__(A,B) used below works for both block_sub and # block_add, and any scalar terms are combined by the final call to # block_simplify(). if isinstance(A, block_mat) and isinstance(B, block_mat): m, n = A.blocks.shape C = block_mat(m, n) for row in range(m): for col in range(n): C[row, col] = self.__class__(A[row, col], B[row, col]) elif isinstance(A, block_mat) and isscalar(B): m, n = A.blocks.shape C = block_mat(m, n) for row in range(m): for col in range(n): C[row, col] = self.__class__( A[row, col], B) if row == col else A[row, col] elif isinstance(B, block_mat) and isscalar(A): m, n = B.blocks.shape C = block_mat(m, n) for row in range(m): for col in range(n): C[row, col] = self.__class__( A, B[row, col]) if row == col else B[row, col] else: C = self.__class__(A, B) return block_simplify(C)
def block_simplify(self): """Try to convert identities to scalars, recursively. A fuller explanation is found in block_transform.block_simplify. """ from block_util import isscalar from block_transform import block_simplify m, n = self.blocks.shape res = block_mat(m, n) # Recursive call for i in range(m): for j in range(n): res[i, j] = block_simplify(self[i, j]) # Check if result after recursive conversion is the (scaled) identity v0 = res.blocks[0, 0] if m != n: return res for i in range(m): for j in range(n): block = res.blocks[i, j] if not isscalar(block): return res if i == j: if block != v0: return res else: if block != 0: return res return v0
def block_simplify(self): """Try to simplify the transpose, recursively. A fuller explanation is found in block_transform.block_simplify. """ from block_util import isscalar from block_transform import block_simplify A = block_simplify(self.A) if isscalar(A): return A if isinstance(A, block_transpose): return A.A return block_transpose(A)
def block_collapse(self): """See block_transform.block_collapse.""" from block_transform import block_collapse, block_simplify from block_mat import block_mat A = block_collapse(self.A) if not isinstance(A, block_mat): return block_transpose(A) m, n = A.blocks.shape ret = block_mat(n, m) for i in range(m): for j in range(n): ret[j, i] = block_transpose(A[i, j]) return block_simplify(ret)
def block_collapse(self): """Create a block_mat of block_muls from a block_mul of block_mats. See block_transform.block_collapse.""" from block_mat import block_mat from block_util import isscalar from block_transform import block_collapse, block_simplify # Reduce all composed objects ops = map(block_collapse, self.chain) # Do the matrix multiply, blockwise. Note that we use # block_mul(A,B) rather than A*B to avoid any implicit calculations # (e.g., scalar*matrix->matrix) -- the result will be transformed by # block_simplify() in the end to take care of any stray scalars. while len(ops) > 1: B = ops.pop() A = ops.pop() if isinstance(A, block_mat) and isinstance(B, block_mat): m, n = A.blocks.shape p, q = B.blocks.shape C = block_mat(m, q) for row in range(m): for col in range(q): for i in range(n): C[row, col] += block_mul(A[row, i], B[i, col]) elif isinstance(A, block_mat) and isscalar(B): m, n = A.blocks.shape C = block_mat(m, n) for row in range(m): for col in range(n): C[row, col] = block_mul(A[row, col], B) elif isinstance(B, block_mat) and isscalar(A): m, n = B.blocks.shape C = block_mat(m, n) for row in range(m): for col in range(n): C[row, col] = block_mul(A, B[row, col]) else: C = block_mul(A, B) ops.append(C) return block_simplify(ops[0])
def block_simplify(self): """Try to combine scalar terms and remove multiplicative identities, recursively. A fuller explanation is found in block_transform.block_simplify. """ from block_util import isscalar from block_transform import block_simplify operators = [] scalar = 1.0 for op in self.chain: op = block_simplify(op) if isscalar(op): scalar *= op else: operators.append(op) if scalar == 0: return 0 if scalar != 1 or len(operators) == 0: operators.insert(0, scalar) if len(operators) == 1: return operators[0] ret = block_mul(None, None) ret.chain = operators return ret