Analytic Continuation

The continuation module implements the later stages of the analytic continuation pipeline, including holomorphic checking, inversion, and composition operations.

Pipeline Overview

After Laurent map fitting (Stage 3), the pipeline continues with:

  • Stage 4: Check if the composition is holomorphic on an annulus

  • Stage 5: Compute the inverse mapping

  • Stage 6: Compute the composition and continuation grid

Pole Class

class analytic_continuation.Pole[source]

Bases: object

A pole of the meromorphic function f.

Parameters:
z: complex
multiplicity: int = 1
__init__(z, multiplicity=1)
Parameters:
Return type:

None

Represents a pole with location and residue information for analysis.

Holomorphic Checking (Stage 4)

Configuration

class analytic_continuation.HolomorphicCheckConfig[source]

Bases: object

Configuration for pole checking (Stage 4).

Parameters:
theta_grid: int = 2048
rho_samples: List[float]
pole_margin_factor: float = 1.0
shrink_steps: List[float]
classmethod from_pipeline_config(cfg)[source]
Parameters:

cfg (dict)

Return type:

HolomorphicCheckConfig

__init__(theta_grid=2048, rho_samples=<factory>, pole_margin_factor=1.0, shrink_steps=<factory>)
Parameters:
Return type:

None

Result

class analytic_continuation.HolomorphicCheckResult[source]

Bases: object

Result of checking if f is holomorphic on annulus image.

Parameters:
ok: bool
min_pole_distance: float
closest_pole: complex | None = None
failure_reason: str | None = None
updated_rho_in: float | None = None
updated_rho_out: float | None = None
__init__(ok, min_pole_distance, closest_pole=None, failure_reason=None, updated_rho_in=None, updated_rho_out=None)
Parameters:
Return type:

None

Main Function

analytic_continuation.check_f_holomorphic_on_annulus(poles, lmap, curve_scale, min_distance_param, cfg=None)[source]

Stage 4: Check that f’s poles are sufficiently far from the annulus image.

Parameters:
  • poles (List[Pole]) – The poles of the meromorphic function f

  • lmap (LaurentMapResult) – The fitted Laurent map

  • curve_scale (float) – The diameter of the curve (for scaling)

  • min_distance_param (float) – The minDistance parameter from SplineExport (for pole margin)

  • cfg (HolomorphicCheckConfig, optional) – Configuration

Return type:

HolomorphicCheckResult

Example usage:

from analytic_continuation import (
    check_f_holomorphic_on_annulus,
    HolomorphicCheckConfig,
)

config = HolomorphicCheckConfig(
    rho_in=0.5,
    rho_out=2.0,
    theta_samples=1024,
    tolerance=1e-8,
)

result = check_f_holomorphic_on_annulus(laurent_map, config)

if result.ok:
    print("Function is holomorphic on the annulus")
else:
    print(f"Check failed: {result.failure_reason}")

Inversion (Stage 5)

Configuration

class analytic_continuation.InvertConfig[source]

Bases: object

Configuration for map inversion (Stage 5).

Parameters:
theta_grid: int = 256
seed_radii: List[float]
max_iters: int = 40
tol_abs_factor: float = 1e-10
tol_rel_factor: float = 1e-10
damping: bool = True
max_backtracks: int = 12
classmethod from_pipeline_config(cfg)[source]
Parameters:

cfg (dict)

Return type:

InvertConfig

__init__(theta_grid=256, seed_radii=<factory>, max_iters=40, tol_abs_factor=1e-10, tol_rel_factor=1e-10, damping=True, max_backtracks=12)
Parameters:
Return type:

None

Result

class analytic_continuation.InvertResult[source]

Bases: object

Result of inverting z(ζ) = z_query.

Parameters:
converged: bool
zeta: complex | None = None
residual: float = inf
iters: int = 0
__init__(converged, zeta=None, residual=inf, iters=0)
Parameters:
Return type:

None

Main Function

analytic_continuation.invert_z(z_query, lmap, curve_scale, cfg=None)[source]

Stage 5: Invert z(ζ) = z_query using multi-start Newton iteration.

Parameters:
  • z_query (complex) – The point to invert

  • lmap (LaurentMapResult) – The Laurent map

  • curve_scale (float) – The diameter of the curve (for tolerance scaling)

  • cfg (InvertConfig, optional) – Configuration

Return type:

InvertResult

Computes the inverse of the Laurent map at a given target point:

from analytic_continuation import invert_z, InvertConfig

config = InvertConfig(
    max_iter=100,
    tol=1e-10,
    initial_guess=None,  # Use automatic guess
)

result = invert_z(laurent_map, target_z=1.5 + 0.5j, config=config)

if result.ok:
    print(f"Inverse found: zeta = {result.zeta}")
    print(f"Iterations: {result.iterations}")
else:
    print(f"Inversion failed: {result.failure_reason}")

Composition (Stage 6)

Result

class analytic_continuation.CompositionResult[source]

Bases: object

Result of computing the composition.

Parameters:
ok: bool
value: complex | None = None
zeta: complex | None = None
residual: float | None = None
N: int | None = None
failure_reason: str | None = None
__init__(ok, value=None, zeta=None, residual=None, N=None, failure_reason=None)
Parameters:
Return type:

None

Main Functions

analytic_continuation.compute_composition(z_query, f, lmap, curve_scale, invert_cfg=None)[source]

Stage 6: Compute A(f(B(z_query))) using the shared parameterization shortcut.

Because reflections A and B are defined via the shared parameter ζ:

B(z(ζ)) = z(1/conj(ζ)) A(w(ζ)) = w(1/conj(ζ)) where w(ζ) = f(z(ζ))

The composition simplifies:

A(f(B(z(ζ)))) = f(z(ζ))

So we just need to: 1. Invert z_query to find ζ 2. Return f(z(ζ)) = f(z_query) if ζ is on the unit circle

Parameters:
  • z_query (complex) – The query point

  • f (Callable[[complex], complex]) – The meromorphic function to evaluate

  • lmap (LaurentMapResult) – The Laurent map

  • curve_scale (float) – The diameter of the curve

  • invert_cfg (InvertConfig, optional) – Configuration for inversion

Return type:

CompositionResult

Compute the composition of functions for analytic continuation:

from analytic_continuation import compute_composition

result = compute_composition(
    laurent_map=lmap,
    f=lambda z: z**2 + 1,  # The function to continue
    zeta=np.exp(1j * theta),
)
analytic_continuation.compute_continuation_grid(f, lmap, curve_scale, x_range, y_range, resolution, invert_cfg=None)[source]

Compute the analytic continuation of f on a grid.

Returns both the computed values and a mask indicating which points converged.

Parameters:
  • f (Callable) – The meromorphic function

  • lmap (LaurentMapResult) – The Laurent map

  • curve_scale (float) – Curve diameter for tolerance scaling

  • x_range (Tuple[float, float]) – The range of the grid

  • y_range (Tuple[float, float]) – The range of the grid

  • resolution (int) – Number of grid points per axis

  • invert_cfg (InvertConfig, optional) – Inversion configuration

Return type:

Tuple[ndarray, ndarray]

Returns:

  • values (np.ndarray) – Complex array of shape (resolution, resolution) with computed values

  • converged (np.ndarray) – Boolean array indicating which points converged

Compute continuation values on a grid:

import numpy as np
from analytic_continuation import compute_continuation_grid

# Define a grid in the zeta plane
re = np.linspace(-2, 2, 100)
im = np.linspace(-2, 2, 100)
zeta_grid = re[:, None] + 1j * im[None, :]

# Compute continuation
continuation = compute_continuation_grid(
    laurent_map=lmap,
    f=lambda z: np.sin(z),
    zeta_grid=zeta_grid,
    mask_outside_annulus=True,
)

Workflow Example

Complete workflow for analytic continuation:

from analytic_continuation import (
    fit_laurent_map,
    check_f_holomorphic_on_annulus,
    invert_z,
    compute_continuation_grid,
    SplineExport,
    LaurentFitConfig,
    HolomorphicCheckConfig,
)
import numpy as np

# Stage 3: Fit Laurent map
export = SplineExport.from_json(curve_json)
fit_result = fit_laurent_map(export)

if not fit_result.ok:
    raise ValueError(f"Fitting failed: {fit_result.failure_reason}")

lmap = fit_result.laurent_map

# Stage 4: Check holomorphic
check_config = HolomorphicCheckConfig(rho_in=0.5, rho_out=2.0)
check_result = check_f_holomorphic_on_annulus(lmap, check_config)

if not check_result.ok:
    raise ValueError(f"Holomorphic check failed: {check_result.failure_reason}")

# Stage 6: Compute continuation grid
re = np.linspace(-3, 3, 200)
im = np.linspace(-3, 3, 200)
zeta_grid = re[:, None] + 1j * im[None, :]

continuation = compute_continuation_grid(
    laurent_map=lmap,
    f=lambda z: 1 / (z**2 + 1),
    zeta_grid=zeta_grid,
)

# The result can be visualized using domain coloring