inline Complex<R> Reflector( Matrix<Complex<R> >& chi, Matrix<Complex<R> >& x ) { #ifndef RELEASE CallStackEntry entry("Reflector"); #endif typedef Complex<R> C; R norm = Nrm2( x ); C alpha = chi.Get(0,0); if( norm == 0 && alpha.imag == R(0) ) { chi.Set(0,0,-chi.Get(0,0)); return C(2); } R beta; if( alpha.real <= 0 ) beta = lapack::SafeNorm( alpha.real, alpha.imag, norm ); else beta = -lapack::SafeNorm( alpha.real, alpha.imag, norm ); const R one = 1; const R safeMin = lapack::MachineSafeMin<R>(); const R epsilon = lapack::MachineEpsilon<R>(); const R safeInv = safeMin/epsilon; Int count = 0; if( Abs(beta) < safeInv ) { R invOfSafeInv = one/safeInv; do { ++count; Scale( invOfSafeInv, x ); alpha *= invOfSafeInv; beta *= invOfSafeInv; } while( Abs(beta) < safeInv ); norm = Nrm2( x ); if( alpha.real <= 0 ) beta = lapack::SafeNorm( alpha.real, alpha.imag, norm ); else beta = -lapack::SafeNorm( alpha.real, alpha.imag, norm ); } C tau = C( (beta-alpha.real)/beta, -alpha.imag/beta ); Scale( one/(alpha-beta), x ); for( Int j=0; j<count; ++j ) beta *= safeInv; chi.Set(0,0,beta); return tau; }
inline R Reflector( Matrix<R>& chi, Matrix<R>& x ) { #ifndef RELEASE CallStackEntry entry("Reflector"); #endif R norm = Nrm2( x ); if( norm == 0 ) { chi.Set(0,0,-chi.Get(0,0)); return R(2); } R beta; R alpha = chi.Get(0,0); if( alpha <= 0 ) beta = lapack::SafeNorm( alpha, norm ); else beta = -lapack::SafeNorm( alpha, norm ); const R one = 1; const R safeMin = lapack::MachineSafeMin<R>(); const R epsilon = lapack::MachineEpsilon<R>(); const R safeInv = safeMin/epsilon; Int count = 0; if( Abs(beta) < safeInv ) { R invOfSafeInv = one/safeInv; do { ++count; Scale( invOfSafeInv, x ); alpha *= invOfSafeInv; beta *= invOfSafeInv; } while( Abs(beta) < safeInv ); norm = Nrm2( x ); if( alpha <= 0 ) beta = lapack::SafeNorm( alpha, norm ); else beta = -lapack::SafeNorm( alpha, norm ); } R tau = (beta-alpha) / beta; Scale( one/(alpha-beta), x ); for( Int j=0; j<count; ++j ) beta *= safeInv; chi.Set(0,0,beta); return tau; }
inline void MakeNormalUniformSpectrum ( Matrix<Complex<R> >& A, Complex<R> center, R radius ) { #ifndef RELEASE PushCallStack("MakeNormalUniformSpectrum"); #endif typedef Complex<R> C; if( A.Height() != A.Width() ) throw std::logic_error("Cannot make a non-square matrix normal"); // Sample the diagonal matrix D from the ball B_radius(center) // and then rotate it with a random Householder similarity transformation: // // (I-2uu^H) D (I-2uu^H)^H = D - 2(u (conj(D) u)^H + (D u) u^H) + // (4 u^H D u) u u^H // // Form d and D const int n = A.Height(); std::vector<C> d( n ); for( int j=0; j<n; ++j ) d[j] = center + radius*SampleUnitBall<C>(); Diagonal( d, A ); // Form u Matrix<C> u( n, 1 ); MakeUniform( u ); const R origNorm = Nrm2( u ); Scale( 1/origNorm, u ); // Form v := D u Matrix<C> v( n, 1 ); for( int i=0; i<n; ++i ) v.Set( i, 0, d[i]*u.Get(i,0) ); // Form w := conj(D) u Matrix<C> w( n, 1 ); for( int i=0; i<n; ++i ) w.Set( i, 0, Conj(d[i])*u.Get(i,0) ); // Update A := A - 2(u w^H + v u^H) Ger( C(-2), u, w, A ); Ger( C(-2), v, u, A ); // Form \gamma := 4 u^H (D u) = 4 (u,Du) const C gamma = 4*Dot(u,v); // Update A := A + gamma u u^H Ger( gamma, u, u, A ); #ifndef RELEASE PopCallStack(); #endif }
inline Number Vector::Dot(const Vector &x) const { // The current implementation of the caching doesn't allow to have // a dependency of something with itself. Therefore, we use the // Nrm2 method if the dot product is to be taken with the vector // itself. Might be more efficient anyway. if (this==&x) { Number nrm2 = Nrm2(); return nrm2*nrm2; } Number retValue; if (!dot_cache_.GetCachedResult2Dep(retValue, this, &x)) { retValue = DotImpl(x); dot_cache_.AddCachedResult2Dep(retValue, this, &x); } return retValue; }
inline void MakeNormalUniformSpectrum ( DistMatrix<Complex<R>,U,V>& A, Complex<R> center=0, R radius=1 ) { #ifndef RELEASE CallStackEntry entry("MakeNormalUniformSpectrum"); #endif typedef Complex<R> C; if( A.Height() != A.Width() ) LogicError("Cannot make a non-square matrix normal"); const Grid& grid = A.Grid(); const bool standardDist = ( U == MC && V == MR ); // Sample the diagonal matrix D from the ball B_radius(center) // and then rotate it with a random Householder similarity transformation: // // (I-2uu^H) D (I-2uu^H)^H = D - 2(u (Conj(D) u)^H + (D u) u^H) + // (4 u^H D u) u u^H // // Form d and D const Int n = A.Height(); std::vector<C> d( n ); if( grid.Rank() == 0 ) for( Int j=0; j<n; ++j ) d[j] = SampleBall<C>( center, radius ); mpi::Broadcast( &d[0], n, 0, grid.Comm() ); DistMatrix<C> ABackup( grid ); if( standardDist ) Diagonal( A, d ); else { ABackup.AlignWith( A ); Diagonal( ABackup, d ); } // Form u DistMatrix<C> u( grid ); if( standardDist ) u.AlignWith( A ); else u.AlignWith( ABackup ); Uniform( u, n, 1 ); const R origNorm = Nrm2( u ); Scale( 1/origNorm, u ); // Form v := D u DistMatrix<C> v( grid ); if( standardDist ) v.AlignWith( A ); else v.AlignWith( ABackup ); v.ResizeTo( n, 1 ); if( v.LocalWidth() == 1 ) { const Int colShift = v.ColShift(); const Int colStride = v.ColStride(); const Int localHeight = v.LocalHeight(); for( Int iLoc=0; iLoc<localHeight; ++iLoc ) { const Int i = colShift + iLoc*colStride; v.SetLocal( iLoc, 0, d[i]*u.GetLocal(iLoc,0) ); } } // Form w := Conj(D) u DistMatrix<C> w( grid ); if( standardDist ) w.AlignWith( A ); else w.AlignWith( ABackup ); w.ResizeTo( n, 1 ); if( w.LocalWidth() == 1 ) { const Int colShift = w.ColShift(); const Int colStride = w.ColStride(); const Int localHeight = w.LocalHeight(); for( Int iLoc=0; iLoc<localHeight; ++iLoc ) { const Int i = colShift + iLoc*colStride; w.SetLocal( iLoc, 0, Conj(d[i])*u.GetLocal(iLoc,0) ); } } // Update A := A - 2(u w^H + v u^H) if( standardDist ) { Ger( C(-2), u, w, A ); Ger( C(-2), v, u, A ); } else { Ger( C(-2), u, w, ABackup ); Ger( C(-2), v, u, ABackup ); } // Form \gamma := 4 u^H (D u) = 4 (u,Du) const C gamma = 4*Dot(u,v); // Update A := A + gamma u u^H if( standardDist ) Ger( gamma, u, u, A ); else Ger( gamma, u, u, ABackup ); // Copy the result into the correct distribution if( !standardDist ) A = ABackup; }
( const Matrix<Real>& Q, const Matrix<Real>& A, const Matrix<Real>& G, const Matrix<Real>& b, const Matrix<Real>& c, const Matrix<Real>& h, Matrix<Real>& x, Matrix<Real>& y, Matrix<Real>& z, Matrix<Real>& s, const MehrotraCtrl<Real>& ctrl ) { DEBUG_ONLY(CallStackEntry cse("qp::affine::Mehrotra")) const Int m = A.Height(); const Int n = A.Width(); const Int k = G.Height(); // TODO: Equilibrate the QP here by calling GeomEquil on [A;G] const Real bNrm2 = Nrm2( b ); const Real cNrm2 = Nrm2( c ); const Real hNrm2 = Nrm2( h ); // TODO: Expose this as a parameter to MehrotraCtrl const bool standardShift = true; Initialize ( Q, A, G, b, c, h, x, y, z, s, ctrl.primalInitialized, ctrl.dualInitialized, standardShift ); Matrix<Real> J, d, rmu, rc, rb, rh, dxAff, dyAff, dzAff, dsAff, dx, dy, dz, ds; Matrix<Real> dSub; Matrix<Int> p;
void Initialize ( const AffineLPProblem<Matrix<Real>,Matrix<Real>>& problem, AffineLPSolution<Matrix<Real>>& solution, bool primalInit, bool dualInit, bool standardShift ) { EL_DEBUG_CSE const Int m = problem.A.Height(); const Int n = problem.A.Width(); const Int k = problem.G.Height(); if( primalInit ) { if( solution.x.Height() != n || solution.x.Width() != 1 ) LogicError("x was of the wrong size"); if( solution.s.Height() != k || solution.s.Width() != 1 ) LogicError("s was of the wrong size"); } if( dualInit ) { if( solution.y.Height() != m || solution.y.Width() != 1 ) LogicError("y was of the wrong size"); if( solution.z.Height() != k || solution.z.Width() != 1 ) LogicError("z was of the wrong size"); } if( primalInit && dualInit ) { // TODO(poulson): Perform a consistency check return; } // Form the KKT matrix // =================== Matrix<Real> J, ones; Ones( ones, k, 1 ); KKT( problem.A, problem.G, ones, ones, J ); // Factor the KKT matrix // ===================== Matrix<Real> dSub; Permutation p; LDL( J, dSub, p, false ); AffineLPResidual<Matrix<Real>> residual; Matrix<Real> u, d; Zeros( residual.dualConic, k, 1 ); if( !primalInit ) { // Minimize || G x - h ||^2, s.t. A x = b by solving // // | 0 A^T G^T | | x | | 0 | // | A 0 0 | | u | = | b |, // | G 0 -I | | -s | | h | // // where 'u' is an unused dummy variable. Zeros( residual.dualEquality, n, 1 ); residual.primalEquality = problem.b; residual.primalEquality *= -1; residual.primalConic = problem.h; residual.primalConic *= -1; KKTRHS ( residual.dualEquality, residual.primalEquality, residual.primalConic, residual.dualConic, ones, d ); ldl::SolveAfter( J, dSub, p, d, false ); ExpandCoreSolution( m, n, k, d, solution.x, u, solution.s ); solution.s *= -1; } if( !dualInit ) { // Minimize || z ||^2, s.t. A^T y + G^T z + c = 0 by solving // // | 0 A^T G^T | | u | | -c | // | A 0 0 | | y | = | 0 |, // | G 0 -I | | z | | 0 | // // where 'u' is an unused dummy variable. residual.dualEquality = problem.c; Zeros( residual.primalEquality, m, 1 ); Zeros( residual.primalConic, k, 1 ); KKTRHS ( residual.dualEquality, residual.primalEquality, residual.primalConic, residual.dualConic, ones, d ); ldl::SolveAfter( J, dSub, p, d, false ); ExpandCoreSolution( m, n, k, d, u, solution.y, solution.z ); } const Real epsilon = limits::Epsilon<Real>(); const Real sNorm = Nrm2( solution.s ); const Real zNorm = Nrm2( solution.z ); const Real gammaPrimal = Sqrt(epsilon)*Max(sNorm,Real(1)); const Real gammaDual = Sqrt(epsilon)*Max(zNorm,Real(1)); if( standardShift ) { // alpha_p := min { alpha : s + alpha*e >= 0 } // ------------------------------------------- const auto sMinPair = VectorMinLoc( solution.s ); const Real alphaPrimal = -sMinPair.value; if( alphaPrimal >= Real(0) && primalInit ) RuntimeError("initialized s was non-positive"); // alpha_d := min { alpha : z + alpha*e >= 0 } // ------------------------------------------- const auto zMinPair = VectorMinLoc( solution.z ); const Real alphaDual = -zMinPair.value; if( alphaDual >= Real(0) && dualInit ) RuntimeError("initialized z was non-positive"); if( alphaPrimal >= -gammaPrimal ) Shift( solution.s, alphaPrimal+1 ); if( alphaDual >= -gammaDual ) Shift( solution.z, alphaDual+1 ); } else { LowerClip( solution.s, gammaPrimal ); LowerClip( solution.z, gammaDual ); } }
inline R Row( DistMatrix<R>& chi, DistMatrix<R>& x ) { #ifndef RELEASE PushCallStack("reflector::Row"); if( chi.Grid() != x.Grid() ) throw std::logic_error ("chi and x must be distributed over the same grid"); if( chi.Height() != 1 || chi.Width() != 1 ) throw std::logic_error("chi must be a scalar"); if( x.Height() != 1 ) throw std::logic_error("x must be a row vector"); if( chi.Grid().Row() != chi.ColAlignment() ) throw std::logic_error("Reflecting with incorrect row of processes"); if( x.Grid().Row() != x.ColAlignment() ) throw std::logic_error("Reflecting with incorrect row of processes"); #endif const Grid& grid = x.Grid(); mpi::Comm rowComm = grid.RowComm(); const int gridCol = grid.Col(); const int gridWidth = grid.Width(); const int rowAlignment = chi.RowAlignment(); std::vector<R> localNorms(gridWidth); R localNorm = Nrm2( x.LockedMatrix() ); mpi::AllGather( &localNorm, 1, &localNorms[0], 1, rowComm ); R norm = blas::Nrm2( gridWidth, &localNorms[0], 1 ); if( norm == 0 ) { if( gridCol == rowAlignment ) chi.SetLocal(0,0,-chi.GetLocal(0,0)); #ifndef RELEASE PopCallStack(); #endif return R(2); } R alpha; if( gridCol == rowAlignment ) alpha = chi.GetLocal(0,0); mpi::Broadcast( &alpha, 1, rowAlignment, rowComm ); R beta; if( alpha <= 0 ) beta = lapack::SafeNorm( alpha, norm ); else beta = -lapack::SafeNorm( alpha, norm ); const R one = 1; const R safeMin = lapack::MachineSafeMin<R>(); const R epsilon = lapack::MachineEpsilon<R>(); const R safeInv = safeMin/epsilon; int count = 0; if( Abs(beta) < safeInv ) { R invOfSafeInv = one/safeInv; do { ++count; Scale( invOfSafeInv, x ); alpha *= invOfSafeInv; beta *= invOfSafeInv; } while( Abs(beta) < safeInv ); localNorm = Nrm2( x.LockedMatrix() ); mpi::AllGather( &localNorm, 1, &localNorms[0], 1, rowComm ); norm = blas::Nrm2( gridWidth, &localNorms[0], 1 ); if( alpha <= 0 ) beta = lapack::SafeNorm( alpha, norm ); else beta = -lapack::SafeNorm( alpha, norm ); } R tau = (beta-alpha)/beta; Scale( one/(alpha-beta), x ); for( int j=0; j<count; ++j ) beta *= safeInv; if( gridCol == rowAlignment ) chi.SetLocal(0,0,beta); #ifndef RELEASE PopCallStack(); #endif return tau; }