Skip to content

Commit a244b86

Browse files
committed
Add shifted-pivot and two-matrix Givens rotation helpers
Add fp_rotate_shifted_vec for single-matrix shifted-pivot rotations (smoothing iterations in fpcons, fppara) and fp_rotate_row_2mat_vec for two-matrix periodic rotations (fpclos). Replace all 4 remaining shifting-pivot call sites with calls to these new helpers. Remove unused variables from fpclos, fpcons, and fppara.
1 parent 5c12939 commit a244b86

File tree

2 files changed

+100
-140
lines changed

2 files changed

+100
-140
lines changed

docs/refactoring/00_refactoring_summary.md

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,32 +44,22 @@ with explicit-shape arrays `h(band)`, `a(nest,*)`, `xi(idim)`, `z(n,idim)`.
4444
Replaced 3 standard Variant B call sites in `fpclos`, `fpcons`, `fppara`.
4545
Removed unused variables `i1`, `i3` from `fpcons` and `fppara`.
4646

47+
### PR 6: Shifting-Pivot and Two-Matrix Givens Rotations (DONE)
48+
49+
**Changes**: Added `fp_rotate_shifted_vec` (single-matrix shifted-pivot rotation)
50+
and `fp_rotate_row_2mat_vec` (two-matrix rotation for periodic splines).
51+
Replaced 4 remaining shifting-pivot call sites: 2 in `fpclos` (two-matrix periodic),
52+
1 in `fpcons`, 1 in `fppara` (single-matrix smoothing iterations).
53+
Removed unused variables: `piv`, `ij` from `fpclos`; `cos`, `sin`, `piv`, `i2`
54+
from `fpcons` and `fppara`.
55+
4756
---
4857

4958
## Remaining Plan
5059

5160
Each item below is a separate PR. PRs are ordered by dependency; documentation (PR 9) can
5261
proceed in parallel with any code PR.
5362

54-
### PR 6: Variant B/C Shifting-Pivot Givens Rotations
55-
56-
**Scope**: Shifting-pivot and two-matrix periodic rotation variants
57-
**New routines**: `fp_rotate_row_2mat` (two-matrix rotation for periodic splines),
58-
possibly `fp_rotate_shifted_vec` (single-matrix with pivot shift)
59-
**Remaining occurrences** (4 sites, all use shifting-pivot pattern `h(1:n) = [h(2:n), zero]`):
60-
61-
| Site | Routine | Pattern | Notes |
62-
|------|---------|---------|-------|
63-
| 1 | fpclos | two-matrix (a1,a2) + shift + vec z | Variant C |
64-
| 2 | fpclos | two-matrix (g1,g2) + shift + vec c | Variant C |
65-
| 3 | fpcons | single-matrix (g) + shift + vec c | could use `fp_rotate_shifted_vec` |
66-
| 4 | fppara | single-matrix (g) + shift + vec c | could use `fp_rotate_shifted_vec` |
67-
68-
**Difficulty**: Medium — shifting pivot and secondary matrix add complexity
69-
**See**: [01_qr_row_rotation_refactor.md](01_qr_row_rotation_refactor.md), Variants B & C
70-
71-
---
72-
7363
### PR 7: Variant D Givens Rotations
7464

7565
**Scope**: Grid/surface fitting rotation patterns

src/fitpack_core.F90

Lines changed: 91 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -3034,9 +3034,9 @@ pure subroutine fpclos(iopt,idim,m,u,mx,x,w,k,s,nest,tol, &
30343034
integer(FP_SIZE), intent(inout) :: nrdata(nest)
30353035

30363036
! ..local scalars..
3037-
real(FP_REAL) :: acc,cos,d1,fac,fpart,fpms,fpold,fp0,f1,f2,f3,p,per,pinv,piv,p1,p2,p3,sin,store,&
3037+
real(FP_REAL) :: acc,cos,d1,fac,fpart,fpms,fpold,fp0,f1,f2,f3,p,per,pinv,p1,p2,p3,sin,store,&
30383038
term,ui,wi,rn
3039-
integer(FP_SIZE) :: i,ij,ik,it,iter,i1,i2,j,jj,jk,jper,j1,j2,kk,kk1,k3,l,l0,l1,l5,mm,m1,new,&
3039+
integer(FP_SIZE) :: i,ik,it,iter,i1,i2,j,jj,jk,jper,j1,j2,kk,kk1,k3,l,l0,l1,l5,mm,m1,new,&
30403040
nk1,nk2,nmax,nmin,nplus,npl1,nrint,n10,n11,n7,n8
30413041
! ..local arrays..
30423042
real(FP_REAL) :: h(MAX_ORDER+1),h1(DEGREE_5+2),h2(DEGREE_5+1),xi(MAX_IDIM)
@@ -3296,50 +3296,7 @@ pure subroutine fpclos(iopt,idim,m,u,mx,x,w,k,s,nest,tol, &
32963296

32973297
! rotate the new row of the observation matrix into triangle
32983298
! by givens transformations.
3299-
if (n10>0) then
3300-
! rotation with the rows 1,2,...n10 of matrix a.
3301-
one_to_n10: do j=1,n10
3302-
piv = h1(1)
3303-
if (equal(piv,zero)) then
3304-
h1(1:kk1) = [h1(2:kk1),zero]
3305-
else
3306-
! calculate the parameters of the givens transformation.
3307-
call fpgivs(piv,a1(j,1),cos,sin)
3308-
3309-
! transformation to the right hand side.
3310-
call fprota(cos,sin,xi(1:idim),z(j:j+(idim-1)*n:n))
3311-
3312-
! transformations to the left hand side with respect to a2.
3313-
call fprota(cos,sin,h2(1:kk),a2(j,1:kk))
3314-
3315-
if (j==n10) exit one_to_n10
3316-
i2 = min(n10-j,kk)+1
3317-
3318-
! transformations to the left hand side with respect to a1.
3319-
call fprota(cos,sin,h1(2:i2),a1(j,2:i2))
3320-
h1(1:i2) = [h1(2:i2),zero]
3321-
endif
3322-
end do one_to_n10
3323-
endif ! n10>0
3324-
3325-
! rotation with the rows n10+1,...n7 of matrix a.
3326-
n10_to_n7: do j=1,kk
3327-
ij = n10+j
3328-
piv = h2(j)
3329-
if (ij<=0 .or. equal(piv,zero)) cycle n10_to_n7
3330-
3331-
! calculate the parameters of the givens transformation.
3332-
call fpgivs(piv,a2(ij,j),cos,sin)
3333-
! transformations to right hand side.
3334-
call fprota(cos,sin,xi(1:idim),z(ij:ij+(idim-1)*n:n))
3335-
3336-
if (j==kk) exit n10_to_n7
3337-
3338-
! transformations to left hand side.
3339-
j1 = j+1
3340-
call fprota(cos,sin,h2(j1:kk),a2(ij,j1:kk))
3341-
3342-
end do n10_to_n7
3299+
call fp_rotate_row_2mat_vec(h1, kk1, h2, kk, a1, a2, nest, xi, z, 1, n10, n, idim)
33433300

33443301
else all_zero
33453302

@@ -3579,46 +3536,7 @@ pure subroutine fpclos(iopt,idim,m,u,mx,x,w,k,s,nest,tol, &
35793536
endif
35803537

35813538
! rotate this row into triangle by givens transformations
3582-
! rotation with the rows l,l+1,...n11.
3583-
rot_n11: do j=l,n11
3584-
piv = h1(1)
3585-
3586-
! calculate the parameters of the givens transformation.
3587-
call fpgivs(piv,g1(j,1),cos,sin)
3588-
3589-
! transformation to right hand side.
3590-
call fprota(cos,sin,xi(1:idim),c(j:j+(idim-1)*n:n))
3591-
3592-
! transformation to the left hand side with respect to g2.
3593-
call fprota(cos,sin,h2(1:k1),g2(j,1:k1))
3594-
3595-
if (j==n11) exit rot_n11
3596-
3597-
! transformation to the left hand side with respect to g1.
3598-
i2 = min(n11-j,k1)+1
3599-
call fprota(cos,sin,h1(2:i2),g1(j,2:i2))
3600-
h1(1:i2) = [h1(2:i2),zero]
3601-
3602-
end do rot_n11
3603-
3604-
! rotation with the rows n11+1,...n7
3605-
rot_n10_n7: do j=1,k1
3606-
ij = n11+j
3607-
if (ij<=0) cycle rot_n10_n7
3608-
piv = h2(j)
3609-
3610-
! calculate the parameters of the givens transformation
3611-
call fpgivs(piv,g2(ij,j),cos,sin)
3612-
3613-
! transformation to the right hand side.
3614-
call fprota(cos,sin,xi(1:idim),c(ij:ij+(idim-1)*n:n))
3615-
3616-
if (j<k1) then
3617-
! transformation to the left hand side.
3618-
j1 = j+1
3619-
call fprota(cos,sin,h2(j1:k1),g2(ij,j1:k1))
3620-
endif
3621-
end do rot_n10_n7
3539+
call fp_rotate_row_2mat_vec(h1, k2, h2, k1, g1, g2, nest, xi, c, l, n11, n, idim)
36223540
end do n8_rows
36233541

36243542
! backward substitution to obtain the b-spline coefficients
@@ -3945,8 +3863,8 @@ pure subroutine fpcons(iopt,idim,m,u,mx,x,w,ib,ie,k,s,nest, &
39453863
real(FP_REAL), intent(inout) :: t(nest),c(nc),fpint(nest),z(nc),a(nest,k1),b(nest,k2),g(nest,k2),q(m,k1)
39463864
integer(FP_SIZE), intent(inout) :: nrdata(nest)
39473865
! ..local scalars..
3948-
real(FP_REAL) :: acc,cos,fac,fpart,fpms,fpold,fp0,f1,f2,f3,p,pinv,piv,p1,p2,p3,rn,sin,store,term,ui,wi
3949-
integer(FP_SIZE) :: i,it,iter,i2,j,jb,je,jj,j1,j2,j3,kbe,l,li,lj,l0,mb,me,mm,nk1,&
3866+
real(FP_REAL) :: acc,fac,fpart,fpms,fpold,fp0,f1,f2,f3,p,pinv,p1,p2,p3,rn,store,term,ui,wi
3867+
integer(FP_SIZE) :: i,it,iter,j,jb,je,jj,j1,j2,j3,kbe,l,li,lj,l0,mb,me,mm,nk1,&
39503868
nmax,nmin,nn,nplus,npl1,nrint,n8,mmin
39513869
logical(FP_BOOL) :: new,check1,check3,success
39523870
! ..local arrays..
@@ -4290,22 +4208,7 @@ pure subroutine fpcons(iopt,idim,m,u,mx,x,w,ib,ie,k,s,nest, &
42904208
endif
42914209

42924210
jj = max(1,it-ib)
4293-
b_cols: do j=jj,nn
4294-
piv = h(1)
4295-
4296-
! calculate the parameters of the givens transformation.
4297-
call fpgivs(piv,g(j,1),cos,sin)
4298-
4299-
! transformations to right hand side.
4300-
call fprota(cos,sin,xi(1:idim),c(j:j+(idim-1)*n:n))
4301-
4302-
! transformations to left hand side.
4303-
if (j<nn) then
4304-
i2 = min(nn-j,k1)+1
4305-
call fprota(cos,sin,h(2:i2),g(j,2:i2))
4306-
h(1:i2) = [h(2:i2),zero]
4307-
endif
4308-
end do b_cols
4211+
call fp_rotate_shifted_vec(h, k2, g, nest, xi, c, jj, nn, n, idim)
43094212
end do b_rows
43104213

43114214
! backward substitution to obtain the b-spline coefficients.
@@ -5696,6 +5599,87 @@ pure subroutine fp_rotate_row_vec(h, band, a, nest, xi, z, j_start, n, idim)
56965599
end do
56975600
end subroutine fp_rotate_row_vec
56985601

5602+
!> Shifted-pivot variant of fp_rotate_row_vec: rotates a new observation row into
5603+
!> upper-triangular band matrix a(nest,band) using Givens rotations, with idim
5604+
!> right-hand sides stored column-wise in z(n,idim).
5605+
!>
5606+
!> Unlike fp_rotate_row_vec (which walks h(i) for i=1..band), this routine always
5607+
!> pivots on h(1) and shifts h left after each rotation step. The effective bandwidth
5608+
!> shrinks as the loop nears j_end. Used by smoothing iterations in fpcons (§7.2.3,
5609+
!> Eq. 7.12) and fppara (§6.3.1, Eq. 6.48) where the smoothing-matrix rows are
5610+
!> rotated into the already-triangularized observation matrix.
5611+
!>
5612+
!> Book ref: §4.1.2 Eq. 4.15 (Givens rotation), §5.2.2 Eq. 5.14-5.16 (smoothing
5613+
!> matrix P with bandwidth k+2), Fig. 5.1 (band structure of P and R₁*).
5614+
pure subroutine fp_rotate_shifted_vec(h, band, a, nest, xi, z, j_start, j_end, n, idim)
5615+
integer(FP_SIZE), intent(in) :: band, nest, n, idim, j_start, j_end
5616+
real(FP_REAL), intent(inout) :: h(band), a(nest,*), xi(idim), z(n,idim)
5617+
5618+
real(FP_REAL) :: cos, sin, piv
5619+
integer(FP_SIZE) :: i2, j
5620+
5621+
do j = j_start, j_end
5622+
piv = h(1)
5623+
call fpgivs(piv, a(j,1), cos, sin)
5624+
call fprota(cos, sin, xi, z(j, 1:idim))
5625+
if (j < j_end) then
5626+
i2 = min(j_end - j, band - 1) + 1
5627+
call fprota(cos, sin, h(2:i2), a(j, 2:i2))
5628+
h(1:i2) = [h(2:i2), zero]
5629+
endif
5630+
end do
5631+
end subroutine fp_rotate_shifted_vec
5632+
5633+
!> Two-matrix variant of fp_rotate_row_vec for periodic spline fitting.
5634+
!> Rotates a split observation row [h1 | h2] into the block-triangular system
5635+
!> [a1 | a2] using Givens rotations, with idim right-hand sides in z(n,idim).
5636+
!>
5637+
!> Phase 1: Rotate h1 through a1 with shifting pivot (h1(1) always), while
5638+
!> simultaneously applying cross-rotations to h2 and a2.
5639+
!> Phase 2: Rotate remaining h2 through a2 (standard, diagonal at a2(ij,j)).
5640+
!>
5641+
!> The two-matrix decomposition arises from periodic B-spline constraints that
5642+
!> wrap the last k columns of the observation matrix into the first k, creating
5643+
!> a block structure [R₁₁* R₁₂*; 0 R₂₂*] (§6.1.1, Eq. 6.13, Fig. 6.1).
5644+
!>
5645+
!> Book ref: §6.1.1 Eq. 6.10, 6.13 (periodic smoothing system and triangular
5646+
!> decomposition), §4.1.2 Eq. 4.15 (Givens rotation mechanics).
5647+
pure subroutine fp_rotate_row_2mat_vec(h1, band1, h2, band2, a1, a2, nest, &
5648+
xi, z, j1_start, j1_end, n, idim)
5649+
integer(FP_SIZE), intent(in) :: band1, band2, nest, n, idim, j1_start, j1_end
5650+
real(FP_REAL), intent(inout) :: h1(band1), h2(band2)
5651+
real(FP_REAL), intent(inout) :: a1(nest,*), a2(nest,*)
5652+
real(FP_REAL), intent(inout) :: xi(idim), z(n,idim)
5653+
5654+
real(FP_REAL) :: cos, sin, piv
5655+
integer(FP_SIZE) :: i2, ij, j
5656+
5657+
! Phase 1: rotate h1 through a1 with shifting, cross-rotating h2/a2
5658+
do j = j1_start, j1_end
5659+
piv = h1(1)
5660+
call fpgivs(piv, a1(j,1), cos, sin)
5661+
call fprota(cos, sin, xi, z(j, 1:idim))
5662+
call fprota(cos, sin, h2(1:band2), a2(j, 1:band2))
5663+
if (j < j1_end) then
5664+
i2 = min(j1_end - j, band1 - 1) + 1
5665+
call fprota(cos, sin, h1(2:i2), a1(j, 2:i2))
5666+
h1(1:i2) = [h1(2:i2), zero]
5667+
endif
5668+
end do
5669+
5670+
! Phase 2: rotate h2 through a2 (diagonal at a2(ij,j))
5671+
do j = 1, band2
5672+
ij = j1_end + j
5673+
if (ij <= 0) cycle
5674+
piv = h2(j)
5675+
call fpgivs(piv, a2(ij,j), cos, sin)
5676+
call fprota(cos, sin, xi, z(ij, 1:idim))
5677+
if (j < band2) then
5678+
call fprota(cos, sin, h2(j+1:band2), a2(ij, j+1:band2))
5679+
endif
5680+
end do
5681+
end subroutine fp_rotate_row_2mat_vec
5682+
56995683

57005684
! Compute spline coefficients on a rectangular grid
57015685
pure subroutine fpgrdi(ifsu,ifsv,ifbu,ifbv,lback,u,mu,v, &
@@ -8247,8 +8231,8 @@ pure subroutine fppara(iopt,idim,m,u,mx,x,w,ub,ue,k,s,nest,tol,maxit, &
82478231
integer(FP_SIZE), intent(inout) :: nrdata(nest)
82488232

82498233
! ..local scalars..
8250-
real(FP_REAL) :: acc,cos,fac,fpart,fpms,fpold,fp0,f1,f2,f3,p,pinv,piv,p1,p2,p3,rn,sin,store,term,ui,wi
8251-
integer(FP_SIZE) :: i,it,iter,i2,j,jj,j1,j2,k3,l,l0,mk1,nk1,nmax,nmin,nplus,npl1,nrint,n8
8234+
real(FP_REAL) :: acc,fac,fpart,fpms,fpold,fp0,f1,f2,f3,p,pinv,p1,p2,p3,rn,store,term,ui,wi
8235+
integer(FP_SIZE) :: i,it,iter,j,jj,j1,j2,k3,l,l0,mk1,nk1,nmax,nmin,nplus,npl1,nrint,n8
82528236
logical(FP_BOOL) :: new,check1,check3,success
82538237
! ..local arrays..
82548238
real(FP_REAL) :: h(MAX_ORDER+1),xi(idim)
@@ -8544,21 +8528,7 @@ pure subroutine fppara(iopt,idim,m,u,mx,x,w,ub,ue,k,s,nest,tol,maxit, &
85448528
! the row of matrix b is rotated into triangle by givens transformation
85458529
h(1:k2) = b(it,1:k2)*pinv
85468530
xi = zero
8547-
b_cols: do j=it,nk1
8548-
piv = h(1)
8549-
8550-
! calculate the parameters of the givens transformation.
8551-
call fpgivs(piv,g(j,1),cos,sin)
8552-
8553-
! transformations to right hand side.
8554-
call fprota(cos,sin,xi,c(j:j+(idim-1)*n:n))
8555-
if (j==nk1) cycle b_rows
8556-
8557-
! transformations to left hand side.
8558-
i2 = merge(nk1-j,k1,j>n8)+1
8559-
call fprota(cos,sin,h(2:i2),g(j,2:i2))
8560-
h(1:i2) = [h(2:i2),zero]
8561-
end do b_cols
8531+
call fp_rotate_shifted_vec(h, k2, g, nest, xi, c, it, nk1, n, idim)
85628532
end do b_rows
85638533

85648534
! backward substitution to obtain the b-spline coefficients.

0 commit comments

Comments
 (0)