Skip to content
Snippets Groups Projects
Verified Commit 172a9598 authored by Sébastien Villemot's avatar Sébastien Villemot
Browse files

Block trust region MEX: gracefully handle the singular Jacobian case

When the Jacobian of the problem is singular, compute a solution to the least
squares problem instead of crashing.

Closes #1889

(cherry picked from commit 82a2aeaa)
parent 97963a07
No related branches found
No related tags found
No related merge requests found
...@@ -55,6 +55,17 @@ module lapack ...@@ -55,6 +55,17 @@ module lapack
implicit none implicit none
interface interface
subroutine dgelsd(m, n, nrhs, a, lda, b, ldb, s, rcond, rank, work, lwork, iwork, info)
import :: blint, real64
implicit none
integer(blint), intent(in) :: m, n, nrhs, lda, ldb, lwork
real(real64), dimension(*), intent(inout) :: a, b
real(real64), dimension(*), intent(out) :: s, work
real(real64), intent(in) :: rcond
integer(blint), dimension(*), intent(out) :: iwork
integer(blint), intent(out) :: rank, info
end subroutine dgelsd
subroutine dgesv(n, nrhs, a, lda, ipiv, b, ldb, info) subroutine dgesv(n, nrhs, a, lda, ipiv, b, ldb, info)
import :: blint, real64 import :: blint, real64
integer(blint), intent(in) :: n, nrhs, lda, ldb integer(blint), intent(in) :: n, nrhs, lda, ldb
......
...@@ -248,8 +248,29 @@ contains ...@@ -248,8 +248,29 @@ contains
gn = b gn = b
r_plu = r r_plu = r
call dgesv(n, 1_blint, r_plu, n, ipiv, gn, n, info) call dgesv(n, 1_blint, r_plu, n, ipiv, gn, n, info)
! TODO: use same trick as NLSolve.jl in case of singularity ! If r is singular, then compute a minimum-norm solution to the least squares problem
if (info /= 0) error stop "LAPACK dgesv error" if (info /= 0) then
block
real(real64), dimension(size(x)) :: s
integer(blint) :: rank
real(real64), dimension(:), allocatable :: work
integer(blint), dimension(:), allocatable :: iwork
integer(blint) :: lwork, liwork
r_plu = r
gn = b
! Query workspace sizes
allocate(work(1), iwork(1))
lwork = -1_blint
call dgelsd(n, n, 1_blint, r_plu, n, gn, n, s, -1._real64, rank, work, lwork, iwork, info)
! Do the actual computation
lwork = int(work(1), blint)
liwork = iwork(1)
deallocate(work, iwork)
allocate(work(lwork), iwork(liwork))
call dgelsd(n, n, 1_blint, r_plu, n, gn, n, s, -1._real64, rank, work, lwork, iwork, info)
if (info /= 0) error stop "Failed to compute the Gauss-Newton direction"
end block
end if
end block end block
end if end if
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment