Esempio n. 1
0
void TestGemv
( El::Int height,
  El::Int width,
  El::Orientation orientation,
  const El::Grid& grid,
  bool print )
{
    El::DistMatrix<Field> A(grid);
    El::Uniform( A, height, width );

    // Draw the entries of the original x and y from uniform distributions
    // over the complex unit ball
    El::DistMatrix<Field,El::VC,El::STAR> x(grid), y(grid);
    if( orientation == El::NORMAL )
    {
        El::Uniform( x, width, 1 );
        El::Uniform( y, height, 1 );
    }
    else
    {
        El::Uniform( x, height, 1 );
        El::Uniform( y, width, 1 );
    }

    if( print )
    {
        El::Print( A, "A" );
        El::Print( x, "x" );
        El::Print( y, "y" );
    }

    // Run the matrix-vector product
    if( grid.Rank() == 0 )
        El::Output("Starting Gemv (with Field=",El::TypeName<Field>(),")");
    El::Timer gemvElem;
    gemvElem.Start();
    // Form y := 3 A x + 4 y
    El::Gemv( orientation, Field(3), A, x, Field(4), y );
    gemvElem.Stop();
    if( grid.Rank() == 0 )
        El::Output("  Time: ",gemvElem.Total());

    if( print )
    {
        if( orientation == El::NORMAL )
            El::Print( y, "y := 3 A x + 4 y" );
        else
            El::Print( y, "y := 3 A^H x + 4 y" );
    }
}
Esempio n. 2
0
int
main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );
    El::mpi::Comm comm = El::mpi::COMM_WORLD;

    try
    {
        typedef double Real;
        typedef El::Complex<Real> Scalar;

        const El::Int m = El::Input("--height","height of matrix",100);
        const El::Int n = El::Input("--width","width of matrix",100);
        const bool print = El::Input("--print","print matrices?",false);
        El::ProcessInput();
        El::PrintInputReport();

        El::DistMatrix<Scalar> A;
        El::Uniform( A, m, n );

        El::Timer timer;
        // Compute the pseudoinverseof A (but do not overwrite A)
        El::DistMatrix<Scalar> pinvA( A );
        if( El::mpi::Rank(comm) == 0 )
            timer.Start();
        El::Pseudoinverse( pinvA );
        if( El::mpi::Rank(comm) == 0 )
            timer.Stop();
        if( print )
        {
            El::Print( A, "A" );
            El::Print( pinvA, "pinv(A)" );
        }

        const Real frobA = El::FrobeniusNorm( A );
        const Real frobPinvA = El::FrobeniusNorm( pinvA );

        if( El::mpi::Rank(comm) == 0 )
        {
            El::Output("PseudoInverse time: ",timer.Total()," secs");
            El::Output
            ("||   A     ||_F = ",frobA,"\n",
             "|| pinv(A) ||_F = ",frobPinvA,"\n");
        }
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
Esempio n. 3
0
int main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );
    El::mpi::Comm comm = El::mpi::COMM_WORLD;
    const int commRank = El::mpi::Rank( comm );
    const int commSize = El::mpi::Size( comm );

    try
    {
        typedef double Real;
        typedef El::Complex<Real> Scalar;

        const El::Int n = El::Input("--size","size of matrix",100);
        const El::Int numRhs = El::Input("--numRhs","# of right-hand sides",1);
        const El::Int blocksize =
          El::Input("--blocksize","algorithmic blocksize",64);
        const El::Int numTests = El::Input("--numTests","number of tests",3);
        const bool error = El::Input("--error","test Elemental error?",true);
        El::Int gridHeight = El::Input("--gridHeight","grid height",0);
        const bool details = El::Input("--details","print norm details?",false);
        const bool print = El::Input("--print","print matrices?",false);
        El::ProcessInput();
        El::PrintInputReport();

        El::SetBlocksize( blocksize );

        // If the grid height wasn't specified, then we should attempt to build
        // a nearly-square process grid
        if( gridHeight == 0 )
            gridHeight = El::Grid::FindFactor( commSize );
        El::Grid grid( comm, gridHeight );
        if( commRank == 0 )
            El::Output("Grid is: ",grid.Height()," x ",grid.Width());

        // Set up random A and B, then make the copies X := B
        El::Timer timer;
        El::DistMatrix<Scalar> A(grid), B(grid), X(grid);

        for( El::Int test=0; test<numTests; ++test )
        {
            El::Uniform( A, n, n );
            El::Uniform( B, n, numRhs );
            X = B;
            if( print )
            {
                El::Print( A, "A" );
                El::Print( B, "B" );
            }

            // Perform the LU factorization and simultaneous solve
            if( commRank == 0 )
                El::Output("Starting Elemental linear solve");
            El::mpi::Barrier( comm );
            if( commRank == 0 )
                timer.Start();
            El::LinearSolve( A, X );
            El::mpi::Barrier( comm );
            if( commRank == 0 )
                El::Output(timer.Stop()," seconds");

            if( error )
            {
                // Form R := A X - B
                auto R( B );
                El::Gemm
                ( El::NORMAL, El::NORMAL, Scalar(1), A, X, Scalar(-1), R );

                // Compute infinity norms and a relative residual
                const Real eps = El::limits::Epsilon<Real>();
                const Real AInfNorm = El::InfinityNorm( A );
                const Real BInfNorm = El::InfinityNorm( B );
                const Real XInfNorm = El::InfinityNorm( X );
                const Real RInfNorm = El::InfinityNorm( R );
                const Real infResidual = RInfNorm / (AInfNorm*XInfNorm*eps*n);
                if( commRank == 0 )
                {
                    if( details )
                    {
                        El::Output("");
                        El::Output("||A||_oo       = ",AInfNorm);
                        El::Output("||B||_oo       = ",BInfNorm);
                        El::Output("||X||_oo       = ",XInfNorm);
                        El::Output("||A X - B||_oo = ",RInfNorm);
                    }
                    El::Output
                    ("||A X - B||_oo / (||A||_oo ||X||_oo eps n) = ",
                     infResidual);
                }

                // Compute one norms and a relative residual
                const Real AOneNorm = El::OneNorm( A );
                const Real BOneNorm = El::OneNorm( B );
                const Real XOneNorm = El::OneNorm( X );
                const Real ROneNorm = El::OneNorm( R );
                const Real oneResidual = ROneNorm / (AOneNorm*XOneNorm*eps*n);
                if( commRank == 0 )
                {
                    if( details )
                    {
                        El::Output("");
                        El::Output("||A||_1       = ",AOneNorm);
                        El::Output("||B||_1       = ",BOneNorm);
                        El::Output("||X||_1       = ",XOneNorm);
                        El::Output("||A X - B||_1 = ",ROneNorm);
                    }
                    El::Output
                    ("||A X - B||_1 / (||A||_1 ||X||_1 eps n) = ",
                     oneResidual,"\n");
                }
            }
        }
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
Esempio n. 4
0
int main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );

    try
    {
        typedef double Real;
        typedef El::Complex<Real> Scalar;

        const El::Int m = El::Input("--height","height of matrix",20);
        const El::Int n = El::Input("--width","width of matrix",100);
        const El::Int r = El::Input("--rank","rank of matrix",5);
        const El::Int maxSteps =
          El::Input("--maxSteps","max # of steps of QR",10);
        const Real tol = El::Input("--tol","tolerance for ID",Real(-1));
        const bool print = El::Input("--print","print matrices?",false);
        const bool smallestFirst =
          El::Input("--smallestFirst","smallest norm first?",false);
        El::ProcessInput();
        El::PrintInputReport();

        El::mpi::Comm comm = El::mpi::COMM_WORLD;

        const El::Grid& grid = El::Grid::Default();
        El::DistMatrix<Scalar> U(grid), V(grid), A(grid);
        El::Uniform( U, m, r );
        El::Uniform( V, n, r );
        El::Gemm( El::NORMAL, El::ADJOINT, Scalar(1), U, V, A );
        const Real frobA = El::FrobeniusNorm( A );
        if( print )
            El::Print( A, "A" );

        El::DistPermutation Omega(grid);
        El::DistMatrix<Scalar,El::STAR,El::VR> Z(grid);
        El::QRCtrl<Real> ctrl;
        ctrl.boundRank = true;
        ctrl.maxRank = maxSteps;
        if( tol != -1. )
        {
            ctrl.adaptive = true;
            ctrl.tol = tol;
        }
        ctrl.smallestFirst = smallestFirst;
        El::Timer timer;
        if( El::mpi::Rank(comm) == 0 )
            timer.Start();
        El::ID( A, Omega, Z, ctrl );
        if( El::mpi::Rank(comm) == 0 )
            timer.Stop();
        const El::Int rank = Z.Height();
        if( print )
        {
            El::DistMatrix<El::Int> OmegaFull(grid);
            Omega.ExplicitMatrix( OmegaFull );
            El::Print( OmegaFull, "Omega" );
            El::Print( Z, "Z" );
        }

        // Pivot A and form the matrix of its (hopefully) dominant columns
        El::Timer permTimer("permTimer");
        permTimer.Start();
        Omega.PermuteCols( A );
        permTimer.Stop();

        auto hatA( A );
        hatA.Resize( m, rank );
        if( print )
        {
            El::Print( A, "A Omega^T" );
            El::Print( hatA, "\\hat{A}" );
        }

        // Check || A Omega^T - \hat{A} [I, Z] ||_F / || A ||_F
        El::DistMatrix<Scalar> AL(grid), AR(grid);
        El::PartitionRight( A, AL, AR, rank );
        El::Zero( AL );
        {
            El::DistMatrix<Scalar,El::MC,El::STAR> hatA_MC_STAR(grid);
            El::DistMatrix<Scalar,El::STAR,El::MR> Z_STAR_MR(grid);
            hatA_MC_STAR.AlignWith( AR );
            Z_STAR_MR.AlignWith( AR );
            hatA_MC_STAR = hatA;
            Z_STAR_MR = Z;
            El::LocalGemm
            ( El::NORMAL, El::NORMAL,
              Scalar(-1), hatA_MC_STAR, Z_STAR_MR, Scalar(1), AR );
        }
        const Real frobError = El::FrobeniusNorm( A );
        if( print )
            El::Print( A, "A Omega^T - \\hat{A} [I, Z]" );

        if( El::mpi::Rank(comm) == 0 )
        {
            El::Output("  ID time: ",timer.Total()," secs");
            El::Output
            ("|| A ||_F = ",frobA,"\n",
             "|| A Omega^T - \\hat{A} [I, Z] ||_F / || A ||_F = ",
             frobError/frobA);
        }
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
Esempio n. 5
0
int main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );

    try
    {
        const El::Int n = El::Input("--n","problem size",200);
        const El::Int maxIter =
          El::Input("--maxIter","maximum # of iter's",500);
        const Real lb = El::Input("--lb","lower bound for x",0.5);
        const Real ub = El::Input("--ub","upper bound for x",1.0);
        const Real lbEig = El::Input("--lbEig","spectral lower bound",1.);
        const Real ubEig = El::Input("--ubEig","spectral upper bound",2.);
        const Real rho = El::Input("--rho","augmented Lagrangian param.",1.);
        const Real alpha = El::Input("--alpha","over-relaxation",1.2);
        const Real absTol = El::Input("--absTol","absolute tolerance",1e-6);
        const Real relTol = El::Input("--relTol","relative tolerance",1e-4);
        const bool inv = El::Input("--inv","form inv(LU) to avoid trsv?",true);
        const bool progress = El::Input("--progress","print progress?",true);
        const bool display = El::Input("--display","display matrices?",false);
        const bool print = El::Input("--print","print matrices",false);
        El::ProcessInput();
        El::PrintInputReport();

        El::ADMMCtrl<Real> ctrl;
        ctrl.rho = rho;
        ctrl.alpha = alpha;
        ctrl.maxIter = maxIter;
        ctrl.absTol = absTol;
        ctrl.relTol = relTol;
        ctrl.inv = inv;
        ctrl.print = progress;

        El::DistMatrix<Real> Q, c, xTrue;
        El::HermitianUniformSpectrum( Q, n, lbEig, ubEig );
        // Alternate the entries of xTrue between ub and lb
        El::Zeros( xTrue, n, 1 );
        if( xTrue.LocalWidth() == 1 )
            for( El::Int iLoc=0; iLoc<xTrue.LocalHeight(); ++iLoc )
                xTrue.SetLocal( iLoc, 0,
                    ( xTrue.GlobalRow(iLoc)%2==0 ? lb : ub ) );
        // Set c := - Q xTrue - du + dl
        El::Zeros( c, n, 1 );
        El::Hemv( El::LOWER, Real(-1), Q, xTrue, Real(0), c );
        if( c.LocalWidth() == 1 )
            for( El::Int iLoc=0; iLoc<c.LocalHeight(); ++iLoc )
                c.UpdateLocal( iLoc, 0,
                    ( c.GlobalRow(iLoc)%2==0 ? 0.5 : -0.5 ) );
        if( print )
        {
            El::Print( Q, "Q" );
            El::Print( c, "c" );
            El::Print( xTrue, "xTrue" );
        }
        if( display )
            El::Display( Q, "Q" );

        El::Timer timer;
        El::DistMatrix<Real> z;
        if( El::mpi::Rank() == 0 )
            timer.Start();
        El::qp::box::ADMM( Q, c, lb, ub, z, ctrl );
        if( El::mpi::Rank() == 0 )
            timer.Stop();

        if( print )
            El::Print( z, "z" );
        if( El::mpi::Rank() == 0 )
            El::Output("QPBox time: ",timer.Total(),"secs");
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
Esempio n. 6
0
int
main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );
    El::mpi::Comm comm = El::mpi::COMM_WORLD;
    const int commRank = El::mpi::Rank( comm );

    try
    {
        typedef double Real;
        typedef El::Complex<Real> Scalar;
        El::Timer timer;

        const El::Int n1 = El::Input("--n1","first grid dimension",30);
        const El::Int n2 = El::Input("--n2","second grid dimension",30);
        const El::Int n3 = El::Input("--n3","third grid dimension",30);
        const Real omega = El::Input("--omega","angular frequency",Real(18));
        const Real damping = El::Input("--damping","damping parameter",Real(7));
        const bool selInv = El::Input("--selInv","selectively invert?",false);
        const bool intraPiv = El::Input("--intraPiv","frontal pivoting?",false);
        const bool natural = El::Input("--natural","analytic partitions?",true);
        const bool sequential = El::Input
          ("--sequential","sequential partitions?",true);
        const int numDistSeps = El::Input
          ("--numDistSeps",
           "number of separators to try per distributed partition",1);
        const int numSeqSeps = El::Input
          ("--numSeqSeps",
           "number of separators to try per sequential partition",1);
        const int cutoff =
          El::Input("--cutoff","cutoff for nested dissection",128);
        const bool print = El::Input("--print","print matrix?",false);
        const bool display = El::Input("--display","display matrix?",false);
        El::ProcessInput();

        const El::Grid grid(comm);
        El::DistSparseMatrix<Scalar> A(grid);
        Scalar dampedOmega( omega, damping );
        El::Helmholtz( A, n1, n2, n3, dampedOmega*dampedOmega );
        const El::Int N = A.Height();
        if( display )
            El::Display( A, "A" );
        if( print )
            El::Print( A, "A" );

        if( commRank == 0 )
            El::Output("Generating random vector x and forming y := A x");
        timer.Start();
        El::DistMultiVec<Scalar> x( N, 1, grid ), y( N, 1, grid );
        El::MakeUniform( x );
        El::Zero( y );
        El::Multiply( El::NORMAL, Scalar(1), A, x, Scalar(0), y );
        const Real yOrigNorm = El::FrobeniusNorm( y );
        El::mpi::Barrier(comm);
        if( commRank == 0 )
            El::Output(timer.Stop()," seconds");

        El::BisectCtrl ctrl;
        ctrl.sequential = sequential;
        ctrl.numSeqSeps = numSeqSeps;
        ctrl.numDistSeps = numDistSeps;
        ctrl.cutoff = cutoff;

        El::DistSparseLDLFactorization<Scalar> sparseLDLFact;
        const bool hermitian = false;
        if( commRank == 0 )
            El::Output("Running analysis...");
        timer.Start();
        if( natural )
        {
            sparseLDLFact.Initialize3DGridGraph
            ( n1, n2, n3, A, hermitian, ctrl );
        }
        else
        {
            sparseLDLFact.Initialize( A, hermitian, ctrl );
        }
        El::mpi::Barrier(comm);
        if( commRank == 0 )
            El::Output(timer.Stop()," seconds");

        auto& front = sparseLDLFact.Front();
        auto& info = sparseLDLFact.NodeInfo();
        const El::Int rootSepSize = info.size;
        if( commRank == 0 )
            El::Output(rootSepSize," vertices in root separator\n");

        if( commRank == 0 )
            El::Output("Running LDL factorization...");
        El::mpi::Barrier(comm);
        timer.Start();
        El::LDLFrontType type;
        if( intraPiv )
            type = selInv ? El::LDL_INTRAPIV_SELINV_2D : El::LDL_INTRAPIV_2D;
        else
            type = selInv ? El::LDL_SELINV_2D : El::LDL_2D;
        sparseLDLFact.Factor( type );
        El::mpi::Barrier(comm);
        if( commRank == 0 )
            El::Output(timer.Stop()," seconds");

        if( info.child != nullptr && info.child->onLeft )
        {
            if( commRank == 0 )
                El::Output
                ("Computing SVD of connectivity of second separator to "
                 "the root separator...");
            timer.Start();
            const auto& FL = front.child->L2D;
            const El::Grid& grid = FL.Grid();
            const El::Int height = FL.Height();
            const El::Int width = FL.Width();
            auto B = FL( El::IR(width,height), El::IR(0,width) );
            El::DistMatrix<Real,El::VR,El::STAR> singVals_VR_STAR( grid );
            El::SVD( B, singVals_VR_STAR );
            El::DistMatrix<Real,El::CIRC,El::CIRC> singVals( singVals_VR_STAR );
            El::mpi::Barrier( grid.Comm() );
            const Real twoNorm = El::MaxNorm( singVals_VR_STAR );
            const El::Int minDim = singVals_VR_STAR.Height();
            if( grid.Rank() == singVals.Root() )
            {
                El::Output
                (" two-norm is ",twoNorm," (took ",timer.Stop()," seconds)");
                for( Real tol=1e-1; tol>=Real(1e-10); tol/=10 )
                {
                    El::Int numRank = minDim;
                    for( El::Int j=0; j<minDim; ++j )
                    {
                        if( singVals.GetLocal(j,0) <= twoNorm*tol )
                        {
                            numRank = j;
                            break;
                        }
                    }
                    El::Output("  rank (",tol,")=",numRank,"/",minDim);
                }
            }
        }

        if( commRank == 0 )
            El::Output
            ("Computing SVD of the largest off-diagonal block of "
             "numerical Green's function on root separator...");
        {
            timer.Start();
            const auto& FL = front.L2D;
            const El::Grid& grid = FL.Grid();
            const El::Int lHalf = rootSepSize/2;
            const El::Int uHalf = rootSepSize - lHalf;
            if( commRank == 0 )
                El::Output("lower half=",lHalf,", upper half=",uHalf);
            auto offDiagBlock =
              FL( El::IR(lHalf,rootSepSize), El::IR(0,lHalf) );
            El::DistMatrix<Real,El::VR,El::STAR> singVals_VR_STAR( grid );
            El::SVD( offDiagBlock, singVals_VR_STAR );
            El::DistMatrix<Real,El::CIRC,El::CIRC> singVals( singVals_VR_STAR );
            El::mpi::Barrier( grid.Comm() );
            const Real twoNorm = El::MaxNorm( singVals_VR_STAR );
            if( grid.Rank() == singVals.Root() )
            {
                El::Output(timer.Stop()," seconds");
                for( Real tol=1e-1; tol>=Real(1e-10); tol/=10 )
                {
                    El::Int numRank = lHalf;
                    for( El::Int j=0; j<lHalf; ++j )
                    {
                        if( singVals.GetLocal(j,0) <= twoNorm*tol )
                        {
                            numRank = j;
                            break;
                        }
                    }
                    El::Output("  rank (",tol,")=",numRank,"/",lHalf);
                }
            }
        }

        if( commRank == 0 )
            El::Output("Solving against y...");
        timer.Start();
        sparseLDLFact.Solve( y );
        El::mpi::Barrier(comm);
        if( commRank == 0 )
            El::Output(timer.Stop()," seconds");

        if( commRank == 0 )
            El::Output("Checking error in computed solution...");
        const Real xNorm = El::FrobeniusNorm( x );
        const Real yNorm = El::FrobeniusNorm( y );
        y -= x;
        const Real errorNorm = El::FrobeniusNorm( y );
        if( commRank == 0 )
            El::Output
            ("|| x     ||_2 = ",xNorm,"\n",
             "|| xComp ||_2 = ",yNorm,"\n",
             "|| A x   ||_2 = ",yOrigNorm,"\n",
             "|| error ||_2 / || x ||_2 = ",errorNorm/xNorm,"\n",
             "|| error ||_2 / || A x ||_2 = ",errorNorm/yOrigNorm);
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
Esempio n. 7
0
int
main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );

    try
    {
        const El::Int m = El::Input("--m","height of matrix",100);
        const El::Int n = El::Input("--n","width of matrix",200);
        // TODO(poulson): Add options for controlling IPM
        const El::Int maxIter =
          El::Input("--maxIter","maximum # of iter's",500);
        const Real lambda = El::Input("--lambda","DS parameter",0.5);
        const bool display = El::Input("--display","display matrices?",false);
        const bool print = El::Input("--print","print matrices",false);
        El::ProcessInput();
        El::PrintInputReport();

        El::SparseMatrix<Real> A;
        El::Matrix<Real> b, xTrue;
        El::Identity( A, m, n );
        El::Uniform( b, m, 1 );
        if( print )
        {
            El::Print( A, "A" );
            El::Print( b, "b" );
        }
        if( display )
            El::Display( A, "A" );

        El::lp::affine::Ctrl<Real> affineCtrl; 
        affineCtrl.mehrotraCtrl.print = true;

        El::Matrix<Real> x;
        El::Timer timer;
        if( El::mpi::Rank() == 0 )
            timer.Start();
        El::DS( A, b, lambda, x, affineCtrl );
        if( El::mpi::Rank() == 0 )
            timer.Stop();
        if( print )
            El::Print( x, "x" );
        const El::Int xZeroNorm = El::ZeroNorm( x );
        if( El::mpi::Rank() == 0 )
        {
            El::Output("Dantzig Selector time: ",timer.Total()," secs");
            El::Output("|| x ||_0 = ",xZeroNorm);
        }
        SoftThreshold( x, El::Sqrt(El::limits::Epsilon<Real>()) );
        if( print )
            El::Print( x, "xThresh" );
        const El::Int xZeroNormThresh = El::ZeroNorm( x );
        if( El::mpi::Rank() == 0 )
        {
            El::Output("|| xThresh ||_0 = ",xZeroNormThresh);
        }
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
Esempio n. 8
0
int
main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );

    try
    {
        const El::Int n = El::Input("--size","width of matrix",100);
        const bool display = El::Input("--display","display matrices?",false);
        const bool print = El::Input("--print","print matrices?",false);
        const bool smallestFirst =
          El::Input("--smallestFirst","smallest norm first?",false);
        El::ProcessInput();
        El::PrintInputReport();
        const El::Int m = n;

        El::QRCtrl<double> ctrl;
        ctrl.smallestFirst = smallestFirst;

        El::DistMatrix<El::Complex<double>> A;
        El::GKS( A, n );
        const double frobA = El::FrobeniusNorm( A );
        if( display )
            El::Display( A, "A" );
        if( print )
            El::Print( A, "A" );

        // Compute the pivoted QR decomposition of A, but do not overwrite A
        auto QRPiv( A );
        El::DistMatrix<El::Complex<double>> householderScalarsPiv;
        El::DistMatrix<double> signaturePiv;
        El::DistPermutation Omega;
        El::Timer PQRtimer;
        if( El::mpi::Rank() == 0 )
            PQRtimer.Start();
        El::QR( QRPiv, householderScalarsPiv, signaturePiv, Omega );
        if( El::mpi::Rank() == 0 )
            PQRtimer.Stop();
        if( display )
        {
            El::Display( QRPiv, "QRPiv" );
            El::Display( householderScalarsPiv, "householderScalarsPiv" );
            El::Display( signaturePiv, "signaturePiv" );

            El::DistMatrix<El::Int> OmegaFull;
            Omega.ExplicitMatrix( OmegaFull );
            El::Display( OmegaFull, "Omega" );
        }
        if( print )
        {
            El::Print( QRPiv, "QRPiv" );
            El::Print( householderScalarsPiv, "householderScalarsPiv" );
            El::Print( signaturePiv, "signaturePiv" );

            El::DistMatrix<El::Int> OmegaFull;
            Omega.ExplicitMatrix( OmegaFull );
            El::Print( OmegaFull, "Omega" );
        }

        // Compute the standard QR decomposition of A
        auto QRNoPiv( A );
        El::DistMatrix<El::Complex<double>> householderScalarsNoPiv;
        El::DistMatrix<double> signatureNoPiv;
        El::Timer QRtimer;
        if( El::mpi::Rank() == 0 )
            QRtimer.Start();
        El::QR( QRNoPiv, householderScalarsNoPiv, signatureNoPiv );
        if( El::mpi::Rank() == 0 )
            QRtimer.Start();
        if( display )
        {
            El::Display( QRNoPiv, "QRNoPiv" );
            El::Display( householderScalarsNoPiv, "householderScalarsNoPiv" );
            El::Display( signatureNoPiv, "signatureNoPiv" );
        }
        if( print )
        {
            El::Print( QRNoPiv, "QRNoPiv" );
            El::Print( householderScalarsNoPiv, "householderScalarsNoPiv" );
            El::Print( signatureNoPiv, "signatureNoPiv" );
        }

        // Check the error in the pivoted QR factorization,
        // || A Omega^T - Q R ||_F / || A ||_F
        auto E( QRPiv );
        El::MakeTrapezoidal( El::UPPER, E );
        El::qr::ApplyQ
        ( El::LEFT, El::NORMAL, QRPiv, householderScalarsPiv, signaturePiv, E );
        Omega.InversePermuteCols( E );
        E -= A;
        const double frobQRPiv = El::FrobeniusNorm( E );
        if( display )
            El::Display( E, "A P - Q R" );
        if( print )
            El::Print( E, "A P - Q R" );

        // Check the error in the standard QR factorization,
        // || A - Q R ||_F / || A ||_F
        E = QRNoPiv;
        El::MakeTrapezoidal( El::UPPER, E );
        El::qr::ApplyQ
        ( El::LEFT, El::NORMAL,
          QRNoPiv, householderScalarsNoPiv, signatureNoPiv, E );
        E -= A;
        const double frobQRNoPiv = El::FrobeniusNorm( E );
        if( display )
            El::Display( E, "A - Q R" );
        if( print )
            El::Print( E, "A - Q R" );

        // Check orthogonality of pivoted Q, || I - Q^H Q ||_F / || A ||_F
        El::Identity( E, m, n );
        El::qr::ApplyQ
        ( El::LEFT, El::NORMAL,
          QRPiv, householderScalarsPiv, signaturePiv, E );
        El::qr::ApplyQ
        ( El::LEFT, El::ADJOINT,
          QRPiv, householderScalarsPiv, signaturePiv, E );
        const El::Int k = El::Min(m,n);
        auto EUpper = E( El::IR(0,k), El::IR(0,k) );
        El::ShiftDiagonal( EUpper, El::Complex<double>(-1) );
        const double frobOrthogPiv = El::FrobeniusNorm( EUpper );
        if( display )
            El::Display( E, "pivoted I - Q^H Q" );
        if( print )
            El::Print( E, "pivoted I - Q^H Q" );

        // Check orthogonality of unpivoted Q, || I - Q^H Q ||_F / || A ||_F
        El::Identity( E, m, n );
        El::qr::ApplyQ
        ( El::LEFT, El::NORMAL,
          QRPiv, householderScalarsPiv, signaturePiv, E );
        El::qr::ApplyQ
        ( El::LEFT, El::ADJOINT,
          QRPiv, householderScalarsPiv, signaturePiv, E );
        EUpper = E( El::IR(0,k), El::IR(0,k) );
        El::ShiftDiagonal( EUpper, El::Complex<double>(-1) );
        const double frobOrthogNoPiv = El::FrobeniusNorm( EUpper );
        if( display )
            El::Display( E, "unpivoted I - Q^H Q" );
        if( print )
            El::Print( E, "unpivoted I - Q^H Q" );

        if( El::mpi::Rank() == 0 )
        {
            El::Output("Pivot QR time: ",PQRtimer.Total()," secs\n",
                       "      QR time: ",QRtimer.Total()," secs");
            El::Output
            ("|| A ||_F = ",frobA,"\n\n",
             "With pivoting: \n",
             "    || A P - Q R ||_F / || A ||_F = ",frobQRPiv/frobA,"\n",
             "    || I - Q^H Q ||_F / || A ||_F = ",frobOrthogPiv/frobA,"\n\n",
             "Without pivoting: \n",
             "    || A - Q R ||_F / || A ||_F = ",frobQRNoPiv/frobA,"\n",
             "    || I - Q^H Q ||_F / || A ||_F = ",frobOrthogNoPiv/frobA,"\n");
        }
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
int
main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );

    try
    {
        El::Int gridHeight =
          El::Input("--gridHeight","process grid height",0);
        const bool colMajor =
          El::Input("--colMajor","column-major ordering?",true);
        const El::Int matType =
          El::Input("--matType","0:uniform,\n"
                                "1:Haar,\n"
                                "2:Lotkin,\n"
                                "3:Grcar,\n"
                                "4:FoxLi,\n"
                                "5:HelmholtzPML1D,\n"
                                "6:HelmholtzPML2D,\n"
                                "7:TrefethenEmbree,\n"
                                "8:Bull's head,\n"
                                "9:Triangle,\n"
                                "10:Whale,\n"
                                "11:UniformHelmholtzGreen's,\n"
                                "12:HatanoNelson,\n"
                                "13:EhrenfestDecay,\n"
                                "14:RiffleDecay\n"
                                "15:Jordan\n",4);
        const El::Int normInt = El::Input("--norm","0:two norm,1:one norm",0);
        const El::Int n = El::Input("--size","height of matrix",100);
        const El::Int nbAlg = El::Input("--nbAlg","algorithmic blocksize",96);

        // QR algorithm options
        const El::Int nbDist =
          El::Input("--nbDist","distribution blocksize",32);

        // Spectral Divide and Conquer options
        const bool sdc = El::Input("--sdc","use Spectral D&C?",false);
        const El::Int cutoff = El::Input("--cutoff","problem size for QR",256);
        const El::Int maxInnerIts = El::Input("--maxInnerIts","SDC limit",2);
        const El::Int maxOuterIts = El::Input("--maxOuterIts","SDC limit",10);
        const bool random = El::Input("--random","Random RRQR in SDC",true);
        const double sdcTol = El::Input("--sdcTol","Rel. tol. for SDC",1e-6);
        const double spreadFactor =
          El::Input("--spreadFactor","median pert.",1e-6);
        const double signTol =
          El::Input("--signTol","Sign tolerance for SDC",1e-9);

        const double realCenter = El::Input("--realCenter","real center",0.);
        const double imagCenter = El::Input("--imagCenter","imag center",0.);
        double realWidth = El::Input("--realWidth","x width of image",0.);
        double imagWidth = El::Input("--imagWidth","y width of image",0.);
        const El::Int numReal = El::Input("--numReal","num real chunks",2);
        const El::Int numImag = El::Input("--numImag","num imag chunks",2);
        const El::Int realSize =
          El::Input("--realSize","number of x samples",100);
        const El::Int imagSize =
          El::Input("--imagSize","number of y samples",100);
        const bool arnoldi = El::Input("--arnoldi","use Arnoldi?",true);
        const El::Int basisSize =
          El::Input("--basisSize","num basis vectors",10);
        const El::Int maxIts =
          El::Input("--maxIts","maximum pseudospec iter's",200);
        const double psTol =
          El::Input("--psTol","tolerance for pseudospectra",1e-6);
        // Uniform options
        const double uniformRealCenter =
          El::Input("--uniformRealCenter","real center of uniform dist",0.);
        const double uniformImagCenter =
          El::Input("--uniformImagCenter","imag center of uniform dist",0.);
        const double uniformRadius =
          El::Input("--uniformRadius","radius of uniform dist",1.);
        // Grcar options
        const El::Int numBands =
          El::Input("--numBands","num bands for Grcar",3);
        // Fox-Li options
        const double omega =
          El::Input("--omega","frequency for Fox-Li/Helm",16*M_PI);
        // Helmholtz-PML options [also uses omega from Fox-Li]
        const El::Int mx =
          El::Input("--mx","number of x points for HelmholtzPML",30);
        const El::Int my =
          El::Input("--my","number of y points for HelmholtzPML",30);
        const El::Int numPmlPoints =
          El::Input("--numPml","num PML points for Helm",5);
        const double sigma = El::Input("--sigma","PML amplitude",1.5);
        const double pmlExp =
          El::Input("--pmlExp","PML takeoff exponent",3.);
        // Uniform Helmholtz Green's options
        const double lambda =
          El::Input("--lambda","wavelength of U.H.Green's",0.1);
        // Hatano-Nelson options
        const double gHatano =
          El::Input("--gHatano","g in Hatano-Nelson",0.5);
        const bool periodic =
          El::Input("--periodic","periodic HatanoNelson?",true);
        // Input/Output options
        const bool progress = El::Input("--progress","print progress?",true);
        const bool deflate = El::Input("--deflate","deflate?",true);
        const bool display = El::Input("--display","display matrices?",false);
        const bool write = El::Input("--write","write matrices?",false);
        const bool saveSchur =
          El::Input("--saveSchur","save Schur factor?",true);
        const El::Int numSaveFreq =
          El::Input("--numSaveFreq","numerical save frequency",-1);
        const El::Int imgSaveFreq =
          El::Input("--imgSaveFreq","image save frequency",-1);
        const El::Int imgDispFreq =
          El::Input("--imgDispFreq","image display frequency",-1);
        const std::string numBase =
          El::Input("--numBase","numerical save basename",std::string("num"));
        const std::string imgBase =
          El::Input("--imgBase","image save basename",std::string("img"));
        const El::Int numFormatInt =
          El::Input("--numFormat","numerical format",2);
        const El::Int imgFormatInt =
          El::Input("--imgFormat","image format",8);
        const El::Int colorMapInt =
          El::Input("--colorMap","color map",0);
        const bool itCounts =
          El::Input("--itCounts","display iter. counts?",true);
        El::ProcessInput();
        El::PrintInputReport();

        El::mpi::Comm comm = El::mpi::COMM_WORLD;
        if( gridHeight == 0 )
            gridHeight = El::Grid::DefaultHeight( El::mpi::Size(comm) );
        const El::GridOrder order = colMajor ? El::COLUMN_MAJOR : El::ROW_MAJOR;
        const El::Grid grid( comm, gridHeight, order );
        El::SetBlocksize( nbAlg );
        if( normInt < 0 || normInt > 1 )
            El::LogicError("Invalid pseudospec norm type");
        if( numFormatInt < 1 || numFormatInt >= El::FileFormat_MAX )
            El::LogicError
            ("Invalid numerical format integer, should be in [1,",
             El::FileFormat_MAX,")");
        if( imgFormatInt < 1 || imgFormatInt >= El::FileFormat_MAX )
            El::LogicError
            ("Invalid image format integer, should be in [1,",
             El::FileFormat_MAX,")");

        const auto psNorm    = static_cast<El::PseudospecNorm>(normInt);
        const auto numFormat = static_cast<El::FileFormat>(numFormatInt);
        const auto imgFormat = static_cast<El::FileFormat>(imgFormatInt);
        const auto colorMap  = static_cast<El::ColorMap>(colorMapInt);
        El::SetColorMap( colorMap );
        const El::Complex<double>
          center(realCenter,imagCenter),
          uniformCenter(uniformRealCenter,uniformImagCenter);

        bool isReal = true;
        std::string matName;
        El::DistMatrix<double> AReal(grid);
        El::DistMatrix<El::Complex<double>> ACpx(grid);
        switch( matType )
        {
        case 0: matName="uniform";
                El::Uniform( ACpx, n, n, uniformCenter, uniformRadius );
                isReal = false;
                break;
        case 1: matName="Haar";
                El::Haar( ACpx, n );
                isReal = false;
                break;
        case 2: matName="Lotkin";
                El::Lotkin( AReal, n );
                isReal = true;
                break;
        case 3: matName="Grcar";
                El::Grcar( AReal, n, numBands );
                isReal = true;
                break;
        case 4: matName="FoxLi";
                El::FoxLi( ACpx, n, omega );
                isReal = false;
                break;
        case 5: matName="HelmholtzPML";
                El::HelmholtzPML
                ( ACpx, n, El::Complex<double>(omega), numPmlPoints, sigma,
                  pmlExp );
                isReal = false;
                break;
        case 6: matName="HelmholtzPML2D";
                El::HelmholtzPML
                ( ACpx, mx, my, El::Complex<double>(omega), numPmlPoints, sigma,
                  pmlExp );
                isReal = false;
                break;
        case 7: matName="TrefethenEmbree";
                El::TrefethenEmbree( ACpx, n );
                isReal = false;
                break;
        case 8: matName="BullsHead";
                El::BullsHead( ACpx, n );
                isReal = false;
                break;
        case 9: matName="Triangle";
                El::Triangle( AReal, n );
                isReal = true;
                break;
        case 10: matName="Whale";
                 El::Whale( ACpx, n );
                 isReal = false;
                 break;
        case 11: matName="UniformHelmholtzGreens";
                 El::UniformHelmholtzGreens( ACpx, n, lambda );
                 isReal = false;
                 break;
        case 12: matName="HatanoNelson";
                 El::HatanoNelson
                 ( AReal, n, realCenter, uniformRadius, gHatano, periodic );
                 isReal = true;
                 break;
        case 13: matName="EhrenfestDecay";
                 // Force the complex matrix to allow for one-norm pseudospectra
                 El::EhrenfestDecay( ACpx, n );
                 isReal = false;
                 break;
        case 14: matName="RiffleDecay";
                 // Force the complex matrix to allow for one-norm pseudospectra
                 El::RiffleDecay( ACpx, n );
                 isReal = false;
                 break;
        case 15: matName="Jordan";
                 El::Jordan( AReal, n, 0. );
                 isReal = true;
                 break;
        default: El::LogicError("Invalid matrix type");
        }
        if( display )
        {
            if( isReal )
                El::Display( AReal, "A" );
            else
                El::Display( ACpx, "A" );
        }
        if( write )
        {
            if( isReal )
            {
                El::Write( AReal, "A", numFormat );
                El::Write( AReal, "A", imgFormat );
            }
            else
            {
                El::Write( ACpx, "A", numFormat );
                El::Write( ACpx, "A", imgFormat );
            }
        }

        // Begin by computing the Schur decomposition
        El::Timer timer;
        El::DistMatrix<El::Complex<double>> w(grid);
        El::mpi::Barrier( comm );
        const bool formATR = true;
        El::DistMatrix<double> QReal(grid);
        El::DistMatrix<El::Complex<double>> QCpx(grid);
        El::SchurCtrl<double> ctrl;
        ctrl.hessSchurCtrl.fullTriangle = formATR;
        ctrl.hessSchurCtrl.blockHeight = nbDist;
        ctrl.hessSchurCtrl.scalapack = false;
        ctrl.useSDC = sdc;
        // Spectral D&C options (only relevant if 'sdc' is true)
        ctrl.sdcCtrl.cutoff = cutoff;
        ctrl.sdcCtrl.maxInnerIts = maxInnerIts;
        ctrl.sdcCtrl.maxOuterIts = maxOuterIts;
        ctrl.sdcCtrl.tol = sdcTol;
        ctrl.sdcCtrl.spreadFactor = spreadFactor;
        ctrl.sdcCtrl.random = random;
        ctrl.sdcCtrl.progress = progress;
        ctrl.sdcCtrl.signCtrl.tol = signTol;
        ctrl.sdcCtrl.signCtrl.progress = progress;

        timer.Start();
        if( isReal )
        {
            if( psNorm == El::PS_TWO_NORM )
                El::Schur( AReal, w, ctrl );
            else
                El::Schur( AReal, w, QReal, ctrl );
        }
        else
        {
            if( psNorm == El::PS_TWO_NORM )
                El::Schur( ACpx, w, ctrl );
            else
                El::Schur( ACpx, w, QCpx, ctrl );
        }
        El::mpi::Barrier( comm );
        const double schurTime = timer.Stop();
        if( El::mpi::Rank(comm) == 0 )
            El::Output("Schur decomposition took ",schurTime," seconds");

        if( saveSchur )
        {
            if( El::mpi::Rank(comm) == 0 )
                El::Output("Writing Schur decomposition to file...");
            timer.Start();
            if( isReal )
            {
                auto schurTitle =
                  El::BuildString
                  (matName,"_",AReal.ColStride(),"x",AReal.RowStride(),
                   "_",AReal.DistRank());
                El::Write( AReal.LockedMatrix(), schurTitle, El::BINARY );
                if( psNorm == El::PS_ONE_NORM )
                {
                    auto QTitle =
                      El::BuildString
                      (matName,"_Q_",QReal.ColStride(),"x",QReal.RowStride(),
                       "_",QReal.DistRank());
                    El::Write( QReal.LockedMatrix(), QTitle, El::BINARY );
                }
            }
            else
            {
                auto schurTitle =
                  El::BuildString
                  (matName,"_",ACpx.ColStride(),"x",ACpx.RowStride(),
                   "_",ACpx.DistRank());
                El::Write( ACpx.LockedMatrix(), schurTitle, El::BINARY );
                if( psNorm == El::PS_ONE_NORM )
                {
                    auto QTitle =
                      El::BuildString
                      (matName,"_Q_",QCpx.ColStride(),"x",QCpx.RowStride(),
                       "_",QCpx.DistRank());
                    El::Write( QCpx.LockedMatrix(), QTitle, El::BINARY );
                }
            }
            El::mpi::Barrier( comm );
            const double saveSchurTime = timer.Stop();
            if( El::mpi::Rank(comm) == 0 )
                El::Output("Saving took ",saveSchurTime," seconds");
        }

        // Find a window if none is specified
        if( realWidth == 0. || imagWidth == 0. )
        {
            const double radius = El::MaxNorm( w );
            const double oneNorm =
              isReal ? El::OneNorm(AReal) : El::OneNorm(ACpx);
            double width;
            if( oneNorm == 0. && radius == 0. )
            {
                width = 1;
                if( El::mpi::Rank(comm) == 0 )
                    El::Output("Setting width to 1 to handle zero matrix");
            }
            else if( radius >= 0.2*oneNorm )
            {
                width = 2.5*radius;
                if( El::mpi::Rank(comm) == 0 )
                    El::Output
                    ("Setting width to ",width,
                     " based on the spectral radius, ",radius);
            }
            else
            {
                width = 0.8*oneNorm;
                if( El::mpi::Rank(comm) == 0 )
                    El::Output
                    ("Setting width to ",width," based on the one norm, ",
                     oneNorm);
            }
            realWidth = width;
            imagWidth = width;
        }

        El::PseudospecCtrl<double> psCtrl;
        psCtrl.norm = psNorm;
        psCtrl.schur = true;
        psCtrl.maxIts = maxIts;
        psCtrl.tol = psTol;
        psCtrl.deflate = deflate;
        psCtrl.arnoldi = arnoldi;
        psCtrl.basisSize = basisSize;
        psCtrl.progress = progress;
        psCtrl.snapCtrl.imgSaveFreq = imgSaveFreq;
        psCtrl.snapCtrl.numSaveFreq = numSaveFreq;
        psCtrl.snapCtrl.imgDispFreq = imgDispFreq;
        psCtrl.snapCtrl.imgFormat = imgFormat;
        psCtrl.snapCtrl.numFormat = numFormat;
        psCtrl.snapCtrl.itCounts = itCounts;

        // Visualize/write the pseudospectra within each window
        El::DistMatrix<double> invNormMap(grid);
        El::DistMatrix<El::Int> itCountMap(grid);
        const El::Int xBlock = realSize / numReal;
        const El::Int yBlock = imagSize / numImag;
        const El::Int xLeftover = realSize - (numReal-1)*xBlock;
        const El::Int yLeftover = imagSize - (numImag-1)*yBlock;
        const double realStep = realWidth/realSize;
        const double imagStep = imagWidth/imagSize;
        const El::Complex<double> corner =
          center - El::Complex<double>(realWidth/2,imagWidth/2);
        for( El::Int realChunk=0; realChunk<numReal; ++realChunk )
        {
            const El::Int realChunkSize =
              ( realChunk==numReal-1 ? xLeftover : xBlock );
            const double realChunkWidth = realStep*realChunkSize;
            for( El::Int imagChunk=0; imagChunk<numImag; ++imagChunk )
            {
                auto chunkTag = El::BuildString("_",realChunk,"_",imagChunk);

                const El::Int imagChunkSize =
                  ( imagChunk==numImag-1 ? yLeftover : yBlock );
                const double imagChunkWidth = imagStep*imagChunkSize;

                const El::Complex<double> chunkCorner = corner +
                    El::Complex<double>
                    (realStep*realChunk*xBlock,imagStep*imagChunk*yBlock);
                const El::Complex<double> chunkCenter = chunkCorner +
                    El::Complex<double>
                    (realStep*realChunkSize,imagStep*imagChunkSize)/2.;

                if( El::mpi::Rank(comm) == 0 )
                    El::Output
                    ("Starting computation for chunk centered at ",chunkCenter);
                El::mpi::Barrier( comm );
                timer.Start();
                psCtrl.snapCtrl.numBase = matName+"_"+numBase+chunkTag;
                psCtrl.snapCtrl.imgBase = matName+"_"+imgBase+chunkTag;
                if( isReal )
                {
                    itCountMap =
                      El::QuasiTriangularSpectralWindow
                      ( AReal, QReal, invNormMap, chunkCenter,
                        realChunkWidth, imagChunkWidth,
                        realChunkSize, imagChunkSize, psCtrl );
                }
                else
                {
                    itCountMap =
                      El::TriangularSpectralWindow
                      ( ACpx, QCpx, invNormMap, chunkCenter,
                        realChunkWidth, imagChunkWidth,
                        realChunkSize, imagChunkSize, psCtrl );
                }
                El::mpi::Barrier( comm );
                const double pseudoTime = timer.Stop();
                const El::Int numIts = MaxNorm( itCountMap );
                if( El::mpi::Rank() == 0 )
                    El::Output
                    ("num seconds=",pseudoTime,"\n",
                     "num iterations=",numIts);
            }
        }
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}
Esempio n. 10
0
int
main( int argc, char* argv[] )
{
    El::Environment env( argc, argv );

    try
    {
        const El::Int m = El::Input("--m","height of matrix",100);
        const El::Int n = El::Input("--n","width of matrix",200);
        const bool useIPM = El::Input("--useIPM","use Interior Point?",true);
        // TODO(poulson): Add options for controlling IPM
        const El::Int maxIter =
          El::Input("--maxIter","maximum # of iter's",500);
        const Real rho = El::Input("--rho","augmented Lagrangian param.",1.);
        const Real alpha = El::Input("--alpha","over-relaxation",1.2);
        const Real absTol = El::Input("--absTol","absolute tolerance",1e-6);
        const Real relTol = El::Input("--relTol","relative tolerance",1e-4);
        const Real pinvTol = El::Input("--pinvTol","pseudoinv tolerance",0.);
        const bool usePinv =
          El::Input("--usePinv","Directly compute pinv(A)",true);
        const bool progress = El::Input("--progress","print progress?",true);
        const bool display = El::Input("--display","display matrices?",false);
        const bool print = El::Input("--print","print matrices",false);
        El::ProcessInput();
        El::PrintInputReport();

        El::DistMatrix<Real> A, b, xTrue;
        El::Uniform( A, m, n );
        El::Uniform( b, m, 1 );
        if( print )
        {
            El::Print( A, "A" );
            El::Print( b, "b" );
        }
        if( display )
            El::Display( A, "A" );

        const bool sparse = false;
        El::BPCtrl<Real> ctrl(sparse);
        ctrl.useIPM = useIPM;
        ctrl.admmCtrl.rho = rho;
        ctrl.admmCtrl.alpha = alpha;
        ctrl.admmCtrl.maxIter = maxIter;
        ctrl.admmCtrl.absTol = absTol;
        ctrl.admmCtrl.relTol = relTol;
        ctrl.admmCtrl.usePinv = usePinv;
        ctrl.admmCtrl.pinvTol = pinvTol;
        ctrl.admmCtrl.progress = progress;
        ctrl.lpIPMCtrl.mehrotraCtrl.print = true;

        El::DistMatrix<Real> x;
        El::Timer timer;
        if( El::mpi::Rank() == 0 )
            timer.Start();
        El::BP( A, b, x, ctrl );
        if( El::mpi::Rank() == 0 )
            timer.Stop();
        if( print )
            El::Print( x, "x" );
        const El::Int xZeroNorm = El::ZeroNorm( x );
        if( El::mpi::Rank() == 0 )
        {
            El::Output("Basis Pursuit time: ",timer.Total()," secs");
            El::Output("|| x ||_0 = ",xZeroNorm);
        }
        SoftThreshold( x, El::Sqrt(El::limits::Epsilon<Real>()) );
        if( print )
            El::Print( x, "xThresh" );
        const El::Int xZeroNormThresh = El::ZeroNorm( x );
        if( El::mpi::Rank() == 0 )
        {
            El::Output("|| xThresh ||_0 = ",xZeroNormThresh);
        }
    }
    catch( std::exception& e ) { El::ReportException(e); }

    return 0;
}