void Riccati ( ElementalMatrix<F>& WPre, ElementalMatrix<F>& X, SignCtrl<Base<F>> ctrl ) { DEBUG_CSE DistMatrixReadProxy<F,F,MC,MR> WProx( WPre ); auto& W = WProx.Get(); const Grid& g = W.Grid(); Sign( W, ctrl ); const Int n = W.Height()/2; DistMatrix<F> WTL(g), WTR(g), WBL(g), WBR(g); PartitionDownDiagonal ( W, WTL, WTR, WBL, WBR, n ); // (ML, MR) = sgn(W) - I ShiftDiagonal( W, F(-1) ); // Solve for X in ML X = -MR DistMatrix<F> ML(g), MR(g); PartitionRight( W, ML, MR, n ); MR *= -1; ls::Overwrite( NORMAL, ML, MR, X ); }
void Sylvester ( Int m, ElementalMatrix<F>& WPre, ElementalMatrix<F>& X, SignCtrl<Base<F>> ctrl ) { EL_DEBUG_CSE DistMatrixReadProxy<F,F,MC,MR> WProx( WPre ); auto& W = WProx.Get(); const Grid& g = W.Grid(); Sign( W, ctrl ); DistMatrix<F> WTL(g), WTR(g), WBL(g), WBR(g); PartitionDownDiagonal ( W, WTL, WTR, WBL, WBR, m ); // WTL and WBR should be the positive and negative identity, WBL should be // zero, and WTR should be -2 X Copy( WTR, X ); X *= -F(1)/F(2); // TODO: Think of how to probe for checks on other quadrants. // Add UpdateDiagonal routine to avoid explicit identity Axpy? /* typedef Base<F> Real; UpdateDiagonal( WTL, F(-1) ); const Real errorWTL = FrobeniusNorm( WTL ); const Int n = W.Height() - m; UpdateDiagonal( WBR, F(1) ); const Real errorWBR = FrobeniusNorm( WBR ); const Real errorWBL = FrobeniusNorm( WBL ); */ }
inline int Lyapunov( const DistMatrix<F>& A, const DistMatrix<F>& C, DistMatrix<F>& X ) { #ifndef RELEASE CallStackEntry cse("Sylvester"); if( A.Height() != A.Width() ) LogicError("A must be square"); if( C.Height() != A.Height() || C.Width() != A.Height() ) LogicError("C must conform with A"); if( A.Grid() != C.Grid() ) LogicError("A and C must have the same grid"); #endif const Grid& g = A.Grid(); const Int m = A.Height(); DistMatrix<F> W(g), WTL(g), WTR(g), WBL(g), WBR(g); Zeros( W, 2*m, 2*m ); PartitionDownDiagonal ( W, WTL, WTR, WBL, WBR, m ); WTL = A; Adjoint( A, WBR ); Scale( F(-1), WBR ); WTR = C; Scale( F(-1), WTR ); return Sylvester( m, W, X ); }