Skip to main content

Automatic convergence detection for iterative numerical methods. Stop wasting compute.

Project description

Convergio

Automatic convergence detection for iterative numerical methods.

Stop wasting compute. One function call tells you if your solver has converged, is stalling, is oscillating, or is diverging.

"Your solver finished 3000 iterations ago."

Install

pip install convergio

Only dependency: NumPy.

Quick Start

Analyze a completed run

from convergio import detect

result = detect(my_residual_history)

print(result.state)        # "converged" | "stalling" | "oscillating" | "diverging" | ...
print(result.quality)      # 0.0 — 1.0
print(result.converged_at) # step where convergence was detected

Detect stalling (new in v0.1.3)

A solver can look "converged" (low variance) but actually be stuck above the target residual. Convergio distinguishes between true convergence and stalling:

result = detect(residuals, residual_target=1e-8)

if result.state == "stalling":
    print("Solver plateaued — try different parameters")
elif result.state == "converged":
    print(f"Solved at step {result.converged_at}")

Monitor a running simulation

from convergio import watch

mon = watch(var_threshold=1e-6, residual_target=1e-8)

for step in range(10000):
    residual = solver.step()
    stop, info = mon.step(residual)
    if stop:
        print(f"Done at step {step} — saved {10000 - step} iterations")
        break

What It Detects

State Meaning Recommendation
converged Signal has stabilized below target Stop
stalling Signal is flat but above target Adjust parameters
oscillating Signal oscillates periodically without settling Continue
noisy High zero-crossing rate but no periodicity (looks like noise) Continue
bistable Signal jumps between 2+ distinct states Investigate
diverging Variance is genuinely growing Restart
numerical_failure Signal contains NaN/Inf — run collapsed Restart
warming_up Not enough data yet Continue

Benchmark Results

Tested on synthetic signals across all convergence states (v0.1.4):

Detection Accuracy

Signal Type N=200 N=500 N=1000
Converging (exp. decay) converged converged converged
Stalling (flat, above target) stalling stalling stalling
Oscillating (sine + noise) oscillating oscillating
Diverging (random walk) diverging diverging

Overall: 87% correct across all signal types and lengths. Hardest case: bistable signals (multi-modal jumping), which can resemble oscillation.

Compute Savings with watch()

Scenario Budget Stopped at Saved
Fast convergence 2,000 1,100 45%
Medium convergence 5,000 4,200 16%
Diverging (early abort) 5,000 350 93%

watch() detects convergence and divergence. Diverging runs are killed early instead of burning through the full iteration budget.

Stalling signals are flagged but not auto-stopped — you decide what to do.

Speed

Signal Length Time Throughput
1,000 5 ms 200K pts/s
10,000 52 ms 190K pts/s
100,000 517 ms 193K pts/s
1,000,000 5.1 s 197K pts/s

detect() runs at ~190,000 points/second. For a typical FEM solver with 5,000 iterations, analysis takes ~25 ms — negligible compared to solve time.

API Reference

detect(signal, window=0, var_threshold=1e-6, osc_threshold=0.005, residual_target=0.0)

Analyze a complete time series.

Parameter Type Default Description
signal array-like 1D array of scalar values
window int 0 (auto) Analysis window size
var_threshold float 1e-6 Variance below this = stable
osc_threshold float 0.005 Min oscillation frequency (zero-crossings / 2N) to flag oscillation
residual_target float 0.0 If > 0: stable signal above this = stalling

Returns ConvergenceResult.

watch(var_threshold=1e-6, check_every=50, min_steps=100, window=0, residual_target=0.0, max_history=10000)

Create a live monitor. Returns Watch object. Call .step(value) each iteration. Memory is bounded by max_history.

Parameter Type Default Description
var_threshold float 1e-6 Variance below this = stable
check_every int 50 Check convergence every N steps
min_steps int 100 Minimum steps before first check
window int 0 (auto) Analysis window size
residual_target float 0.0 If > 0: stable signal above this = stalling
max_history int 10000 Keep at most this many recent values (bounds memory)

ConvergenceResult

Field Type Description
state str converged, stalling, oscillating, noisy, bistable, diverging, numerical_failure, warming_up
quality float 0.0 — 1.0 convergence quality
converged_at int or None Step where convergence detected
final_variance float Variance of last window
oscillation_freq float Detected oscillation frequency
n_modes int Number of distinct stable states
recommendation str stop, continue, restart, adjust_params
saved_steps int Steps saved by early stopping
total_steps int Total steps in analyzed signal
note str Optional hint (e.g. missing residual_target, numerical failure); empty if none

What's New

v0.2.1

  • Documentation: README now reflects the v0.2 states, parameters and note field.

v0.2.0 — audit-driven robustness pass

  • NaN/Inf no longer crash — new state numerical_failure instead of a ValueError.
  • Stationary noise is separated from periodic oscillation — new state noisy (autocorrelation check); noise is no longer mislabelled diverging.
  • osc_threshold is now actually used (it was inert); default rescaled to 0.005 (the documented zero-crossing frequency), behaviour-preserving.
  • count_modes over-counting fixed — a finite unimodal sample no longer produces spurious extra modes (valley-prominence merge).
  • rolling_variance now really uses cumulative sums (O(n)); previously a per-window Python loop despite the comment.
  • watch() bounds memory via max_history instead of re-analysing an unbounded history every check.
  • New note field — a stabilized signal with no residual_target that plateaus without dropping from its start now flags the missing target (state stays converged for backward compatibility).

v0.1.5

  • All 6 convergence states: converged, stalling, oscillating, diverging, bistable, warming_up
  • Improved trend-check robustness for near-convergent signals
  • Battle-tested in CAP Stability Engine v0.8 (15/16 SuiteSparse matrices solved)

v0.1.4

  • Trend-check: smooth decline is no longer misclassified as stalling

v0.1.3

  • residual_target parameter: distinguishes true convergence from stalling
  • stalling state: flat signal above target is now correctly identified
  • watch() reports stalling without auto-stopping (user decides)

v0.1.0

  • Initial release: converged, oscillating, bistable, diverging, warming_up

Works With

  • FEM / CFD solvers (residual monitoring)
  • ML training (loss convergence)
  • Monte Carlo simulations (running averages)
  • Optimization loops (objective function)
  • Molecular dynamics (energy equilibration)
  • Any iterative numerical process that produces a scalar time series

License

MIT

Author

Maximilian Jurak — 3 Kaiserberge Engineering & Research

max.jurak@3kaiserberge.com

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

convergio-0.2.1.tar.gz (15.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

convergio-0.2.1-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file convergio-0.2.1.tar.gz.

File metadata

  • Download URL: convergio-0.2.1.tar.gz
  • Upload date:
  • Size: 15.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for convergio-0.2.1.tar.gz
Algorithm Hash digest
SHA256 f04ab2bccfd86f2c3ce1614994df3aa2240ed090e043c8cc78b4bb28eea2b097
MD5 2899882fc158f985584d65307473d520
BLAKE2b-256 c00bc2b0dca1b46231a6d9d222b814ac239172cfbb6640a52bf15205610fc05f

See more details on using hashes here.

File details

Details for the file convergio-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: convergio-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for convergio-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5e824a3f2501d4840be9a24a695bd95717575d017c672920283972c507ab140b
MD5 a2604207cb3ca650454f0fe19ccfc07e
BLAKE2b-256 96222314feb98c5670290e0590e4761b224ca36c836822c1c159b172d010b229

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page