| 2 | 2 | |
| 3 | 3 | from sympy import ask, Q |
| 4 | 4 | from sympy.core import Basic, Add |
| 5 | from sympy.core.numbers import Zero | |
| 5 | 6 | from sympy.core.compatibility import range |
| 6 | 7 | from sympy.strategies import typed, exhaust, condition, do_one, unpack |
| 7 | 8 | from sympy.strategies.traverse import bottom_up |
| 79 | 80 | def __new__(cls, *args, **kwargs): |
| 80 | 81 | from sympy.matrices.immutable import ImmutableDenseMatrix |
| 81 | 82 | from sympy.utilities.iterables import is_sequence |
| 82 | isMat = lambda i: getattr(i, 'is_Matrix', False) | |
| 83 | isMat = lambda i: getattr(i, 'is_Matrix', False) or isinstance(i, Zero) | |
| 83 | 84 | if len(args) != 1 or \ |
| 84 | 85 | not is_sequence(args[0]) or \ |
| 85 | 86 | len(set([isMat(r) for r in args[0]])) != 1: |
| 96 | 97 | if ok: |
| 97 | 98 | # same number of rows for each matrix in a row |
| 98 | 99 | for r in rows: |
| 99 | ok = len(set([i.rows for i in r])) == 1 | |
| 100 | if not ok: | |
| 100 | def _get_rows(item): | |
| 101 | if isinstance(item, Zero): | |
| 102 | # For Zero objects, we can't determine rows here | |
| 103 | # This will be handled by the rowblocksizes property | |
| 104 | return None | |
| 105 | return item.rows | |
| 106 | row_sizes = [_get_rows(i) for i in r if _get_rows(i) is not None] | |
| 107 | if row_sizes and len(set(row_sizes)) != 1: | |
| 108 | ok = False | |
| 101 | 109 | break |
| 102 | 110 | blocky = ok |
| 103 | 111 | # same number of cols for each matrix in each col |
| 104 | 112 | for c in range(len(rows[0])): |
| 105 | ok = len(set([rows[i][c].cols | |
| 106 | for i in range(len(rows))])) == 1 | |
| 107 | if not ok: | |
| 113 | def _get_cols(item): | |
| 114 | if isinstance(item, Zero): | |
| 115 | # For Zero objects, we can't determine cols here | |
| 116 | # This will be handled by the colblocksizes property | |
| 117 | return None | |
| 118 | return item.cols | |
| 119 | col_sizes = [_get_cols(rows[i][c]) for i in range(len(rows)) if _get_cols(rows[i][c]) is not None] | |
| 120 | if col_sizes and len(set(col_sizes)) != 1: | |
| 121 | ok = False | |
| 108 | 122 | break |
| 109 | 123 | if not ok: |
| 110 | 124 | # same total cols in each row |
| 111 | ok = len(set([ | |
| 112 | sum([i.cols for i in r]) for r in rows])) == 1 | |
| 125 | def _get_cols_sum(r): | |
| 126 | def _get_cols(item): | |
| 127 | if isinstance(item, Zero): | |
| 128 | # For Zero objects, we can't determine cols here | |
| 129 | # Return 0 and let rowblocksizes/colblocksizes handle it | |
| 130 | return 0 | |
| 131 | return item.cols | |
| 132 | return sum([_get_cols(i) for i in r]) | |
| 133 | ok = len(set([_get_cols_sum(r) for r in rows])) == 1 | |
| 113 | 134 | if blocky and ok: |
| 114 | 135 | raise ValueError(filldedent(''' |
| 115 | 136 | Although this matrix is comprised of blocks, |
| 133 | 154 | numrows = numcols = 0 |
| 134 | 155 | M = self.blocks |
| 135 | 156 | for i in range(M.shape[0]): |
| 136 | numrows += M[i, 0].shape[0] | |
| 157 | block = M[i, 0] | |
| 158 | if isinstance(block, Zero): | |
| 159 | # For Zero objects, use rowblocksizes to get the dimension | |
| 160 | numrows += self.rowblocksizes[i] | |
| 161 | else: | |
| 162 | numrows += block.shape[0] | |
| 137 | 163 | for i in range(M.shape[1]): |
| 138 | numcols += M[0, i].shape[1] | |
| 164 | block = M[0, i] | |
| 165 | if isinstance(block, Zero): | |
| 166 | # For Zero objects, use colblocksizes to get the dimension | |
| 167 | numcols += self.colblocksizes[i] | |
| 168 | else: | |
| 169 | numcols += block.shape[1] | |
| 139 | 170 | return (numrows, numcols) |
| 140 | 171 | |
| 141 | 172 | @property |
| 148 | 179 | |
| 149 | 180 | @property |
| 150 | 181 | def rowblocksizes(self): |
| 151 | return [self.blocks[i, 0].rows for i in range(self.blockshape[0])] | |
| 182 | def _get_block_rows(block, row_idx): | |
| 183 | if isinstance(block, Zero): | |
| 184 | # For Zero objects, infer rows from other blocks in the same row | |
| 185 | for j in range(self.blockshape[1]): | |
| 186 | other_block = self.blocks[row_idx, j] | |
| 187 | if not isinstance(other_block, Zero): | |
| 188 | return other_block.rows | |
| 189 | # If all blocks in row are Zero, infer from column structure | |
| 190 | for i in range(self.blockshape[0]): | |
| 191 | other_block = self.blocks[i, 0] | |
| 192 | if not isinstance(other_block, Zero): | |
| 193 | return other_block.rows | |
| 194 | # Fallback: assume 1x1 if we can't determine | |
| 195 | return 1 | |
| 196 | return block.rows | |
| 197 | ||
| 198 | return [_get_block_rows(self.blocks[i, 0], i) for i in range(self.blockshape[0])] | |
| 152 | 199 | |
| 153 | 200 | @property |
| 154 | 201 | def colblocksizes(self): |
| 155 | return [self.blocks[0, i].cols for i in range(self.blockshape[1])] | |
| 202 | def _get_block_cols(block, col_idx): | |
| 203 | if isinstance(block, Zero): | |
| 204 | # For Zero objects, infer cols from other blocks in the same column | |
| 205 | for i in range(self.blockshape[0]): | |
| 206 | other_block = self.blocks[i, col_idx] | |
| 207 | if not isinstance(other_block, Zero): | |
| 208 | return other_block.cols | |
| 209 | # If all blocks in column are Zero, infer from row structure | |
| 210 | for j in range(self.blockshape[1]): | |
| 211 | other_block = self.blocks[0, j] | |
| 212 | if not isinstance(other_block, Zero): | |
| 213 | return other_block.cols | |
| 214 | # Fallback: assume 1x1 if we can't determine | |
| 215 | return 1 | |
| 216 | return block.cols | |
| 217 | ||
| 218 | return [_get_block_cols(self.blocks[0, i], i) for i in range(self.blockshape[1])] | |
| 156 | 219 | |
| 157 | 220 | def structurally_equal(self, other): |
| 158 | 221 | return (isinstance(other, BlockMatrix) |
| Test Name | Status |
|---|---|
test_issue_17624 | Fail |
test_zero_matrix_add | Fail |
test_bc_matmul | Pass |
test_bc_matadd | Pass |
test_bc_transpose | Pass |
test_bc_dist_diag | Pass |
test_block_plus_ident | Pass |
test_BlockMatrix | Pass |
test_block_collapse_explicit_matrices | Pass |
test_BlockMatrix_trace | Pass |
test_BlockMatrix_Determinant | Pass |
test_squareBlockMatrix | Pass |
test_BlockDiagMatrix | Pass |
test_blockcut | Pass |
test_reblock_2x2 | Pass |
test_deblock | Pass |
test_sort_key | Pass |
test_matadd_sympify | Pass |
test_matadd_of_matrices | Pass |
test_doit_args | Pass |
test_generic_identity | Pass |
© 2025 Ridges AI. Building the future of decentralized AI development.