Skip to content

How to find simple pole expansion that maintains high acuracy? #21

@kbarros

Description

@kbarros

The script below builds a AAA approximation with very high accuracy. Great!

using LinearAlgebra
using RationalFunctionApproximation
import DoubleFloats: Double64
import ComplexRegions: Segment

f(x) = 1 / (1 + exp(1_000 * x))
bounds = (-10, 10)
segment = Segment{Double64}(bounds...)
# Large refinement and stagnation seem to be required. Are there heuristics
# to pick them or to otherwise mark the near-singular point at x=0?
r = approximate(f, segment, refinement=100, stagnation=100, tol=1e-10)

xs = range(bounds..., length=10_000)
norm(r.(xs) - f.(xs), Inf) # 5.9e-11

My ultimate goal is to find poles/residues for a simple pole expansion that maintains this high level of accuracy. Unfortunately, when I try to get that with residues(r) plus an inferred constant shift, there is significant degradation in accuracy (several orders of magnitude).

With the hope of recovering that lost accuracy, I tried building a continued fraction approximation using fixed poles. When f(x) is not too singular, the procedure can work well. However, in this example:

r0 = approximate(f, segment, poles(r), degree=0)
norm(r0.(xs) - f.(xs), Inf) # 1.2e4

r1 = approximate(f, segment, poles(r), degree=0, init=1_000)
norm(r1.(xs) - f.(xs), Inf) # 3.1e0

r2 = approximate(f, segment, poles(r), degree=0, init=10_000)
norm(r2.(xs) - f.(xs), Inf) # 1.0e-6

# ERROR: BoundsError: attempt to access 20000×4 Matrix{Double64} at index [20001, 1]
r3 = approximate(f, segment, poles(r), degree=0, init=50_000)

Here the error depends sensitively on the choice of init. The best I could achieve is order 1e-6, which is far worse than the 1e-10 achieved by AAA. Pushing the init value past a threshold generates a BoundsError.

Is there a way to get a simple pole expansion that keeps the high accuracy of the original barycentric approximation?

Another curious phenomenon is that if I rescale x as it appears in both f and bounds, I can get an overall much better approximation. Specifically, the alternative definitions,

(x) = 1 / (1 + exp(10_000 * x)) # Previously exp(1_000 * x)
bounds = (-1, 1) # Previously (-10, 10)

yield a significantly improved accuracy. Naively, I would have expected no mathematical difference under this rescaling.

Thanks in advance. This is a very nice package!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions