@@ -1054,7 +1054,13 @@ function do_factorization(alg::QRFactorization, A, b, u)
10541054 # `alg.pivot` so the return type is determined by the static
10551055 # `QRFactorization{P}` parameter (otherwise this branch returns
10561056 # `Union{QRCompactWY, QRPivoted}` depending on `alg.inplace`).
1057- if A isa GPUArraysCore. AnyGPUArray || is_cusparse (A) || issparsematrixcsc (A)
1057+ if A isa GPUArraysCore. AnyGPUArray && ! is_cusparse (A) && is_underdetermined (A)
1058+ # A GPU `qr` factors a wide matrix happily, but solving with the result
1059+ # builds `UpperTriangular(R)` on an `R` that is not square and throws.
1060+ # Going through `Aᵀ` turns it back into a triangular solve and gives the
1061+ # minimum-norm solution, which is what dense `\` returns on the CPU.
1062+ fact = MinNormQR (qr (copy (transpose (A))))
1063+ elseif A isa GPUArraysCore. AnyGPUArray || is_cusparse (A) || issparsematrixcsc (A)
10581064 fact = qr (A)
10591065 elseif alg. inplace
10601066 if A isa Symmetric
@@ -1076,7 +1082,13 @@ function init_cacheval(
10761082 maxiters:: Int , abstol, reltol, verbose:: Union{LinearVerbosity, Bool} ,
10771083 assumptions:: OperatorAssumptions
10781084 )
1079- return ArrayInterface. qr_instance (convert (AbstractMatrix, A), alg. pivot)
1085+ A_ = convert (AbstractMatrix, A)
1086+ # Matches the wide GPU branch of `do_factorization`: the slot has to be typed for
1087+ # what will be stored in it, not for a plain `QR`.
1088+ if A_ isa GPUArraysCore. AnyGPUArray && ! is_cusparse (A_) && is_underdetermined (A_)
1089+ return MinNormQR (qr (copy (transpose (A_))))
1090+ end
1091+ return ArrayInterface. qr_instance (A_, alg. pivot)
10801092end
10811093
10821094function init_cacheval (
@@ -1192,6 +1204,12 @@ function init_cacheval(
11921204 alg:: CholeskyFactorization , A:: GPUArraysCore.AnyGPUArray , b, u, Pl,
11931205 Pr, maxiters:: Int , abstol, reltol, verbose:: Union{LinearVerbosity, Bool} , assumptions:: OperatorAssumptions
11941206 )
1207+ # `cholesky` needs a square matrix, and the default solver initializes this slot for
1208+ # every `A` before it knows which algorithm it will use. Instance an empty
1209+ # factorization for a non-square `A`, rather than returning `nothing`, so the return
1210+ # type does not depend on the runtime value of `assumptions.issq`.
1211+ # See https://github.com/SciML/NonlinearSolve.jl/issues/746
1212+ assumptions. issq || return cholesky (similar (A, 0 , 0 ); check = false )
11951213 return cholesky (A; check = false )
11961214end
11971215
0 commit comments