Skip to main content

Exact limit computation for Python functions. Resolve singularities algebraically.

Project description

composite-resolve

Evaluate Python functions at points where they're undefined.

The library where you pass a plain numeric Python function and get exact limits via algebraic infinitesimal arithmetic, with provenance tracking. To my knowledge, this is the first library that does this directly on plain Python functions.

Eliminates edge-case handling and numerical instability at singularities, just write the function and evaluate it everywhere.

import math
from composite_resolve import safe

@safe
def sinc(x):
    return math.sin(x) / x

sinc(0.5)  # → 0.9589 (normal computation)
sinc(0)    # → 1.0 (singularity resolved)

Uses composite arithmetic to resolve singularities algebraically. Works with any callable that uses standard Python arithmetic and math module functions. No symbolic expressions, no approximation. Pure Python, zero dependencies.

Install

pip install composite-resolve

The @safe Decorator

Write your math as-is. The decorator handles singularities automatically:

import math
from composite_resolve import safe

@safe
def f(x):
    return (x**2 - 1) / (x - 1)

f(3)   # → 4.0 (normal)
f(1)   # → 2.0 (resolved — no ZeroDivisionError)

@safe
def entropy(p):
    return -p * math.log(p)

entropy(0.5)  # → 0.347 (normal)
entropy(0)    # → 0.0 (resolved — no ValueError)

Normal inputs run the original function directly with zero overhead. Only when the function fails (ZeroDivisionError, NaN, Inf) does the resolver kick in.

Direct API

For more control, use resolve, limit, and classify directly:

import math
from composite_resolve import resolve, limit, classify, taylor

# Evaluate at removable singularities
resolve(lambda x: math.sin(x) / x, at=0)                # → 1.0
resolve(lambda x: (math.exp(x) - 1) / x, at=0)          # → 1.0
resolve(lambda x: (x**2 - 1) / (x - 1), at=1)           # → 2.0

# Indeterminate forms
limit(lambda x: x * math.log(x), to=0, dir="+")          # → 0.0    (0 * inf)
limit(lambda x: x**x, to=0, dir="+")                      # → 1.0    (0^0)
limit(lambda x: (1 + x)**(1/x), to=0)                     # → e      (1^inf)
limit(lambda x: 1/x - 1/math.sin(x), to=0)                # → 0.0    (inf - inf)

# Limits at infinity
limit(lambda x: (1 + 1/x)**x, to=math.inf)                # → e
limit(lambda x: math.sin(x) / x, to=math.inf)              # → 0.0

# One-sided limits
limit(lambda x: 1/x, to=0, dir="+")   # raises LimitDivergesError (+inf)
limit(lambda x: 1/x, to=0, dir="-")   # raises LimitDivergesError (-inf)
limit(lambda x: 1/x, to=0)            # raises LimitDoesNotExistError

# Singularity classification
classify(lambda x: math.sin(x)/x, at=0)   # → Removable(value=1.0)
classify(lambda x: 1/x, at=0)             # → Pole(order=1, residue=1.0)
classify(lambda x: math.exp(x), at=0)     # → Regular(value=1.0)

# Taylor coefficients
taylor(lambda x: math.exp(x), at=0, order=4)
# → [1.0, 1.0, 0.5, 0.16667, 0.04167]

How It Works

The library evaluates functions using composite arithmetic. Instead of symbolic manipulation, the library substitutes a concrete algebraic infinitesimal into your function. The result carries enough structure to resolve 0/0, 0×∞, and all other indeterminate forms through ordinary arithmetic.

The function is treated as a black box. No expression tree, no symbolic manipulation.

API

safe(f) -> wrapped function

Decorator. Normal inputs run f directly. Singularities are resolved automatically.

resolve(f, at, dir="both", truncation=20) -> float

Evaluate f at a point where it would normally fail. Returns math.inf or -math.inf for divergent limits.

limit(f, to, dir="both", truncation=20) -> float

Compute the limit of f(x) as x -> to. Raises LimitDivergesError for infinite limits, LimitDoesNotExistError when the limit doesn't exist.

evaluate(f, at) -> float

Strict: only returns a value if the singularity is removable. Raises SingularityError otherwise.

taylor(f, at=0, order=10) -> list[float]

Extract Taylor coefficients [f(a), f'(a)/1!, f''(a)/2!, ...].

classify(f, at=0, dir="both") -> SingularityType

Returns Regular, Removable, Pole, or Essential.

residue(f, at=0) -> float

Residue at a pole.

Examples

# Evaluate a function across its full domain, including singularities
from composite_resolve import resolve

f = lambda x: (x**2 - 1) / (x - 1)
for x in range(-5, 6):
    print(f"x={x:>2d}  f(x)={resolve(f, at=x):.1f}")
# x=1 gives 2.0 — no special case needed
# Cross-entropy loss at boundary
resolve(lambda p: -(0*math.log(p) + 1*math.log(1-p)), at=0, dir="+")  # → 0.0

# Continuous compounding
limit(lambda n: (1 + 0.05/n)**n, to=math.inf)  # → 1.05127

Math Library Support

Functions can use math, numpy, or composite_resolve.math — all work transparently:

import math
import numpy as np
from composite_resolve import safe

@safe
def f(x):
    return math.sin(x) / x    # works

@safe
def g(x):
    return np.sin(x) / x      # also works

f(0)  # → 1.0
g(0)  # → 1.0

math functions are patched during resolution. numpy functions dispatch via __array_ufunc__.

Important: use import math not from math import sin. The from form captures the original function at import time — patching the module later doesn't reach it. See limitations for details.

Limitations

  • Single-variable functions only
  • Use import math not from math import sin — the from form captures the original function, patching can't reach it
  • Functions must use math or numpy transcendentals (not jax, torch, etc.)
  • Not thread-safe during limit()/resolve()/@safe calls
  • Float-precision evaluation points (e.g., math.pi/2 is not exactly pi/2)

Some edge cases might still not be covered. Needs community scrutiny on evaluting the results.

License

AGPL-3.0. Commercial licensing available: tmilovan@fwd.hr

Author

Toni Milovan — tmilovan@fwd.hr

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

composite_resolve-0.1.3.tar.gz (53.6 kB view details)

Uploaded Source

Built Distribution

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

composite_resolve-0.1.3-py3-none-any.whl (63.3 kB view details)

Uploaded Python 3

File details

Details for the file composite_resolve-0.1.3.tar.gz.

File metadata

  • Download URL: composite_resolve-0.1.3.tar.gz
  • Upload date:
  • Size: 53.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for composite_resolve-0.1.3.tar.gz
Algorithm Hash digest
SHA256 b9d046cccb9dc0074f14fdd67636ddc341f58c6458bf06de3fbd9dc13f927847
MD5 94ddb18c2e72181a7494d262012b810f
BLAKE2b-256 2f338b7036472121ef0a56f8c131c4f85f40a45bb4ec51d87515b30867c39113

See more details on using hashes here.

File details

Details for the file composite_resolve-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for composite_resolve-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 971333cd80550a544ff7071e2e151dd47c3ffe0c3cbf1618e8f38206a612fead
MD5 d040168398b4ca974317c8fe8a68a44c
BLAKE2b-256 d7b4b27faa5006bf3fa6ea70cd5da312f86f2ed30916197525a8811373aca8bc

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