K i{ddlmZmZddlmZmZmZmZddlm Z ddl m Z m Z ddl mZmZmZmZmZddlmZddlmZmZddlmZdd lmZmZdd lmZdd lm Z m!Z!dd l"m#Z#dd l$m%Z%ddl&m'Z'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl/m0Z0m1Z1ddl2m3Z3ddl4m5Z5m6Z6Gdde'Z7Gdde7Z8dZ9dZ:dZ;dZdZ?d Z@d!ZAd"ZBd#ZCd$ZDd%ZEd&ZFd'ZGy()))Qask)BasicAddMulS)_sympify)reim)typedexhaust conditiondo_oneunpack) bottom_up) is_sequencesift) filldedent)Matrix ShapeError)NonInvertibleMatrixError)det Determinant)Inverse)MatAdd) MatrixExpr MatrixElement)MatMul)MatPow) MatrixSlice) ZeroMatrixIdentity)trace) Transpose transposeceZdZdZdZedZedZedZedZ edZ dZ d Z d Z d Zd Zd ZdZdZdZdZddZdZdZdZdZedZedZfdZxZS) BlockMatrixauA BlockMatrix is a Matrix comprised of other matrices. The submatrices are stored in a SymPy Matrix object but accessed as part of a Matrix Expression >>> from sympy import (MatrixSymbol, BlockMatrix, symbols, ... Identity, ZeroMatrix, block_collapse) >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) >>> print(B) Matrix([ [X, Z], [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]]) >>> print(block_collapse(C*B)) Matrix([[X, Z + Z*Y]]) Some matrices might be comprised of rows of blocks with the matrices in each row having the same height and the rows all having the same total number of columns but not having the same number of columns for each matrix in each row. In this case, the matrix is not a block matrix and should be instantiated by Matrix. >>> from sympy import ones, Matrix >>> dat = [ ... [ones(3,2), ones(3,3)*2], ... [ones(2,3)*3, ones(2,2)*4]] ... >>> BlockMatrix(dat) Traceback (most recent call last): ... ValueError: Although this matrix is comprised of blocks, the blocks do not fill the matrix in a size-symmetric fashion. To create a full matrix from these arguments, pass them directly to Matrix. >>> Matrix(dat) Matrix([ [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [3, 3, 3, 4, 4], [3, 3, 3, 4, 4]]) See Also ======== sympy.matrices.matrixbase.MatrixBase.irregular c ddlm}d}t|dk7s3t|dr%t|dDchc] }|| c}dk7rt t d|r|dng}||s&|r||dr|g}t|Dchc] }t|c}dk(x}}|r|D],}t|D chc]} | j c} dk(}|r,n|}|r^tt|dD]D} ttt|D chc]} || | jc} dk(}|rDn|sXt|Dchc]}td|Dc}dk(}|r|rt t dt t d||d } tj|| } | Scc}wcc}wcc} wcc} wcc}w) NrImmutableDenseMatrixct|ddS)N is_MatrixF)getattr)is l/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/sympy/matrices/expressions/blockmatrix.pyz%BlockMatrix.__new__..Rs'![%8z\ expecting a sequence of 1 or more rows containing Matrices.c34K|]}|jywNcols).0r.s r/ z&BlockMatrix.__new__..qs*1*a0 Although this matrix is comprised of blocks, the blocks do not fill the matrix in a size-symmetric fashion. To create a full matrix from these arguments, pass them directly to Matrix.a} When there are not the same number of rows in each row's matrices or there are not the same number of total columns in each row, the matrix is not a block matrix. If this matrix is known to consist of blocks fully filling a 2-D space then see Matrix.irregular.Fevaluate) sympy.matrices.immutabler*lenr ValueErrorrrowsranger6sumr__new__) clsargskwargsr*isMatrr?blockyokr.cmatobjs r/rBzBlockMatrix.__new__PsA8 t9>Q(tAw/!U1X/0A5Z)()* *tAwBT{d1gvt4!s1v45: :FRAa0aff01Q6B"3tAw<0" %*3t9%5"7 !#'q'!*//"78;<=!! " 48:/0C***:;>?@b$Z1#&$%% !-)"*++#4%8mmC% [051"7 :sF9 F>8G G G cdx}}|j}t|jdD]}|||dfjdz }t|jdD]}||d|fjdz }||fSNrr2)blocksr@shape)selfnumrowsnumcolsMr.s r/rPzBlockMatrix.shapes' KKqwwqz" (A qAw}}Q' 'G (qwwqz" (A qAw}}Q' 'G (!!r1c.|jjSr4rOrPrQs r/ blockshapezBlockMatrix.blockshapes{{   r1c |jdSNrrDrWs r/rOzBlockMatrix.blockssyy|r1ct|jdDcgc]}|j|dfjc}Scc}wrZ)r@rXrOr?rQr.s r/ rowblocksizeszBlockMatrix.rowblocksizes705dooa6H0IJ1 AqD!&&JJJ"Act|jdDcgc]}|jd|fjc}Scc}w)Nr2r)r@rXrOr6r]s r/ colblocksizeszBlockMatrix.colblocksizesr_r`ct|txrj|j|jk(xrO|j|jk(xr4|j|jk(xr|j |j k(Sr4) isinstancer'rPrXr^rbrQothers r/structurally_equalzBlockMatrix.structurally_equalss5+.: ekk):5#3#33:""e&9&99:""e&9&99  ;r1ct|tr;|j|jk(r"t|j|jzS||zSr4)rdr'rbr^rOres r/ _blockmulzBlockMatrix._blockmulsB uk *""e&9&99t{{5<<78 8e|r1ct|tr3|j|r"t|j|jzS||zSr4)rdr'rgrOres r/ _blockaddzBlockMatrix._blockadds< uk *++E2t{{U\\9: :e|r1c|jDcgc] }t|}}t|jd|jd|}|j}t |Scc}wrN)rOr%rrXr')rQmatrixmatricesrTs r/_eval_transposezBlockMatrix._eval_transposesY48KK@&If%@@ 4??1%tq'98 D KKM1~ AsA%ctt|jd|jd|jj SrN)r'rrXrOadjointrWs r/ _eval_adjointzBlockMatrix._eval_adjoints: 4??1%tq'94;; G O O Q  r1c|j|jk(rSt|jdDcgc]}|j||f}}t |Dcgc] }t |c}Sycc}wcc}wrZ)r^rbr@rXrOrr#)rQr.rOblocks r/ _eval_tracezBlockMatrix._eval_tracesi   !3!3 316tq7I1JKAdkk!Q$'KFK6:%u:; ; 4K:s A.A3c|jdk(rt|jdS|jdk(r|jj\\}}\}}t t j |r*t|t|||jz|zz zSt t j |r*t|t|||jz|zz zSt|S)Nr2r2rrrz) rXrrOtolistrr invertibleIr)rQABCDs r/_eval_determinantzBlockMatrix._eval_determinants ??f $t{{4() ) ??f ${{))+ Va a1<<?#1vc!aeAg+...Q\\!_%1vc!aeAg+...4  r1cf|jDcgc] }t|}}t|jd|jd|}|jDcgc] }t |}}t|jd|jd|}t |t |fScc}wcc}wrN)rOr rrXr r')rQrm real_matrices im_matricess r/_eval_as_real_imagzBlockMatrix._eval_as_real_imags26++>F> >tq14??13E}U 04 >> from sympy import MatrixSymbol, BlockMatrix, ZeroMatrix >>> from sympy.abc import m, n >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) >>> B.transpose() Matrix([ [X.T, 0], [Z.T, Y.T]]) >>> _.transpose() Matrix([ [X, Z], [0, Y]]) )rorWs r/r%zBlockMatrix.transposes*##%%r1c|jdk(r|jj\\}}\}}||||d} |r3||j||zj ||jzn||j }|dk(r |||z|zz S|dk(r |||z|zz S|dk(r |||z|zz S|dk(r |||z|zz S|St d#t $r t dwxYw) a Return the Schur Complement of the 2x2 BlockMatrix Parameters ========== mat : String, optional The matrix with respect to which the Schur Complement is calculated. 'A' is used by default generalized : bool, optional If True, returns the generalized Schur Component which uses Moore-Penrose Inverse Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) The default Schur Complement is evaluated with "A" >>> X.schur() -C*A**(-1)*B + D >>> X.schur('D') A - B*D**(-1)*C Schur complement with non-invertible matrices is not defined. Instead, the generalized Schur complement can be calculated which uses the Moore-Penrose Inverse. To achieve this, `generalized` must be set to `True` >>> X.schur('B', generalized=True) C - D*(B.T*B)**(-1)*B.T*A >>> X.schur('C', generalized=True) -A*(C.T*C)**(-1)*C.T*D + B Returns ======= M : Matrix The Schur Complement Matrix Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If given matrix is non-invertible References ========== .. [1] Wikipedia Article on Schur Component : https://en.wikipedia.org/wiki/Schur_complement See Also ======== sympy.matrices.matrixbase.MatrixBase.pinv ry)r~rrrr~rrrzThe given matrix is not invertible. Please set generalized=True to compute the generalized Schur Complement which uses Moore-Penrose Inversez>Schur Complement can only be calculated for 2x2 block matrices)rXrOr{Tinvrr) rQrK generalizedr~rrrdrs r/schurzBlockMatrix.schursJ ??f ${{))+ Va aaq2A [:Eqvxx#++-afhh61S6::<#:q3w{?*CZq3w{?*CZq3w{?*CZq3w{?* ]^ ^ , [.0Z[[ [s$ACC#C3CCC%c|jdk(r|jj\\}}\}} |j}t |j d}t |j d}t|j }t||g||z|gg} t||j}t|||zg|j|gg} | || fStd#t$r t dwxYw)aLReturns the Block LDU decomposition of a 2x2 Block Matrix Returns ======= (L, D, U) : Matrices L : Lower Diagonal Matrix D : Diagonal Matrix U : Upper Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> L, D, U = X.LDUdecomposition() >>> block_collapse(L*D*U) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "A" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition ryzTBlock LDU decomposition cannot be calculated when "A" is singularrr2z@Block LDU decomposition is supported only for 2x2 block matrices) rXrOr{r}rr"rPr!r'BlockDiagMatrixrrr) rQr~rrrAIIpIqZLUs r/LDUdecompositionzBlockMatrix.LDUdecompositionPsT ??e #{{))+ Va a &SS!''!*%B!''!*%BAGG$Ab!WqtRj12A4::<0Ab"Q$Zb 23Aa7N_` `, &.0%&& &s CC3c|jdk(r|jj\\}}\}} |j}t |j d}t |j d}t|j }t|||zg|j|gg} t|jd|}t||g||z|gg} | || fStd#t$r t dwxYw)aLReturns the Block UDL decomposition of a 2x2 Block Matrix Returns ======= (U, D, L) : Matrices U : Upper Diagonal Matrix D : Diagonal Matrix L : Lower Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> U, D, L = X.UDLdecomposition() >>> block_collapse(U*D*L) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "D" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition ryzTBlock UDL decomposition cannot be calculated when "D" is singularrr2rz@Block UDL decomposition is supported only for 2x2 block matrices) rXrOr{r}rr"rPr!r'rrrr) rQr~rrrDIrrrrrs r/UDLdecompositionzBlockMatrix.UDLdecompositionsT ??e #{{))+ Va a &SS!''!*%B!''!*%BAGG$Ab!B$Z!##r34A 33Ab!WbdBZ01Aa7N_` `, &.0%&& &s CC4c|jdk(r|jj\\}}\}} |tjz}|j }t|j}|jtjz}t||g||z|gg}t|||zg|j|gg} || fStd#t $r t dwxYw)a#Returns the Block LU decomposition of a 2x2 Block Matrix Returns ======= (L, U) : Matrices L : Lower Diagonal Matrix U : Upper Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> L, U = X.LUdecomposition() >>> block_collapse(L*U) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "A" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition ryzSBlock LU decomposition cannot be calculated when "A" is singularz?Block LU decomposition is supported only for 2x2 block matrices) rXrOr{rHalfr}rr!rPrr'rr) rQr~rrrrrrrrs r/LUdecompositionzBlockMatrix.LUdecompositionsR ??e #{{))+ Va a &qvvISSAGG$A aff$AaVadAY/0AaAYQx01Aa4K^_ _, &.0%&& &s CCc ||}}t|jD]@\}}||k}|dk(rn1|dk(r||z}||jddz ks3t|||cSt|jD]@\} } || k}|dk(rn1|dk(r|| z}| |jddz ks3t|||cS|j  f||fS)NTFrr2) enumerater^rXrrbrO) rQr.jrEorig_iorig_j row_blockrRcmp col_blockrSs r/_entryzBlockMatrix._entrysA"+D,>,>"? ; Iwg+Cd{W T__Q/!33$T66:: ;#,D,>,>"? ; Iwg+Cd{W T__Q/!33$T66:: ;{{9i/0A66r1cF|jd|jdk7ryt|jdD]f}t|jdD]I}||k(r|j||fjsy||k7s,|j||fjrHyhy)Nrr2FT)rXr@rO is_Identity is_ZeroMatrix)rQr.rs r/rzBlockMatrix.is_Identitys ??1 !3 3tq)* !A4??1-. !a4 AqD 1 = = a4 AqD 1 ? ?  ! ! r1c4|j|jk(Sr4)r^rbrWs r/is_structurally_symmetricz%BlockMatrix.is_structurally_symmetric$s!!T%7%777r1c||k(ryt|tr|j|jk(ryt||S)NT)rdr'rOsuperequals)rQrf __class__s r/rzBlockMatrix.equals(s8 5= uk *t{{ell/Jw~e$$r1)r~F)__name__ __module__ __qualname____doc__rBpropertyrPrXrOr^rbrgrirkrorrrurrrr%rrrrrrrr __classcell__)rs@r/r'r's6n2h""!!KKKK; < !F0&.Y_v:ax:ax8`t7,  88%%r1r'ceZdZdZdZedZedZedZedZ edZ edZ d Z d Z dd Zd Zd ZdZdZy)raA sparse matrix with block matrices along its diagonals Examples ======== >>> from sympy import MatrixSymbol, BlockDiagMatrix, symbols >>> n, m, l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> BlockDiagMatrix(X, Y) Matrix([ [X, 0], [0, Y]]) Notes ===== If you want to get the individual diagonal blocks, use :meth:`get_diag_blocks`. See Also ======== sympy.matrices.dense.diag c ntjtg|Dcgc] }t|c}Scc}wr4)rrBrr )rCmatsms r/rBzBlockDiagMatrix.__new__Js(}}_KT/J /JKK/Js2 c|jSr4r[rWs r/diagzBlockDiagMatrix.diagMs yyr1c 2ddlm}|j}tt |Dcgc]R}tt |Dcgc]2}||k(r||n%t ||j ||j4c}T}}}||dScc}wcc}}w)Nrr)Fr:)r<r*rDr@r=r!r?r6)rQr*rr.rdatas r/rOzBlockDiagMatrix.blocksQsAyy"'s4y!13"'s4y!13Fa 47<<a(NN333$D59933sB7B <BBcrtd|jDtd|jDfS)Nc34K|]}|jywr4)r?r7rts r/r8z(BlockDiagMatrix.shape..\65EJJ6r9c34K|]}|jywr4r5rs r/r8z(BlockDiagMatrix.shape..]rr9)rArDrWs r/rPzBlockDiagMatrix.shapeZs06DII666DII668 8r1c4t|j}||fSr4)r=rD)rQns r/rXzBlockDiagMatrix.blockshape_s  N1v r1cT|jDcgc]}|jc}Scc}wr4)rDr?rQrts r/r^zBlockDiagMatrix.rowblocksizesd(, 2u 222%cT|jDcgc]}|jc}Scc}wr4)rDr6rs r/rbzBlockDiagMatrix.colblocksizeshrrc:td|jDS)z%Returns true if all blocks are squarec34K|]}|jywr4) is_square)r7rKs r/r8z5BlockDiagMatrix._all_square_blocks..ns6S3==6r9)allrDrWs r/_all_square_blocksz"BlockDiagMatrix._all_square_blocksls6DII666r1c|jr)t|jDcgc] }t|c}Stj Scc}wr4)rrrDrrZerorQrKs r/rz!BlockDiagMatrix._eval_determinantps<  " " $TYY7cS78 8vv 8sA c|jr.t|jDcgc]}|jc}St dcc}w)Nz Matrix det == 0; not invertible.)rrrDinverser)rQexpandrKs r/ _eval_inversezBlockDiagMatrix._eval_inversews@  " " $"dii$HsS[[]$HI I&'IJJ%IsA cht|jDcgc]}|jc}Scc}wr4)rrDr%rs r/rozBlockDiagMatrix._eval_transpose}s%DII FS FGG Fs/ct|trU|j|jk(r>> from sympy import BlockDiagMatrix, Matrix >>> A = Matrix([[1, 2], [3, 4]]) >>> B = Matrix([[5, 6], [7, 8]]) >>> M = BlockDiagMatrix(A, B) How to get diagonal blocks from the block diagonal matrix: >>> diag_blocks = M.get_diag_blocks() >>> diag_blocks[0] Matrix([ [1, 2], [3, 4]]) >>> diag_blocks[1] Matrix([ [5, 6], [7, 8]]) r[rWs r/get_diag_blockszBlockDiagMatrix.get_diag_blockss0yyr1N)ignored)rrrrrBrrrOrPrXr^rbrrrrorirkrr1r/rr0s2L::8833337K H66r1rcddlm}d}t|ttt t ttt ttttttttt t t"t$i}t't)t'||}||}t+|dd}||S|S)aEvaluates a block matrix expression >>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, ZeroMatrix, block_collapse >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m, m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m, n), Y]]) >>> print(B) Matrix([ [X, Z], [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]]) >>> print(block_collapse(C*B)) Matrix([[X, Z + Z*Y]]) r)expr_fnscPt|txr|jtSr4)rdrhasr'exprs r/r0z block_collapse..sD*5O$((;:Or1)fnsdoitN)sympy.strategies.utilrrr rr bc_mataddbc_block_plus_identr bc_matmulbc_distrr$ bc_transposer bc_inverser' bc_unpackdeblockr rr-)rrhasbmconditioned_rlruleresultrs r/block_collapsers*/ OE  VI':; VIw/ Y  j &G4  6  N  N #  D$ZF 664 (D v  r1cB|jdk(r|jdS|S)Nrwrx)rXrOrs r/rrs" & {{4  Kr1ct|jd}|d}|s|S|d}|d}|ddD]}|j|}|r t||zS|S)Nc"t|tSr4rdr')rTs r/r0zbc_matadd..s Z;%?r1TFrr2)rrDrkr)rrDrO nonblocksrtrs r/rrsq  ? @D $ZF  U I 1IE ABZ#"#y!E)) r1c:|jDcgc]}|js|}}|s|S|jDcgc]}t|ts|c}rt fdDrdj rt djDcgc] }t|c}}|jDcgc]"}|jrt|tr!|$}}t|t|zg|jS|Scc}wcc}wcc}wcc}w)Nc3FK|]}|jdyw)rN)rg)r7rrOs r/r8z&bc_block_plus_ident..s G1q++F1I6Gs!r) rDrrdr'rrrr^r"rr=r)rargidentskblock_idrestrOs @r/rrs!YY :c#//c :F :  !YY Gc*S+*Fc GF3GGG!966"171H1H%J,-&.a[%JK#yye SVXcHdeehV,=v==BBDD K;H%Jes-D D DDD6DDDc |j\}}|dk(r|St|}t|tr&|j}|Dcgc]}||z }}t|St|t rd|j }t|jDcgc]-}t|jDcgc] }||||fzc}/}}}t |S|Scc}wcc}wcc}}w)z Turn a*[X, Y] into [a*X, a*Y] r2) as_coeff_mmulrrdrrr'rOr@r?r6)rfactorrKunpackedrnew_Br.rs r/rrs$$&KFC { c{H(O, MM)*+##++&& Hk * OO?DQVV}N:;uQVV} 5!Va1g  5NN5!! K, 6Ns CC,C =CCc(t|trP|jdjr5|jddkDr#d|jdg|jdz}}n|S|j \}}d}|dzt |kr|||dz\}}t|t r9t|t r)|j|||<|j|dznt|t r4|jt |gg||<|j|dznIt|t r4t |ggj|||<|j|dzn|dz }|dzt |krt|g|jS)Nr2rrz) rdrrD is_Integeras_coeff_matricesr=r'ripoprr)rrrnr.r~rs r/rrsb$ 99Q< " "tyy|a'7 499Q<.1"=HFK113 A Q3X !A#1 a %*Q *D++a.HQK LL1  ; '++kA3%&89HQK LL1  ; '%se,66q9HQK LL1  qDA Q3X  & $8 $ ) ) ++r1cLt|j}|jSr4)rrro)rcollapses r/rr.sdhh'H  # # %%r1ct|jtr|jSt |}||k7r|St t t|jSr4)rdrrrblockinverse_1x1blockinverse_2x2r reblock_2x2)rexpr2s r/rr3sK$((O,||~ T "E u} GK$9: ;;r1ct|jtrV|jjdk(r=t |jj dj gg}t|S|S)Nrwr)rdrr'rXrrOr)rrKs r/rr<sW$((K(TXX-@-@F-Jtxxq)1134563 Kr1c2t|jtr{|jjdk(ra|jjj \\}}\}}t ||||}|dk7r%|jj|j}|dk(r:|j}t|||zz|z|zz| |z|zg| |z|z|ggS|dk(r:|j}t |z|z|g|||z|z|z|zz| |z|zggS|dk(r:|j} t| |zz| | |z|z|z| zzg|| |z| zggS|dk(r:|j} t| |z| zg| |z|z| | |z|z|z| zzggS|S)Nryr~rrr) rdrr'rXrOr{_choose_2x2_inversion_formularr}) rr~rrrformulaMIrBICIrs r/rrCs$((K(TXX-@-@F-J88??))+ !Q !Q/1a; d?(**B c>Bb1frkAo&:!:RC!GbL IRCRSGVXLZ\K]^_ _ c>B"q2r 2R"q&2+/B:N5NQSPSVWPWZ\P\4]^_ _ c>B"q2rBFRK!Ob4H/H IBQSPSVWPWZ\P\K]^_ _ c>BbS1Wr\ 2bS1Wr\2QQS VWZ\H\C\4]^_ _ Kr1cTttj|}|dk(ryttj|}|dk(ryttj|}|dk(ryttj|}|dk(ry|dk7ry|dk7ry|dk7ry|dk7ryy)a\ Assuming [[A, B], [C, D]] would form a valid square block matrix, find which of the classical 2x2 block matrix inversion formulas would be best suited. Returns 'A', 'B', 'C', 'D' to represent the algorithm involving inversion of the given argument or None if the matrix cannot be inverted using any of those formulas. Tr~rrrFN)rrr|)r~rrrA_invB_invC_invD_invs r/rr\s  Q E }  Q E }  Q E }  Q E } ~ ~ ~ ~ r1c Tt|tr|jjts|Sd}|jj | t dt fdtjdDg}tdjdD]k}t |dfj}tdjdD]"}|j||fj}$|j|}mt|S#t$r|cYSwxYw)z( Flatten a BlockMatrix of BlockMatrices c@t|tr|St|ggSr4r)rs r/r0zdeblock..s*Q 4Q+se:Lr1rc3ZK|]"}d|fjjd$yw)rr2NrV)r7r.bbs r/r8zdeblock..s(P2ad8??003Ps(+r2) rdr'rOr applyfuncrrAr@rProw_joincol_joinr)rwrapMMrowrTcolr%s @r/rrs a %QXX\\+-F LD   D !B  AsPU288A;=OPPRT UBHHQK( Cr#q&z(()AQ , 4JJr#s(|223 4QB  2 sCD D'&D'c rt|trtd|jDs|St}|j\}}|j}t d|D]}t d|D]}t ||d|d|f}t ||d||df}t |||dd|f} t |||d|df} t||| | } | |t||g| | ggccS||d||dddfg||dddf||ddddfggS)z Reblock a BlockMatrix so that it has 2x2 blocks of block matrices. If possible in such a way that the matrix continues to be invertible using the classical 2x2 block inversion formulas. c3&K|] }|dkD yw)rzNr)r7rs r/r8zreblock_2x2..s3SaAE3Ssr2Nrxr)rdr'rrXrOr@rr) rBM rowblocks colblocksrOr.rr~rrrrs r/rrsd dK (3S4??3S0S B??Iy [[F 1i 5q)$ 5A"VBQBF^,-A"VBQBF^,-A"VABF^,-A"VABF^,-A3Aq!Q?G""QFQF#344 5 5 t b12/06!"a%=!2fQRVn#568 99r1cRd}g}|D]}|j|||zf||z }|S)z Convert sequence of numbers into pairs of low-high pairs >>> from sympy.matrices.expressions.blockmatrix import bounds >>> bounds((1, 10, 50)) [(0, 1), (1, 11), (11, 61)] r)append)sizeslowrvsizes r/boundsr8sB C B 3d #$ t  Ir1ct|}t|}t|Dcgc]}|Dcgc]}t|||c}c}}Scc}wcc}}w)a Cut a matrix expression into Blocks >>> from sympy import ImmutableMatrix, blockcut >>> M = ImmutableMatrix(4, 4, range(16)) >>> B = blockcut(M, (1, 3), (1, 3)) >>> type(B).__name__ 'BlockMatrix' >>> ImmutableMatrix(B.blocks[0, 1]) Matrix([[1, 2, 3]]) )r8r'r )rrowsizescolsizes rowbounds colboundsrowboundcolbounds r/blockcutr@sax Ix I )24%*34%%T8X>44 5544s A A A A N)Hsympy.assumptions.askrr sympy.corerrrrsympy.core.sympifyr $sympy.functions.elementary.complexesr r sympy.strategiesr r rrrsympy.strategies.traversersympy.utilities.iterablesrrsympy.utilities.miscrsympy.matricesrrsympy.matrices.exceptionsr&sympy.matrices.expressions.determinantrr"sympy.matrices.expressions.inverser!sympy.matrices.expressions.mataddr"sympy.matrices.expressions.matexprrr!sympy.matrices.expressions.matmulr!sympy.matrices.expressions.matpowr sympy.matrices.expressions.slicer "sympy.matrices.expressions.specialr!r" sympy.matrices.expressions.tracer#$sympy.matrices.expressions.transposer$r%r'rrrrrrrrrrrrrrr8r@rr1r/rUs*))'7FF/7+->C64H448C2EU%*U%pxkxv1f  (,2& <2!H(9: 5r1