The copy appears to be called in svdvals which slows to a crawl for large matrices. Is this a known issue?
It appears that copy(f.Q) relies on a default method for AbstractArrays, which might explain the difference in performance. Is this something that may be improved?
I’m definitely not an expert here, but is that because theq isn’t present as a dense matrix until you copy it. It’s stored in packed form as a product of Householder reflectors. Do you actually a dense copy? You can multiply by it while still in packed form.
@malacroi is correct. Extracting Q from the data structure you get from qr or qr! is expensive. IIRC, it’s O(N^3) work. If you just want to multiply D by Q’, for example, then f.Q'*B is what you want.
The fast way to extract the Q factor as a dense matrix is just what you already do in your first example, namely Array(f.Q). Indeed, copy will probably fall back on a general method that uses indexing, which is slow for the way f.Q is stored/represented.
If you want to make a copy of an array or some object that behaves as it, but is maybe not explicit (like a Q factor, or a transposed matrix), and you want the result to be a explicit Array that has fast indexing and its own memory, then Array(object) is a good way.
Looks like we’re missing a specialized copy(x::QRPackedQ) = Array(x) method for performance. But maybe that method should even return a QRPackedQ object, since copy doesn’t have to return an Array. You could file an issue in GitHub.
I realize that I may evaluate svdvals(Array(Q)) instead of svdvals(Q), however is it reasonable to expect svdvals to perform this by itself? This is a different question from whether we should implement a specific method for copy(::AbstractQ), as — from the suggestions above — copy might not be be the best choice for certain types of matrices.