Skip to content

Commit ab2e4ee

Browse files
Add lascl2, fix weighted_lstsq error propagation
1 parent 2064540 commit ab2e4ee

6 files changed

Lines changed: 118 additions & 11 deletions

File tree

src/core/stdlib_error.fypp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ module stdlib_error
8181

8282
!> Handle optional error message
8383
procedure :: handle => error_handling
84+
85+
!> Update the location of the error message
86+
procedure :: update_location => state_update_location
8487

8588
end type state_type
8689

@@ -252,6 +255,15 @@ contains
252255

253256
end subroutine error_handling
254257

258+
!> Update the location of the error message
259+
pure subroutine state_update_location(this, where_at)
260+
class(state_type), intent(inout) :: this
261+
character(len=*), intent(in) :: where_at
262+
263+
if (len_trim(where_at) > 0) this%where_at = adjustl(where_at)
264+
265+
end subroutine state_update_location
266+
255267
!> Produce a nice error string
256268
pure function state_print(this) result(msg)
257269
class(state_type),intent(in) :: this

src/lapack/stdlib_lapack_base.fypp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,27 @@ interface
13101310
#:endfor
13111311
end interface
13121312

1313+
! LASCL2 performs diagonal scaling: X(i,:) = D(i) * X(i,:)
1314+
interface
1315+
#:for ik,it,ii in LINALG_INT_KINDS_TYPES
1316+
#:for rk,rt,ri in REAL_KINDS_TYPES
1317+
pure module subroutine stdlib${ii}$_${ri}$lascl2( m, n, d, x, ldx )
1318+
integer(${ik}$), intent(in) :: m, n, ldx
1319+
real(${rk}$), intent(in) :: d(*)
1320+
real(${rk}$), intent(inout) :: x(ldx,*)
1321+
end subroutine stdlib${ii}$_${ri}$lascl2
1322+
1323+
#:endfor
1324+
#:for ck,ct,ci in CMPLX_KINDS_TYPES
1325+
pure module subroutine stdlib${ii}$_${ci}$lascl2( m, n, d, x, ldx )
1326+
integer(${ik}$), intent(in) :: m, n, ldx
1327+
real(${ck}$), intent(in) :: d(*)
1328+
complex(${ck}$), intent(inout) :: x(ldx,*)
1329+
end subroutine stdlib${ii}$_${ci}$lascl2
1330+
1331+
#:endfor
1332+
#:endfor
1333+
end interface
13131334

13141335
interface
13151336
#:for ik,it,ii in LINALG_INT_KINDS_TYPES

src/lapack/stdlib_lapack_blas_like_l2.fypp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5681,4 +5681,55 @@ submodule(stdlib_lapack_base) stdlib_lapack_blas_like_l2
56815681

56825682

56835683
#:endfor
5684+
5685+
! LASCL2 performs diagonal scaling on a matrix: X(i,:) = D(i) * X(i,:)
5686+
#:for ik,it,ii in LINALG_INT_KINDS_TYPES
5687+
#:for rk,rt,ri in REAL_KINDS_TYPES
5688+
pure module subroutine stdlib${ii}$_${ri}$lascl2( m, n, d, x, ldx )
5689+
!! LASCL2 performs a diagonal scaling on a matrix:
5690+
!! X(i,j) = D(i) * X(i,j), for i = 1,...,M and j = 1,...,N.
5691+
!! D is a vector of length M containing the diagonal scaling factors.
5692+
! Scalar Arguments
5693+
integer(${ik}$), intent(in) :: m, n, ldx
5694+
! Array Arguments
5695+
real(${rk}$), intent(in) :: d(*)
5696+
real(${rk}$), intent(inout) :: x(ldx,*)
5697+
! =====================================================================
5698+
! Local Scalars
5699+
integer(${ik}$) :: i, j
5700+
! Executable Statements
5701+
do j = 1, n
5702+
do i = 1, m
5703+
x(i,j) = d(i) * x(i,j)
5704+
end do
5705+
end do
5706+
return
5707+
end subroutine stdlib${ii}$_${ri}$lascl2
5708+
5709+
#:endfor
5710+
#:for ck,ct,ci in CMPLX_KINDS_TYPES
5711+
pure module subroutine stdlib${ii}$_${ci}$lascl2( m, n, d, x, ldx )
5712+
!! LASCL2 performs a diagonal scaling on a matrix:
5713+
!! X(i,j) = D(i) * X(i,j), for i = 1,...,M and j = 1,...,N.
5714+
!! D is a vector of length M containing the diagonal scaling factors.
5715+
! Scalar Arguments
5716+
integer(${ik}$), intent(in) :: m, n, ldx
5717+
! Array Arguments
5718+
real(${ck}$), intent(in) :: d(*)
5719+
complex(${ck}$), intent(inout) :: x(ldx,*)
5720+
! =====================================================================
5721+
! Local Scalars
5722+
integer(${ik}$) :: i, j
5723+
! Executable Statements
5724+
do j = 1, n
5725+
do i = 1, m
5726+
x(i,j) = d(i) * x(i,j)
5727+
end do
5728+
end do
5729+
return
5730+
end subroutine stdlib${ii}$_${ci}$lascl2
5731+
5732+
#:endfor
5733+
#:endfor
5734+
56845735
end submodule stdlib_lapack_blas_like_l2

src/lapack/stdlib_linalg_lapack.fypp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16228,6 +16228,20 @@ module stdlib_linalg_lapack
1622816228
#:endfor
1622916229
end interface lascl
1623016230

16231+
interface lascl2
16232+
!! LASCL2 performs a diagonal scaling on a matrix:
16233+
!! X(i,j) = D(i) * X(i,j), for i = 1,...,M and j = 1,...,N.
16234+
!! D is a vector of length M containing the diagonal scaling factors.
16235+
#:for ik,it,ii in LINALG_INT_KINDS_TYPES
16236+
#:for rk,rt,ri in REAL_KINDS_TYPES
16237+
module procedure stdlib${ii}$_${ri}$lascl2
16238+
#:endfor
16239+
#:for ck,ct,ci in CMPLX_KINDS_TYPES
16240+
module procedure stdlib${ii}$_${ci}$lascl2
16241+
#:endfor
16242+
#:endfor
16243+
end interface lascl2
16244+
1623116245
interface lasd0
1623216246
!! Using a divide and conquer approach, LASD0: computes the singular
1623316247
!! value decomposition (SVD) of a real upper bidiagonal N-by-M

src/linalg/stdlib_linalg_least_squares.fypp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
submodule (stdlib_linalg) stdlib_linalg_least_squares
88
!! Least-squares solution to Ax=b
99
use stdlib_linalg_constants
10-
use stdlib_linalg_lapack, only: gelsd, gglse, stdlib_ilaenv
10+
use stdlib_linalg_lapack, only: gelsd, gglse, stdlib_ilaenv, lascl2
1111
use stdlib_linalg_lapack_aux, only: handle_gelsd_info, handle_gglse_info
1212
use stdlib_linalg_state, only: linalg_state_type, linalg_error_handling, LINALG_ERROR, &
1313
LINALG_INTERNAL_ERROR, LINALG_VALUE_ERROR
@@ -590,7 +590,7 @@ submodule (stdlib_linalg) stdlib_linalg_least_squares
590590

591591
! Local variables
592592
type(linalg_state_type) :: err0
593-
integer(ilp) :: m, n, j
593+
integer(ilp) :: m, n
594594
logical(lk) :: copy_a
595595
${rt}$, pointer :: amat(:,:)
596596
${rt}$, allocatable, target :: amat_alloc(:,:)
@@ -644,22 +644,23 @@ submodule (stdlib_linalg) stdlib_linalg_least_squares
644644

645645
! Handle A matrix: either copy or use original
646646
if (copy_a) then
647-
allocate(amat_alloc(m, n))
647+
allocate(amat_alloc(m, n), source=a)
648648
amat => amat_alloc
649649
else
650650
amat => a
651651
end if
652652

653-
! Scale A column-wise (cache-friendly: column-major order)
654-
do j = 1, n
655-
amat(:, j) = sqrt_w(:) * a(:, j)
656-
end do
653+
! Scale rows of A by sqrt(w) using LAPACK's lascl2
654+
call lascl2(m, n, sqrt_w, amat, m)
657655

658656
! Scale b
659657
b_scaled = sqrt_w * b
660658

661-
! Solve transformed OLS problem
662-
call stdlib_linalg_${ri}$_solve_lstsq_one(amat, b_scaled, x, cond=cond, overwrite_a=.true., rank=rank, err=err)
659+
! Solve transformed OLS problem using local error state
660+
call stdlib_linalg_${ri}$_solve_lstsq_one(amat, b_scaled, x, cond=cond, overwrite_a=.true., rank=rank, err=err0)
661+
662+
! Propagate error with updated location
663+
call linalg_error_handling(err0, err, where_at=this)
663664

664665
! Cleanup
665666
if (copy_a) deallocate(amat_alloc)

src/linalg_core/stdlib_linalg_state.fypp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,25 @@ module stdlib_linalg_state
7373
end function linalg_message
7474

7575
!> Flow control: on output flag present, return it; otherwise, halt on error
76-
pure subroutine linalg_error_handling(ierr,ierr_out)
76+
!> If where_at is provided, update the error location before returning/stopping
77+
pure subroutine linalg_error_handling(ierr,ierr_out,where_at)
7778
type(linalg_state_type),intent(in) :: ierr
7879
type(linalg_state_type),optional,intent(out) :: ierr_out
80+
character(len=*),optional,intent(in) :: where_at
7981

8082
character(len=:),allocatable :: err_msg
8183

8284
if (present(ierr_out)) then
8385
! Return error flag
8486
ierr_out = ierr
87+
! Update location if requested
88+
if (present(where_at)) call ierr_out%update_location(where_at)
8589
elseif (ierr%error()) then
86-
err_msg = ierr%print()
90+
if (present(where_at)) then
91+
err_msg = '['//trim(where_at)//'] returned '//ierr%print_msg()
92+
else
93+
err_msg = ierr%print()
94+
end if
8795
error stop err_msg
8896
end if
8997

0 commit comments

Comments
 (0)