I talked briefly to @sebastian.westerheide about this. He's currently occupied otherwise, so he can't take care of this at the moment, but he was able to give the following comments:
The tests were mostly derived from code from code Sebastian uses elsewhere, and meant as an example how the Eigenvalue code can be used. For use as unit tests they don't have to operate on 60x60 or 40x40 matrices as they do now, 10x10 should be sufficient.
They unit tests just compute, but do not check the condition numbers.
-*- mode: compilation; default-directory: "~/Projekte/dune-deprecations/dune-istl/build-cmake/dune/istl/eigenvalue/test/" -*-Compilation started at Thu Apr 19 12:11:13./arpackppsuperlutest testing for N = 60, BS = 1 MatrixInfo: Computing 2-norm condition number (assuming that matrix is symmetric). ArPackPlusPlus_Algorithms: Computing an approximation of the dominant eigenvalue of a matrix which is assumed to be symmetric. Obtained eigenvalues of A by solving A*x = λ*x using the ARPACK++ class ARSymStdEig: converged eigenvalues of A: 1 / 1 dominant eigenvalue of A: 7.9947 Result (#iterations = 35, ║residual║_2 = 2.81231e-14): λ = 7.9947 PowerIteration_Algorithms: Performing TLIME iteration for estimated eigenvalue in the interval (0,0).ERROR: Dune::ISTLError [applyTLIMEIteration:/home/joe/Projekte/dune-deprecations/dune-istl/dune/istl/eigenvalue/test/../poweriteration.hh:733]: TLIME iteration did not converge in 20000 iterations (║residual║_2 = 3.58816e-10, epsilon = 1e-11).Compilation exited abnormally with code 1 at Thu Apr 19 12:17:21
It appears to be connected to superlu, not arpack as I originally wrote, at least I wasn't able to trigger it with two runs of arpackpptest.
OK, I just did not understand how including libraries in the tests worked, so that point was bogus and the tests do indeed link all the required libraries, and only the required libraries.
The combined arpackppsuperlutest uses dune_add_test directly to define the cmake target:
By setting up the target outside of dune_add_test(), add_dune_all_flags() isn't implied, and the test can skip linking to SuperLU (and ENABLE_SUPERLU stays unset).
@joe is absolutely right in saying that the problem which he encountered is due to the TLIME algorithm, which is used to compute the smallest magnitude eigenvalue / smallest singular value of the test matrix.
On his machine, the residual does not fall below the given threshold value epsilon = 1e-11 within the given maximum of 20000 iterations, when using SuperLU as a linear solver.
Unfortunately, I was not able to reproduce this behavior on my Ubuntu 14.04 LTS machine.
Using the current master branch versions of
./arpackppsuperlutesttesting for N = 60, BS = 1 MatrixInfo: Computing 2-norm condition number (assuming that matrix is symmetric). ArPackPlusPlus_Algorithms: Computing an approximation of the dominant eigenvalue of a matrix which is assumed to be symmetric. Obtained eigenvalues of A by solving A*x = λ*x using the ARPACK++ class ARSymStdEig: converged eigenvalues of A: 1 / 1 dominant eigenvalue of A: 7.9947 Result (#iterations = 35, ║residual║_2 = 1.83633e-14): λ = 7.9947 PowerIteration_Algorithms: Performing TLIME iteration for estimated eigenvalue in the interval (0,0). Interval (0,0) is free of eigenvalues, approximating the closest eigenvalue. Result (#iterations = 5, ║residual║_2 = 9.22821e-12): λ = 0.00530364 Largest magnitude eigenvalue λ_max = 7.9947 Smallest magnitude eigenvalue λ_min = 0.00530364 2-norm condition number cond_2 = 1507.4computation of condition number took 1.09179 seconds MatrixInfo: Computing 2-norm condition number. ArPackPlusPlus_Algorithms: Computing an approximation of the largest singular value of a matrix which is assumed to be nonsymmetric. Obtained singular values of A by solving (A^T*A)*x = σ²*x using the ARPACK++ class ARSymStdEig: converged eigenvalues of A^T*A: 1 / 1 largest eigenvalue of A^T*A: 63.9152 => largest singular value of A: 7.9947 Result (#iterations = 22, ║residual║_2 = 2.6779e-13): σ = 7.9947 PowerIteration_Algorithms: Performing TLIME iteration for estimated eigenvalue in the interval (0,0). Interval (0,0) is free of eigenvalues, approximating the closest eigenvalue. Result (#iterations = 4, ║residual║_2 = 2.13295e-12): λ = 2.81286e-05 Largest singular value σ_max = 7.9947 Smallest singular value σ_min = 0.00530364 2-norm condition number cond_2 = 1507.4computation of condition number took 1.31215 seconds
As @joe already mentioned, the unit tests do not have to operate on 60x60 or 40x40 matrices, as they do now. Therefore, one could handle the issue by just using something like a 10x10 matrix.
But since arpackppsuperlutest does not fail on my machine and takes less than 3 seconds, even though operating on the 60x60 matrix and compiling without optimizations (I compiled using -O0), it would rather be interesting to know why the SuperLU-driven TLIME algorithm does not converge on @joe's machine.
I furthermore used docker to check whether the positive outcome of the test on my machine is related to the specific library versions which I am using in Ubuntu 14.04 LTS. The answer is no.
In Debian Stretch with
libsuperlu-dev (Version: 5.2.1+dfsg1-2) and
libarpack2 (3.4.0-1+b1)
the test also succeeds and I get:
./arpackppsuperlutesttesting for N = 60, BS = 1 MatrixInfo: Computing 2-norm condition number (assuming that matrix is symmetric). ArPackPlusPlus_Algorithms: Computing an approximation of the dominant eigenvalue of a matrix which is assumed to be symmetric. Obtained eigenvalues of A by solving A*x = λ*x using the ARPACK++ class ARSymStdEig: converged eigenvalues of A: 1 / 1 dominant eigenvalue of A: 7.9947 Result (#iterations = 35, ║residual║_2 = 1.83633e-14): λ = 7.9947 PowerIteration_Algorithms: Performing TLIME iteration for estimated eigenvalue in the interval (0,0). Interval (0,0) is free of eigenvalues, approximating the closest eigenvalue. Result (#iterations = 6, ║residual║_2 = 4.10771e-15): λ = 0.00530364 Largest magnitude eigenvalue λ_max = 7.9947 Smallest magnitude eigenvalue λ_min = 0.00530364 2-norm condition number cond_2 = 1507.4computation of condition number took 1.11077 seconds MatrixInfo: Computing 2-norm condition number. ArPackPlusPlus_Algorithms: Computing an approximation of the largest singular value of a matrix which is assumed to be nonsymmetric. Obtained singular values of A by solving (A^T*A)*x = σ²*x using the ARPACK++ class ARSymStdEig: converged eigenvalues of A^T*A: 1 / 1 largest eigenvalue of A^T*A: 63.9152 => largest singular value of A: 7.9947 Result (#iterations = 22, ║residual║_2 = 2.6779e-13): σ = 7.9947 PowerIteration_Algorithms: Performing TLIME iteration for estimated eigenvalue in the interval (0,0). Interval (0,0) is free of eigenvalues, approximating the closest eigenvalue. Result (#iterations = 4, ║residual║_2 = 1.54212e-12): λ = 2.81286e-05 Largest singular value σ_max = 7.9947 Smallest singular value σ_min = 0.00530364 2-norm condition number cond_2 = 1507.4computation of condition number took 1.45375 seconds
As you can see, the newer version of libsuperlu-dev yields the same smallest magnitude eigenvalue / smallest singular value on my machine as the older version which I used in the above comment.
Nevertheless, it should be noted that both SuperLU versions result in different residuals / iteration counts for the TLIME algorithm.
One could argue that @joe probably uses yet another version of libsuperlu-dev for which arpackppsuperlutest fails.
Unfortunately, arpackppsuperlutest fails on @joe's machine using Debian Stretch with exactly the same versions of libsuperlu-dev (and libarpack2).
I do see the problems in an environment with Vc installed and -march=native, which enables all kinds of CPU features in the compiler. Also, there is one warning about use of uninitialized values, although that seems not directly related (in matrixinfo.hh). I'm gonna try to make a Dockerfile with an exact reproducer.
Here is a reproducer: prepare a directory, into which you checkout dune-common and dune-istl. Then put in the following two files: Dockerfile, opts. Run docker build . in that directory.
The final command runs arpacksuperlutest with a timeout of 10 seconds. If the test succeeds it will complete in about 2 seconds.
It looks as if the package libopenblas-dev is installed, the test will be linked to both
@sebastian.westerheide just helped me interpret the output in that log. The error message seems to appear multiple times: the first time presumably directly (though the message does not indicate an error, it's just the normal program output before it is aborted due to timeout). The second one seems to be passed through some parts of the build system that hiccup on the unicode λ that appears in the fourth line.
I should probably document the outline for a solution I had before getting distracted by more urgent things:
I think libdunecommon links to blas only so some tests can use it. If that is indeed the case, we might get away with liking those tests directly to blas, and maybe inlining the necessary stuff from the library instead.
If lapack was found, dynmatrixev.cc (which is compiled into libdunecommon), declares DGEEV_FORTRAN() and uses it in Dune::DynamicMatrixHelp::eigenValuesNonsymLapackCall(). If lapack was not found, eigenValuesNonsymLapackCall() is a noop.
Dune::DynamicMatrixHelp::eigenValuesNonsymLapackCall() is only used by DynamicMatrixHelp::eigenValuesNonsymLapackCall()DynamicMatrixHelp::eigenValuesNonSym() (from dynmatrixev.hh), which in turn is only used by the rosser matrix test in eigenvaluetest.cc
Similar
FMatrixHelp::eigenValuesLapackCall() only used by FMatrixHelp::eigenValues<dim, K>() (fmatrixev.hh). There are non-lapack-using specializations for dim <= 3.
FMatrixHelp::eigenValuesNonsymLapackCall() only used by FMatrixHelp::eigenValuesNonSym() (fmatrixev.hh)
FMatrixHelp::eigenValues() is used by eigenvaluetest.cc but only for dim==2 and dim==3, so without using lapack. It is also used by fmatrixtest.cc, in it's lapack incarnation, to test the rosser matrix (though the test function there is called test_ev()).
multMatrix() and invertMatrix() are implemented in fmatrix.hh, not in fmatrixev.*, so if we do things to fmatrixev.* that should not interfere with those uses.
(Side note: I believe those uses are hacks, and should actually be converted to the official interface -- e.g. invertMatrix() is only implemented for matrices up to 3×3. But that is another issue.)
Otherwise (core, extenstion, and staging modules), blas appears in:
ISTL: cmake/modules/FindSuperLU.cmake: find_package(BLAS QUIET) + inclusion of the detected flags in the SuperLU-Flags, and istl looks for SuperLU by default.
Besides istl, SuperLU is used in PDELab. It is also used in dune-tpmc, but that cannot have worked properly since dune-tpmc does not depend on istl.
Wait a minute -- I was assuming the rosser matrix tests test some dense matrix Dune functionality using the eigenvalues. But all the Dune-functionality they test is actually the wrapper around the lapack functions that compute the eigenvalues. Had my assumption been correct we could have moved the link-dependency out of libdunecommon and into the tests, but now I'm not so sure. Either someone is using the eigenvalue functions from the *MatrixHelp namespaces, or they can be removed completely, along with their tests.
Asked on the Dune-List if anyone is using those functions. Gave it one week (until 2018-07-09) for responses. If no-one objects, I'm going to assume Help == Impl and will remove the eigenvalue functions from *matrixev.hh without deprecation.
Talked with Carsten, he knows about one specific case of someone using eigenValuesLapackCall() and thinks there are other cases of people using the eigenValue() functions.
The difference between the *Call() functions and the others is that all the *Call() function do is figuring out the fortran-mangled name of the function to call, while the other functions convert the data to a format expected by the fortran functions (and then invoke the *Call() functions with that data).
In the case above, the user uses eigenValuesLapackCall() instead of the data-format-conversion-wrapper because he needs the eigenvectors in addition to the eigenvalues.
Looks like the best option is to keep the data-format-conversion wrappers, and get rid of the *Call() wrappers. As a replacement, provide the Fortran-mangling functionality to users, so they can call whatever lapack functions they please. Users will have to add findpackage(LAPACK) to their projects to use this functionality, and they'll need to add the lapack flags, either globally in their project or to each target.
So it's actually perfectly normal that both libblas and libopenblas are linked, because the former appears to be a wrapper library around the latter. Dammit.
So, that leaves us with two possibilities: (1) the blas library provided by openblas is broken and (2) undefined behavior somewhere in the test program.