Skip to content

Commit a83ff55

Browse files
authored
Add standard chop (#94)
* Use standard chop to see if tail is zero * add standardchop * weaker zero test * tests pass * Update Project.toml
1 parent 9ef7f01 commit a83ff55

File tree

8 files changed

+135
-16
lines changed

8 files changed

+135
-16
lines changed

Project.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ClassicalOrthogonalPolynomials"
22
uuid = "b30e2e7b-c4ee-47da-9d5f-2c5c27239acd"
33
authors = ["Sheehan Olver <[email protected]>"]
4-
version = "0.6"
4+
version = "0.6.1"
55

66
[deps]
77
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -28,7 +28,7 @@ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
2828
ArrayLayouts = "0.8"
2929
BandedMatrices = "0.17"
3030
BlockArrays = "0.16.9"
31-
BlockBandedMatrices = "0.11"
31+
BlockBandedMatrices = "0.11.6"
3232
ContinuumArrays = "0.10"
3333
DomainSets = "0.5.6"
3434
FFTW = "1.1"
@@ -37,20 +37,21 @@ FastTransforms = "0.13"
3737
FillArrays = "0.13"
3838
HypergeometricFunctions = "0.3.4"
3939
InfiniteArrays = "0.12.3"
40-
InfiniteLinearAlgebra = "0.6.5"
40+
InfiniteLinearAlgebra = "0.6.7"
4141
IntervalSets = "0.5, 0.6"
4242
LazyArrays = "0.22"
43-
LazyBandedMatrices = "0.7"
43+
LazyBandedMatrices = "0.7.14"
4444
QuasiArrays = "0.9"
4545
SpecialFunctions = "1.0, 2"
4646
julia = "1.7"
4747

4848
[extras]
49+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
4950
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
5051
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
5152
SemiseparableMatrices = "f8ebbe35-cbfb-4060-bf7f-b10e4670cf57"
5253
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
5354
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
5455

5556
[targets]
56-
test = ["Base64", "Test", "ForwardDiff", "SemiseparableMatrices", "StaticArrays"]
57+
test = ["Base64", "Test", "ForwardDiff", "SemiseparableMatrices", "StaticArrays", "Random"]

src/ClassicalOrthogonalPolynomials.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import QuasiArrays: cardinality, checkindex, QuasiAdjoint, QuasiTranspose, Inclu
3232
AbstractQuasiFill, _dot, _equals, QuasiArrayLayout, PolynomialLayout
3333

3434
import InfiniteArrays: OneToInf, InfAxes, Infinity, AbstractInfUnitRange, InfiniteCardinal, InfRanges
35-
import InfiniteLinearAlgebra: chop!, chop
35+
import InfiniteLinearAlgebra: chop!, chop, choplength, compatible_resize!
3636
import ContinuumArrays: Basis, Weight, basis, @simplify, Identity, AbstractAffineQuasiVector, ProjectionFactorization,
3737
inbounds_getindex, grid, plotgrid, transform_ldiv, TransformFactorization, QInfAxes, broadcastbasis, ExpansionLayout, basismap,
3838
AffineQuasiVector, AffineMap, WeightLayout, AbstractWeightedBasisLayout, WeightedBasisLayout, WeightedBasisLayouts, demap, AbstractBasisLayout, BasisLayout,
@@ -66,6 +66,7 @@ cardinality(::EuclideanDomain) = ℵ₁
6666
cardinality(::Union{DomainSets.RealNumbers,DomainSets.ComplexNumbers}) = ℵ₁
6767
cardinality(::Union{DomainSets.Integers,DomainSets.Rationals,DomainSets.NaturalNumbers}) = ℵ₀
6868

69+
include("standardchop.jl")
6970
include("adaptivetransform.jl")
7071

7172
const WeightedBasis{T, A<:AbstractQuasiVector, B<:Basis} = BroadcastQuasiMatrix{T,typeof(*),<:Tuple{A,B}}

src/adaptivetransform.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ padchop(cfs, tol, ax...) = pad(chop(cfs, tol), ax...)
1111
padchop!(cfs::PseudoBlockVector, tol, ax...) = padchop!(cfs.blocks, tol, ax...)
1212

1313

14+
padresize!(cfs, m, ax...) = pad(compatible_resize!(cfs, m), ax...)
15+
padresize!(cfs::PseudoBlockVector, m, ax...) = padresize!(cfs.blocks, m, ax...)
16+
17+
1418
increasingtruncations(::OneToInf) = oneto.(2 .^ (4:∞))
1519
increasingtruncations(::BlockedUnitRange) = broadcast(n -> Block.(oneto(n)), (2 .^ (4:∞)))
1620
function adaptivetransform_ldiv(A::AbstractQuasiArray{U}, f::AbstractQuasiVector{V}) where {U,V}
@@ -27,16 +31,18 @@ function adaptivetransform_ldiv(A::AbstractQuasiArray{U}, f::AbstractQuasiVector
2731
An = A[:,jr]
2832
cfs = An \ f
2933
maxabsc = maximum(abs, cfs)
30-
if maxabsc == 0 && maxabsfr == 0
34+
if maxabsc tol && maxabsfr tol # probably zero
3135
return pad(similar(cfs,0), ax)
3236
end
3337

3438
m = length(cfs)
35-
if maximum(abs,@views(cfs[max(1,m-2):m])) < 10tol*maxabsc
36-
n = length(cfs)
37-
c = padchop!(cfs, tol, ax)
39+
= standardchoplength(cfs, tol)
40+
41+
42+
if< m-1 # coefficient tail is "zero" based on standard chop
43+
c = padresize!(cfs, m̃, ax)
3844
un = A * c
39-
if all(norm.(un[r] - fr, 1) .< tol * n * maxabsfr*1000)
45+
if all(norm.(un[r] - fr, 1) .< m*tol*1000*max(maxabsfr, 1))
4046
return c
4147
end
4248
end

src/standardchop.jl

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Contains code that is based in part on Chebfun v5's chebfun/standardChop.m,
2+
# which is distributed with the following license:
3+
4+
# Copyright (c) 2017, The Chancellor, Masters and Scholars of the University
5+
# of Oxford, and the Chebfun Developers. All rights reserved.
6+
#
7+
# Redistribution and use in source and binary forms, with or without
8+
# modification, are permitted provided that the following conditions are met:
9+
# * Redistributions of source code must retain the above copyright
10+
# notice, this list of conditions and the following disclaimer.
11+
# * Redistributions in binary form must reproduce the above copyright
12+
# notice, this list of conditions and the following disclaimer in the
13+
# documentation and/or other materials provided with the distribution.
14+
# * Neither the name of the University of Oxford nor the names of its
15+
# contributors may be used to endorse or promote products derived from
16+
# this software without specific prior written permission.
17+
#
18+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
29+
# Jared Aurentz and Nick Trefethen, July 2015.
30+
#
31+
# Copyright 2017 by The University of Oxford and The Chebfun Developers.
32+
# See http://www.chebfun.org/ for Chebfun information.
33+
34+
function standardchoplength(coeffs, tol)
35+
# Check magnitude of TOL:
36+
if tol 1
37+
throw(ArgumentError("tolerance must be less than 1"))
38+
end
39+
40+
# Make sure COEFFS has length at least 17:
41+
n = length(coeffs)
42+
43+
if n < 17
44+
# resort to naive chop
45+
mx = maximum(abs,coeffs)
46+
return choplength(coeffs, tol*mx)
47+
end
48+
49+
# Step 1: Convert COEFFS to a new monotonically nonincreasing
50+
# vector ENVELOPE normalized to begin with the value 1.
51+
52+
b = convert(Vector, abs.(coeffs))
53+
for j = n-1:-1:1
54+
b[j] = max(b[j], b[j+1])
55+
end
56+
iszero(b[1]) && return 1
57+
58+
b .= b ./ b[1]
59+
60+
61+
plateauPoint = 0
62+
63+
for j = 2:n
64+
j2 = round(Int,1.25*j + 5);
65+
if j2 > n
66+
# there is no plateau: exit
67+
return n
68+
end
69+
e1 = b[j]
70+
e2 = b[j2]
71+
r = 3*(1 - log(e1)/log(tol))
72+
plateau = (e1 == 0) || (e2/e1 > r)
73+
if plateau
74+
# a plateau has been found: go to Step 3
75+
plateauPoint = j - 1
76+
break
77+
end
78+
end
79+
80+
# Step 3: fix CUTOFF at a point where ENVELOPE, plus a linear function
81+
# included to bias the result towards the left end, is minimal.
82+
#
83+
84+
if plateauPoint  0 && b[plateauPoint] == 0
85+
return plateauPoint
86+
end
87+
88+
j3 = sum(b .≥ tol^(7/6))
89+
if j3 < j2
90+
j2 = j3 + 1
91+
b[j2] = tol^(7/6)
92+
end
93+
cc = log10.(b[1:j2])
94+
cc .+= range(0, stop=(-1/3)*log10(tol), length=j2)
95+
d = argmin(cc)
96+
return max(d - 1, 1)
97+
end

test/runtests.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Base, ClassicalOrthogonalPolynomials, ContinuumArrays, QuasiArrays, FillArrays,
22
LazyArrays, BandedMatrices, LinearAlgebra, FastTransforms, IntervalSets,
3-
InfiniteLinearAlgebra, Test
3+
InfiniteLinearAlgebra, Random, Test
44
using ForwardDiff, SemiseparableMatrices, SpecialFunctions, LazyBandedMatrices
55
import ContinuumArrays: BasisLayout, MappedBasisLayout
66
import ClassicalOrthogonalPolynomials: jacobimatrix, ∞, ChebyshevInterval, LegendreWeight,
@@ -12,6 +12,8 @@ import ClassicalOrthogonalPolynomials: oneto
1212
import InfiniteLinearAlgebra: KronTrav, Block
1313
import FastTransforms: clenshaw!
1414

15+
Random.seed!(0)
16+
1517
@testset "singularities" begin
1618
x = Inclusion(ChebyshevInterval())
1719
@test singularities(x) == singularities(exp.(x)) == singularities(x.^2) ==

test/test_interlace.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using ClassicalOrthogonalPolynomials, BlockArrays, LazyBandedMatrices, FillArrays, ContinuumArrays, StaticArrays, Test
2-
import ClassicalOrthogonalPolynomials: PiecewiseInterlace, SetindexInterlace, plotgrid
2+
import ClassicalOrthogonalPolynomials: PiecewiseInterlace, SetindexInterlace, plotgrid, BroadcastQuasiVector
33

44
@testset "Interlace" begin
55
@testset "Piecewise" begin
@@ -152,5 +152,17 @@ import ClassicalOrthogonalPolynomials: PiecewiseInterlace, SetindexInterlace, pl
152152
U = V / V \ broadcast(x -> cos.((1:10) .* x), x)
153153
@test U[0.1] cos.((1:10) .* 0.1)
154154
end
155+
156+
@testset "zero" begin
157+
= [-1/4 1/4 1/2 1/2; 1/4 -1/4 1/2 1/2; 0 0 -1/4 1/4; 0 0 1/4 -1/4]
158+
= [1/4 1/4 -1/2 1/2; 1/4 1/4 1/2 -1/2; 0 0 1/4 1/4; 0 0 1/4 1/4]
159+
X = z ->/z +'*z
160+
Y = z ->/z +'*z
161+
F = Fourier{ComplexF64}()
162+
S = SetindexInterlace(SMatrix{4,4,ComplexF64},fill(F,4^2)...)
163+
θ = axes(S,1)
164+
XY = S \ BroadcastQuasiVector{eltype(S)}-> (I-X(exp(im*θ))^2)*(I-Y(exp(im*θ))^2), θ)
165+
@test iszero(norm(XY))
166+
end
155167
end
156168
end

test/test_legendre.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using ClassicalOrthogonalPolynomials, LazyArrays, QuasiArrays, BandedMatrices, ContinuumArrays, ForwardDiff, Test
2-
import ClassicalOrthogonalPolynomials: recurrencecoefficients, jacobimatrix, Clenshaw, weighted
2+
import ClassicalOrthogonalPolynomials: recurrencecoefficients, jacobimatrix, Clenshaw, weighted, oneto
33
import QuasiArrays: MulQuasiArray
44

55
@testset "Legendre" begin

test/test_stieltjes.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ end
310310

311311
@testset "inversion" begin
312312
= BlockHcat(Eye((axes(H,1),))[:,Block(1)], H)
313-
@test BlockArrays.blockcolsupport(H̃,1) == Block.(1:1)
314-
@test last(BlockArrays.blockcolsupport(H̃,2))  Block(30)
313+
@test BlockArrays.blockcolsupport(H̃,Block(1)) == Block.(1:1)
314+
@test last(BlockArrays.blockcolsupport(H̃,Block(2)))  Block(30)
315315

316316
UT = U \ T
317317
D = U \ Derivative(x) * T

0 commit comments

Comments
 (0)