1
+ """
2
+ Represent an Orthogonal polynomial which has a conversion operator from P, that is, Q = P * inv(U).
3
+ """
4
+ struct ConvertedOrthogonalPolynomial{T, WW<: AbstractQuasiVector{T} , XX, UU, PP} <: OrthonormalPolynomial{T}
5
+ weight:: WW
6
+ X:: XX # jacobimatrix
7
+ U:: UU # conversion to P
8
+ P:: PP
9
+ end
10
+
11
+ _p0 (Q:: ConvertedOrthogonalPolynomial ) = _p0 (Q. P)
12
+
13
+ axes (Q:: ConvertedOrthogonalPolynomial ) = axes (Q. P)
14
+ MemoryLayout (:: Type{<:ConvertedOrthogonalPolynomial} ) = ConvertedOPLayout ()
15
+ jacobimatrix (Q:: ConvertedOrthogonalPolynomial ) = Q. X
16
+ orthogonalityweight (Q:: ConvertedOrthogonalPolynomial ) = Q. weight
17
+
18
+
19
+ # transform to P * U if needed for differentiation, etc.
20
+ arguments (:: ApplyLayout{typeof(*)} , Q:: ConvertedOrthogonalPolynomial ) = Q. P, ApplyArray (inv, Q. U)
21
+
22
+ OrthogonalPolynomial (w:: AbstractQuasiVector ) = OrthogonalPolynomial (w, orthogonalpolynomial (singularities (w)))
23
+ function OrthogonalPolynomial (w:: AbstractQuasiVector , P:: AbstractQuasiMatrix )
24
+ Q = normalized (P)
25
+ X = cholesky_jacobimatrix (w, Q)
26
+ ConvertedOrthogonalPolynomial (w, X, X. dv. U, Q)
27
+ end
28
+
29
+ orthogonalpolynomial (w:: AbstractQuasiVector ) = OrthogonalPolynomial (w)
30
+ orthogonalpolynomial (w:: SubQuasiArray ) = orthogonalpolynomial (parent (w))[parentindices (w)[1 ],:]
31
+
32
+
33
+
1
34
"""
2
35
cholesky_jacobimatrix(w, P)
3
36
4
37
returns the Jacobi matrix `X` associated to a quasi-matrix of polynomials
5
38
orthogonal with respect to `w(x) w_p(x)` where `w_p(x)` is the weight of the polynomials in `P`.
6
39
7
40
The resulting polynomials are orthonormal on the same domain as `P`. The supplied `P` must be normalized. Accepted inputs are `w` as a function or `W` as an infinite matrix representing multiplication with the function `w` on the basis `P`.
8
-
9
- An optional bool can be supplied, i.e. `cholesky_jacobimatrix(sqrtw, P, false)` to disable checks of symmetry for the weight multiplication matrix and orthonormality for the basis (use with caution).
10
41
"""
11
- function cholesky_jacobimatrix (w:: Function , P:: OrthogonalPolynomial , checks:: Bool = true )
12
- checks && ! (P isa Normalized) && error (" Polynomials must be orthonormal." )
13
- W = Symmetric (P \ (w .(axes (P,1 )) .* P)) # Compute weight multiplication via Clenshaw
14
- return cholesky_jacobimatrix (W, P, false ) # At this point checks already passed or were entered as false, no need to recheck
42
+ cholesky_jacobimatrix (w:: Function , P) = cholesky_jacobimatrix (w .(axes (P,1 )), P)
43
+
44
+ function cholesky_jacobimatrix (w:: AbstractQuasiVector , P)
45
+ Q = normalized (P)
46
+ W = Symmetric (Q \ (w .* Q)) # Compute weight multiplication via Clenshaw
47
+ return cholesky_jacobimatrix (W, Q)
15
48
end
16
- function cholesky_jacobimatrix (W:: AbstractMatrix , P:: OrthogonalPolynomial , checks:: Bool = true )
17
- checks && ! (P isa Normalized) && error (" Polynomials must be orthonormal." )
18
- checks && ! (W isa Symmetric) && error (" Weight modification matrix must be symmetric." )
19
- return SymTridiagonal (CholeskyJacobiBands {:dv} (W,P),CholeskyJacobiBands {:ev} (W,P))
49
+ function cholesky_jacobimatrix (W:: AbstractMatrix , Q)
50
+ isnormalized (Q) || error (" Polynomials must be orthonormal" )
51
+ U = cholesky (W). U
52
+ X = jacobimatrix (Q)
53
+ UX = ApplyArray (* ,U,X)
54
+ return SymTridiagonal (CholeskyJacobiBand {:dv} (U, UX),CholeskyJacobiBand {:ev} (U, UX))
20
55
end
21
56
22
57
# The generated Jacobi operators are symmetric tridiagonal, so we store their data in cached bands
23
- mutable struct CholeskyJacobiBands {dv,T} <: AbstractCachedVector{T}
58
+ mutable struct CholeskyJacobiBand {dv,T} <: AbstractCachedVector{T}
24
59
data:: Vector{T} # store band entries, :dv for diagonal, :ev for off-diagonal
25
60
U:: UpperTriangular{T} # store upper triangular conversion matrix (needed to extend available entries)
26
61
UX:: ApplyArray{T} # store U*X, where X is the Jacobi matrix of the original P (needed to extend available entries)
27
62
datasize:: Int # size of so-far computed block
28
63
end
29
64
30
65
# Computes the initial data for the Jacobi operator bands
31
- function CholeskyJacobiBands {:dv} (W, P:: OrthogonalPolynomial{T} ) where T
32
- U = cholesky (W). U
33
- X = jacobimatrix (P)
34
- UX = ApplyArray (* ,U,X)
66
+ function CholeskyJacobiBand {:dv} (U:: AbstractMatrix{T} , UX) where T
35
67
dv = zeros (T,2 ) # compute a length 2 vector on first go
36
68
dv[1 ] = dot (view (UX,1 ,1 ), U[1 ,1 ] \ [one (T)])
37
69
dv[2 ] = dot (view (UX,2 ,1 : 2 ), U[1 : 2 ,1 : 2 ] \ [zero (T); one (T)])
38
- return CholeskyJacobiBands {:dv,T} (dv, U, UX, 2 )
70
+ return CholeskyJacobiBand {:dv,T} (dv, U, UX, 2 )
39
71
end
40
- function CholeskyJacobiBands {:ev} (W, P:: OrthogonalPolynomial{T} ) where T
41
- U = cholesky (W). U
42
- X = jacobimatrix (P)
43
- UX = ApplyArray (* ,U,X)
72
+ function CholeskyJacobiBand {:ev} (U:: AbstractMatrix{T} , UX) where T
44
73
ev = zeros (T,2 ) # compute a length 2 vector on first go
45
74
ev[1 ] = dot (view (UX,1 ,1 : 2 ), U[1 : 2 ,1 : 2 ] \ [zero (T); one (T)])
46
75
ev[2 ] = dot (view (UX,2 ,1 : 3 ), U[1 : 3 ,1 : 3 ] \ [zeros (T,2 ); one (T)])
47
- return CholeskyJacobiBands {:ev,T} (ev, U, UX, 2 )
76
+ return CholeskyJacobiBand {:ev,T} (ev, U, UX, 2 )
48
77
end
49
78
50
- size (:: CholeskyJacobiBands ) = (ℵ₀,) # Stored as an infinite cached vector
79
+ size (:: CholeskyJacobiBand ) = (ℵ₀,) # Stored as an infinite cached vector
51
80
52
81
# Resize and filling functions for cached implementation
53
- function resizedata! (K:: CholeskyJacobiBands , nm:: Integer )
82
+ function resizedata! (K:: CholeskyJacobiBand , nm:: Integer )
54
83
νμ = K. datasize
55
84
if nm > νμ
56
85
resize! (K. data,nm)
@@ -59,7 +88,7 @@ function resizedata!(K::CholeskyJacobiBands, nm::Integer)
59
88
end
60
89
K
61
90
end
62
- function cache_filldata! (J:: CholeskyJacobiBands {:dv,T} , inds:: UnitRange{Int} ) where T
91
+ function cache_filldata! (J:: CholeskyJacobiBand {:dv,T} , inds:: UnitRange{Int} ) where T
63
92
# pre-fill U and UX to prevent expensive step-by-step filling in of cached U and UX in the loop
64
93
getindex (J. U,inds[end ]+ 1 ,inds[end ]+ 1 )
65
94
getindex (J. UX,inds[end ]+ 1 ,inds[end ]+ 1 )
@@ -69,7 +98,7 @@ function cache_filldata!(J::CholeskyJacobiBands{:dv,T}, inds::UnitRange{Int}) wh
69
98
J. data[k] = dot (view (J. UX,k,k- 1 : k), J. U[k- 1 : k,k- 1 : k] \ ek)
70
99
end
71
100
end
72
- function cache_filldata! (J:: CholeskyJacobiBands {:ev, T} , inds:: UnitRange{Int} ) where T
101
+ function cache_filldata! (J:: CholeskyJacobiBand {:ev, T} , inds:: UnitRange{Int} ) where T
73
102
# pre-fill U and UX to prevent expensive step-by-step filling in of cached U and UX in the loop
74
103
getindex (J. U,inds[end ]+ 1 ,inds[end ]+ 1 )
75
104
getindex (J. UX,inds[end ]+ 1 ,inds[end ]+ 1 )
@@ -88,55 +117,52 @@ returns the Jacobi matrix `X` associated to a quasi-matrix of polynomials
88
117
orthogonal with respect to `w(x) w_p(x)` where `w_p(x)` is the weight of the polynomials in `P`.
89
118
90
119
The resulting polynomials are orthonormal on the same domain as `P`. The supplied `P` must be normalized. Accepted inputs for `sqrtw` are the square root of the weight modification as a function or `sqrtW` as an infinite matrix representing multiplication with the function `sqrt(w)` on the basis `P`.
91
-
92
- An optional bool can be supplied, i.e. `qr_jacobimatrix(sqrtw, P, false)` to disable checks of symmetry for the weight multiplication matrix and orthonormality for the basis (use with caution).
93
120
"""
94
- function qr_jacobimatrix (sqrtw:: Function , P:: OrthogonalPolynomial , checks:: Bool = true )
95
- checks && ! (P isa Normalized) && error (" Polynomials must be orthonormal." )
96
- sqrtW = (P \ (sqrtw .(axes (P,1 )) .* P)) # Compute weight multiplication via Clenshaw
97
- return qr_jacobimatrix (sqrtW, P, false ) # At this point checks already passed or were entered as false, no need to recheck
121
+ function qr_jacobimatrix (sqrtw:: Function , P)
122
+ Q = normalized (P)
123
+ x = axes (P,1 )
124
+ sqrtW = (Q \ (sqrtw .(x) .* Q)) # Compute weight multiplication via Clenshaw
125
+ return qr_jacobimatrix (sqrtW, Q)
98
126
end
99
- function qr_jacobimatrix (sqrtW:: AbstractMatrix , P:: OrthogonalPolynomial , checks:: Bool = true )
100
- checks && ! (P isa Normalized) && error (" Polynomials must be orthonormal." )
101
- checks && ! (sqrtW isa Symmetric) && error (" Weight modification matrix must be symmetric." )
102
- K = SymTridiagonal (QRJacobiBands {:dv} (sqrtW,P),QRJacobiBands {:ev} (sqrtW,P))
103
- return K
127
+ function qr_jacobimatrix (sqrtW:: AbstractMatrix , Q)
128
+ isnormalized (Q) || error (" Polynomials must be orthonormal" )
129
+ SymTridiagonal (QRJacobiBand {:dv} (sqrtW,Q),QRJacobiBand {:ev} (sqrtW,Q))
104
130
end
105
131
106
132
# The generated Jacobi operators are symmetric tridiagonal, so we store their data in cached bands
107
- mutable struct QRJacobiBands {dv,T} <: AbstractCachedVector{T}
133
+ mutable struct QRJacobiBand {dv,T} <: AbstractCachedVector{T}
108
134
data:: Vector{T} # store band entries, :dv for diagonal, :ev for off-diagonal
109
135
U:: ApplyArray{T} # store upper triangular conversion matrix (needed to extend available entries)
110
136
UX:: ApplyArray{T} # store U*X, where X is the Jacobi matrix of the original P (needed to extend available entries)
111
137
datasize:: Int # size of so-far computed block
112
138
end
113
139
114
140
# Computes the initial data for the Jacobi operator bands
115
- function QRJacobiBands {:dv} (sqrtW, P:: OrthogonalPolynomial{T} ) where T
141
+ function QRJacobiBand {:dv} (sqrtW, P:: OrthogonalPolynomial{T} ) where T
116
142
U = qr (sqrtW). R
117
143
U = ApplyArray (* ,Diagonal (sign .(view (U,band (0 )))),U)
118
144
X = jacobimatrix (P)
119
145
UX = ApplyArray (* ,U,X)
120
146
dv = zeros (T,2 ) # compute a length 2 vector on first go
121
147
dv[1 ] = dot (view (UX,1 ,1 ), U[1 ,1 ] \ [one (T)])
122
148
dv[2 ] = dot (view (UX,2 ,1 : 2 ), U[1 : 2 ,1 : 2 ] \ [zero (T); one (T)])
123
- return QRJacobiBands {:dv,T} (dv, U, UX, 2 )
149
+ return QRJacobiBand {:dv,T} (dv, U, UX, 2 )
124
150
end
125
- function QRJacobiBands {:ev} (sqrtW, P:: OrthogonalPolynomial{T} ) where T
151
+ function QRJacobiBand {:ev} (sqrtW, P:: OrthogonalPolynomial{T} ) where T
126
152
U = qr (sqrtW). R
127
153
U = ApplyArray (* ,Diagonal (sign .(view (U,band (0 )))),U)
128
154
X = jacobimatrix (P)
129
155
UX = ApplyArray (* ,U,X)
130
156
ev = zeros (T,2 ) # compute a length 2 vector on first go
131
157
ev[1 ] = dot (view (UX,1 ,1 : 2 ), U[1 : 2 ,1 : 2 ] \ [zero (T); one (T)])
132
158
ev[2 ] = dot (view (UX,2 ,1 : 3 ), U[1 : 3 ,1 : 3 ] \ [zeros (T,2 ); one (T)])
133
- return QRJacobiBands {:ev,T} (ev, U, UX, 2 )
159
+ return QRJacobiBand {:ev,T} (ev, U, UX, 2 )
134
160
end
135
161
136
- size (:: QRJacobiBands ) = (ℵ₀,) # Stored as an infinite cached vector
162
+ size (:: QRJacobiBand ) = (ℵ₀,) # Stored as an infinite cached vector
137
163
138
164
# Resize and filling functions for cached implementation
139
- function resizedata! (K:: QRJacobiBands , nm:: Integer )
165
+ function resizedata! (K:: QRJacobiBand , nm:: Integer )
140
166
νμ = K. datasize
141
167
if nm > νμ
142
168
resize! (K. data,nm)
@@ -145,7 +171,7 @@ function resizedata!(K::QRJacobiBands, nm::Integer)
145
171
end
146
172
K
147
173
end
148
- function cache_filldata! (J:: QRJacobiBands {:dv,T} , inds:: UnitRange{Int} ) where T
174
+ function cache_filldata! (J:: QRJacobiBand {:dv,T} , inds:: UnitRange{Int} ) where T
149
175
# pre-fill U and UX to prevent expensive step-by-step filling in of cached U and UX in the loop
150
176
getindex (J. U,inds[end ]+ 1 ,inds[end ]+ 1 )
151
177
getindex (J. UX,inds[end ]+ 1 ,inds[end ]+ 1 )
@@ -155,7 +181,7 @@ function cache_filldata!(J::QRJacobiBands{:dv,T}, inds::UnitRange{Int}) where T
155
181
J. data[k] = dot (view (J. UX,k,k- 1 : k), J. U[k- 1 : k,k- 1 : k] \ ek)
156
182
end
157
183
end
158
- function cache_filldata! (J:: QRJacobiBands {:ev, T} , inds:: UnitRange{Int} ) where T
184
+ function cache_filldata! (J:: QRJacobiBand {:ev, T} , inds:: UnitRange{Int} ) where T
159
185
# pre-fill U and UX to prevent expensive step-by-step filling in of cached U and UX in the loop
160
186
getindex (J. U,inds[end ]+ 1 ,inds[end ]+ 1 )
161
187
getindex (J. UX,inds[end ]+ 1 ,inds[end ]+ 1 )
0 commit comments