@@ -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