void Sign( Matrix<F>& A, Matrix<F>& N, const SignCtrl<Base<F>> ctrl ) { DEBUG_CSE Matrix<F> ACopy( A ); sign::Newton( A, ctrl ); Gemm( NORMAL, NORMAL, F(1), A, ACopy, N ); }
inline typename Base<F>::type LogDetDivergence ( UpperOrLower uplo, const DistMatrix<F>& A, const DistMatrix<F>& B ) { #ifndef RELEASE PushCallStack("LogDetDivergence"); #endif if( A.Grid() != B.Grid() ) throw std::logic_error("A and B must use the same grid"); if( A.Height() != A.Width() || B.Height() != B.Width() || A.Height() != B.Height() ) throw std::logic_error ("A and B must be square matrices of the same size"); typedef typename Base<F>::type R; const int n = A.Height(); const Grid& g = A.Grid(); DistMatrix<F> ACopy( A ); DistMatrix<F> BCopy( B ); Cholesky( uplo, ACopy ); Cholesky( uplo, BCopy ); if( uplo == LOWER ) { Trtrsm( LEFT, uplo, NORMAL, NON_UNIT, F(1), BCopy, ACopy ); } else { MakeTrapezoidal( LEFT, uplo, 0, ACopy ); Trsm( LEFT, uplo, NORMAL, NON_UNIT, F(1), BCopy, ACopy ); } MakeTrapezoidal( LEFT, uplo, 0, ACopy ); const R frobNorm = Norm( ACopy, FROBENIUS_NORM ); R logDet; R localLogDet(0); DistMatrix<F,MD,STAR> d(g); ACopy.GetDiagonal( d ); if( d.InDiagonal() ) { const int nLocalDiag = d.LocalHeight(); for( int iLocal=0; iLocal<nLocalDiag; ++iLocal ) { const R delta = RealPart(d.GetLocal(iLocal,0)); localLogDet += 2*Log(delta); } } mpi::AllReduce( &localLogDet, &logDet, 1, mpi::SUM, g.VCComm() ); const R logDetDiv = frobNorm*frobNorm - logDet - R(n); #ifndef RELEASE PopCallStack(); #endif return logDetDiv; }
void TransformRows ( const Matrix<F>& V, Matrix<F>& A ) { DEBUG_CSE // TODO(poulson): Consider forming chunk-by-chunk to save memory Matrix<F> ACopy( A ); Gemm( ADJOINT, NORMAL, F(1), V, ACopy, A ); }
QDWHInfo QDWH( Matrix<F>& A, Matrix<F>& P, const QDWHCtrl& ctrl ) { EL_DEBUG_CSE Matrix<F> ACopy( A ); auto info = QDWH( A, ctrl ); Zeros( P, A.Height(), A.Height() ); Trrk( LOWER, NORMAL, NORMAL, F(1), A, ACopy, F(0), P ); MakeHermitian( LOWER, P ); return info; }
void Sign ( AbstractDistMatrix<Field>& APre, AbstractDistMatrix<Field>& NPre, const SignCtrl<Base<Field>> ctrl ) { EL_DEBUG_CSE DistMatrixReadWriteProxy<Field,Field,MC,MR> AProx( APre ); DistMatrixWriteProxy<Field,Field,MC,MR> NProx( NPre ); auto& A = AProx.Get(); auto& N = NProx.Get(); DistMatrix<Field> ACopy( A ); sign::Newton( A, ctrl ); Gemm( NORMAL, NORMAL, Field(1), A, ACopy, N ); }
void Sign ( ElementalMatrix<F>& APre, ElementalMatrix<F>& NPre, const SignCtrl<Base<F>> ctrl ) { DEBUG_CSE DistMatrixReadWriteProxy<F,F,MC,MR> AProx( APre ); DistMatrixWriteProxy<F,F,MC,MR> NProx( NPre ); auto& A = AProx.Get(); auto& N = NProx.Get(); DistMatrix<F> ACopy( A ); sign::Newton( A, ctrl ); Gemm( NORMAL, NORMAL, F(1), A, ACopy, N ); }
ValueInt<Base<F>> InverseFreeSignDivide( ElementalMatrix<F>& XPre ) { DEBUG_CSE DistMatrixReadWriteProxy<F,F,MC,MR> XProx( XPre ); auto& X = XProx.Get(); typedef Base<F> Real; const Grid& g = X.Grid(); const Int n = X.Width(); if( X.Height() != 2*n ) LogicError("Matrix should be 2n x n"); // Expose A and B, and then copy A auto B = X( IR(0,n ), ALL ); auto A = X( IR(n,2*n), ALL ); DistMatrix<F> ACopy( A ); // Run the inverse-free alternative to Sign InverseFreeSign( X ); // Compute the pivoted QR decomp of inv(A + B) A [See LAWN91] // 1) B := A + B // 2) [Q,R,Pi] := QRP(A) // 3) B := Q^H B // 4) [R,Q] := RQ(B) B += A; DistMatrix<F,MD,STAR> t(g); DistMatrix<Base<F>,MD,STAR> d(g); DistMatrix<Int,VR,STAR> p(g); QR( A, t, d, p ); qr::ApplyQ( LEFT, ADJOINT, A, t, d, B ); RQ( B, t, d ); // A := Q^H A Q A = ACopy; rq::ApplyQ( LEFT, ADJOINT, B, t, d, A ); rq::ApplyQ( RIGHT, NORMAL, B, t, d, A ); // Return || E21 ||1 / || A ||1 // Return || E21 ||1 / || A ||1 ValueInt<Real> part = ComputePartition( A ); part.value /= OneNorm(ACopy); return part; }
inline typename Base<F>::type LogDetDivergence( UpperOrLower uplo, const Matrix<F>& A, const Matrix<F>& B ) { #ifndef RELEASE PushCallStack("LogDetDivergence"); #endif if( A.Height() != A.Width() || B.Height() != B.Width() || A.Height() != B.Height() ) throw std::logic_error ("A and B must be square matrices of the same size"); typedef typename Base<F>::type R; const int n = A.Height(); Matrix<F> ACopy( A ); Matrix<F> BCopy( B ); Cholesky( uplo, ACopy ); Cholesky( uplo, BCopy ); if( uplo == LOWER ) { Trtrsm( LEFT, uplo, NORMAL, NON_UNIT, F(1), BCopy, ACopy ); } else { MakeTrapezoidal( LEFT, uplo, 0, ACopy ); Trsm( LEFT, uplo, NORMAL, NON_UNIT, F(1), BCopy, ACopy ); } MakeTrapezoidal( LEFT, uplo, 0, ACopy ); const R frobNorm = Norm( ACopy, FROBENIUS_NORM ); Matrix<F> d; ACopy.GetDiagonal( d ); R logDet(0); for( int i=0; i<n; ++i ) logDet += 2*Log( RealPart(d.Get(i,0)) ); const R logDetDiv = frobNorm*frobNorm - logDet - R(n); #ifndef RELEASE PopCallStack(); #endif return logDetDiv; }
QDWHInfo QDWH ( AbstractDistMatrix<F>& APre, AbstractDistMatrix<F>& PPre, const QDWHCtrl& ctrl ) { EL_DEBUG_CSE DistMatrixReadWriteProxy<F,F,MC,MR> AProx( APre ); DistMatrixWriteProxy<F,F,MC,MR> PProx( PPre ); auto& A = AProx.Get(); auto& P = PProx.Get(); DistMatrix<F> ACopy( A ); auto info = QDWH( A, ctrl ); Zeros( P, A.Height(), A.Height() ); Trrk( LOWER, NORMAL, NORMAL, F(1), A, ACopy, F(0), P ); MakeHermitian( LOWER, P ); return info; }
Base<F> InverseFreeSignDivide( Matrix<F>& X ) { DEBUG_CSE typedef Base<F> Real; const Int n = X.Width(); if( X.Height() != 2*n ) LogicError("Matrix should be 2n x n"); // Expose A and B, and then copy A auto B = X( IR(0,n ), ALL ); auto A = X( IR(n,2*n), ALL ); Matrix<F> ACopy( A ); // Run the inverse-free alternative to Sign InverseFreeSign( X ); // Compute the pivoted QR decomp of inv(A + B) A [See LAWN91] // 1) B := A + B // 2) [Q,R,Pi] := QRP(A) // 3) B := Q^H B // 4) [R,Q] := RQ(B) B += A; Matrix<F> t; Matrix<Base<F>> d; Matrix<Int> p; QR( A, t, d, p ); qr::ApplyQ( LEFT, ADJOINT, A, t, d, B ); RQ( B, t, d ); // A := Q^H A Q A = ACopy; rq::ApplyQ( LEFT, ADJOINT, B, t, d, A ); rq::ApplyQ( RIGHT, NORMAL, B, t, d, A ); // Return || E21 ||1 / || A ||1 ValueInt<Real> part = ComputePartition( A ); part.value /= OneNorm(ACopy); return part; }
inline void SVDUpper ( DistMatrix<F>& A, DistMatrix<typename Base<F>::type,VR,STAR>& s, DistMatrix<F>& V, double heightRatio=1.5 ) { #ifndef RELEASE PushCallStack("svd::SVDUpper"); if( A.Height() < A.Width() ) throw std::logic_error("A must be at least as tall as it is wide"); if( heightRatio <= 1.0 ) throw std::logic_error("Nonsensical switchpoint for SVD"); #endif const Grid& g = A.Grid(); const int m = A.Height(); const int n = A.Width(); if( m > heightRatio*n ) { DistMatrix<F> R(g); ExplicitQR( A, R ); svd::SimpleSVDUpper( R, s, V ); // Unfortunately, extra memory is used in forming A := A R, // where A has been overwritten with the Q from the QR factorization // of the original state of A, and R has been overwritten with the U // from the SVD of the R from the QR factorization of A // // Perhaps this should be broken into pieces. DistMatrix<F> ACopy( A ); Gemm( NORMAL, NORMAL, F(1), ACopy, R, F(0), A ); } else { svd::SimpleSVDUpper( A, s, V ); } #ifndef RELEASE PopCallStack(); #endif }
std::tuple<bool, CMatrix2D const, std::vector<double> > LinearSolver::GaussElim(CMatrix2D const & A, std::vector<double> const & f) { // Solve the equation A x = f using Gauss' elimination method with // row pivoting. // Description of algorithm: First, search for the largest element // in all following row and use it as the pivot element. This is to // reduce round-off errors. The matrix ACopy will be transformed // into the identity matrix, while the identity matrix, AInv, will // be transformed into the inverse. // A x = Id y is successively transformed into A^{-1} A x = A^{-1} Id f, // where ACopy = Id and A^{-1} = AInv. boost::uint64_t max_col = A.getCols(); boost::uint64_t max_row = A.getRows(); bool success = false; CMatrix2D ACopy(A); CMatrix2D AInv(CMatrix2D::identity(max_col)); std::vector<double> rhs(f); bool assert_cond = max_col == max_row; BOOST_ASSERT_MSG(assert_cond, "LinearSolver::GaussElim: Matrix must be quadratic"); if (!assert_cond) throw std::out_of_range("LinearSolver::GaussElim: Matrix must be quadratic"); // Create row-row map (because of pivoting) std::vector<int> row_row_map(max_row); for (int i = 0; i < max_row; ++i) row_row_map[i] = i; for (int col = 0; col < max_col; ++col) { // Find pivot element row index int pivot_index = findPivotIndex(ACopy, col, row_row_map); // Arrange rows due to row pivoting if (col != row_row_map[pivot_index]) { row_row_map[pivot_index] = col; row_row_map[row_row_map[col]] = pivot_index; } BOOST_ASSERT_MSG(row_row_map[pivot_index] == col, "LinearSolver::GaussElim: Pivoting error"); double pivot_element = ACopy(pivot_index, col); // Matrix is singular if (pivot_element == 0.0) return std::make_tuple(false, AInv, rhs); // Divide pivot row by pivot element to set element to 1 for (int i = 0; i < max_col; ++i) { // ACopy(pivot_index, i) = 0 for i < col if (i >= col) { double& val1 = ACopy(pivot_index, i); val1 /= pivot_element; } double& val2 = AInv(pivot_index, i); val2 /= pivot_element; } // Do same transformation on the rhs rhs[pivot_index] /= pivot_element; // Add pivot row to all other rows to reduce column col // to the corresponding identity matrix column. for (int current_row = 0; current_row < max_row; ++current_row) { if (current_row == pivot_index) continue; double val = - ACopy(current_row, col) / ACopy(pivot_index, col); for (int j = 0; j < max_col; ++j) { ACopy(current_row, j) += val * ACopy(pivot_index, j); AInv(current_row, j) += val * AInv(pivot_index, j); } // Do same transformation on the rhs rhs[current_row] += val * rhs[pivot_index]; } } // Rearrange the rows in AInv due to pivoting for (int i = 0; i < max_row; ++i) { int row = row_row_map[i]; if (row == i) continue; // Swap rows for (int j = 0; j < max_col; ++j) { double tmp = AInv(i, j); AInv(i, j) = AInv(row, j); AInv(row, j) = tmp; tmp = ACopy(i, j); ACopy(i, j) = ACopy(row, j); ACopy(row, j) = tmp; } // Swap rows on the rhs double tmp = rhs[i]; rhs[i] = rhs[row]; rhs[row] = tmp; row_row_map[i] = row_row_map[row]; row_row_map[row] = row; } return std::make_tuple(success, AInv, rhs); }
GaussJordan::Return_t GaussJordan::solve(Matrix2D const & A, Vector const & f) const { // Solve the equation A x = f using Gauss-Jordan elimination with row pivoting. // Description of algorithm: First, search for the largest element in the current // column use it as the pivot element. This is to reduce round-off errors. The // matrix ACopy will be transformed into the identity matrix, while the identity // matrix, AInvwerse, will be transformed into the inverse. // A x = Id y is successively transformed into A^{-1} A x = A^{-1} Id f, // where ACopy = Id and A^{-1} = AInverse. BOOST_ASSERT_MSG(A.cols() == A.rows(), "Gauss::solve: Matrix must be quadratic"); BOOST_ASSERT_MSG(A.cols() == f.size(), "Gauss::solve: r.h.s. vector size mismatch"); IMatrix2D::size_type max_col = A.cols(); IMatrix2D::size_type max_row = A.rows(); bool success = false; Matrix2D ACopy(A); Matrix2D AInverse(Matrix2D::identity(max_col)); Vector rhs(f); initializePivoting(max_row); /* This is a column index, rather than a row index. * Obviously, this makes no difference for a square * matrix, but if #columns > #rows, the problem is * overspecified and then least-squares could be used. * The other extreme is an underspecified problem, which * we do not bother with at all here. */ for (IMatrix2D::size_type col = 0; col < max_col; ++col) { // ACopy.print(); // print(ACopy); // AInverse.print(); // print(AInverse); auto physical_pivot_row_index = getPivotElementsRowIndex(ACopy, col); // "swap" rows 'col' and 'row_with_pivot_element' due to row pivoting adjustPivotingMap(col, physical_pivot_row_index); double pivot_element = ACopy(physical_pivot_row_index, col); if (pivot_element == 0.0) // Matrix is singular return std::make_tuple(false, AInverse, rhs); // Divide pivot row by pivot element to set pivot element to 1 // as part of the reduction of ACopy to the identity matrix. // Note: Start column is 'col', as all elements with column // index (0, ..., col - 1) are 0 already. for (IMatrix2D::size_type i = 0; i < max_col; ++i) { if (i >= col) { double & val1 = ACopy(physical_pivot_row_index, i); val1 /= pivot_element; } double & val2 = AInverse(physical_pivot_row_index, i); val2 /= pivot_element; } // ACopy.print(); // print(ACopy); // AInverse.print(); // print(AInverse); // Do same transformation on the rhs rhs(physical_pivot_row_index) /= pivot_element; // Add pivot row to all later rows such that all elements // in those rows become 0, i.e. we set the column to the // column of the identity matrix. for (IMatrix2D::size_type i = 0; i < max_row; ++i) { auto mapped_i = logicalToPhysicalRowIndex(i); if (mapped_i == physical_pivot_row_index) // skip pivot row continue; double val = - ACopy(mapped_i, col) / ACopy(physical_pivot_row_index, col); // subtract the pivot row from row 'mapped_i' for (IMatrix2D::size_type j = 0; j < max_col; ++j) { if (j >= col) ACopy(mapped_i, j) += val * ACopy(physical_pivot_row_index, j); AInverse(mapped_i, j) += val * AInverse(physical_pivot_row_index, j); } // do same transformation on the rhs rhs(mapped_i) += val * rhs(physical_pivot_row_index); // ACopy.print(); // print(ACopy); // AInverse.print(); // print(AInverse); } // ACopy.print(); // print(ACopy); // AInverse.print(); // print(AInverse); } // AInverse.print(); // print(AInverse); // Rearrange the rows in AInverse due to pivoting rearrangeDueToPivoting(ACopy, AInverse, rhs); // ACopy.print(); // AInverse.print(); return std::make_tuple(success, AInverse, rhs); }