Catalog PyPI
PACKAGE EXPLORERView in registry

aadc

PyPI

Accelerate numerical Python by recording and compiling it — with optional exact derivatives (AAD)

aadadjointalgorithmic-differentiationautomatic-differentiationderivativesgradientsgreeksjitquantitative-financerisk
Versions collected1
Direct dependencies2From release 2.22.2
Last observed20 Oct, 16:51 UTC

README

Version 2.22.2 documentation

aadc

Run the same numerical code many times, much faster.

AADC records your calculation once — as you already wrote it, in ordinary Python arithmetic — and turns that recording into machine code. Replaying it skips the interpreter entirely, and replays several scenarios at once on the CPU's vector units.

import aadc

f = aadc.Functions()
f.start_recording()
x  = aadc.idouble(1.0);  xa = x.mark_as_input()
y  = my_pricer(x)                  # your existing code, unchanged
ya = y.mark_as_output()
f.stop_recording()

f.compile("scalar")                     # -> machine code, once
ws = f.create_workspace(kind="scalar")  # a workspace those kernels run on
ws.set_val(xa, 1.5)
ws.forward()                            # compiled replay: ws.val(ya)
ws.set_diff(ya, 1.0)
ws.reverse()                            # ws.diff(xa) = dy/dx at x = 1.5

compile() with no argument is the same as compile("scalar"): the same script runs compiled on x86-64, Apple Silicon and Linux AArch64 alike, and create_workspace() / aadc.evaluate() with no workspace argument use the workspace those kernels run on. compile("auto") compiles for the host's vector lanes instead (AVX2 on x86-64, NEON on Apple Silicon) — use it for batches: aadc.evaluate() after compile("auto") replays several scenarios per instruction, typically 3-4x faster than after plain compile(). Choose the backend at the FIRST compile() of a recording: a later call with another backend does not replace kernels already installed.

From then on every replay runs compiled. Typical speedups are several times the interpreted path — about 4x on one customer's FX pricer — and more when you replay a batch of scenarios, because the vector backends evaluate four (AVX2) or eight (AVX-512) at a time.

Where to look first

import aadc
help(aadc)                 # the three ideas, and a quickstart that runs
aadc.llms_txt()            # the same, written for a coding agent

dir(aadc) is the declared API (aadc.__all__), and every headline type carries a docstring — help(aadc.Functions), help(aadc.idouble), help(aadc.Workspace).

The one trap. if x > k: on an active value forces a plain bool, which freezes that comparison as it came out while recording — a later replay with different inputs still follows the recorded branch. Use aadc.iif(x > k, a, b) when the condition depends on an input. Every such conversion is counted, so this is detectable rather than silent:

kernel.num_passive_warnings()      # 0 is the goal
kernel.passive_warnings()          # kind and location of each

Derivatives are optional. If you want them, the same recording gives you exact first-order sensitivities of every output with respect to every input — no bumping, no re-running the pricer per input, and exact rather than finite-difference approximations. If you do not want them, AADC is simply a compiler for the hot loop you already have.

That is the whole idea: record once, replay compiled — and take the derivatives if they are useful to you.

Install

pip install aadc

Supports CPython 3.10 and later. One abi3 wheel serves every CPython >= 3.11 on a given platform (the extension is built against the CPython Limited API); 3.10 is served by its own version-specific wheel.

Supported platforms

Binary wheels only — there is no source distribution, so pip install aadc on anything not listed here fails with no matching distribution rather than attempting a build.

CPython 3.10 – 3.14
Linux x86-64 (manylinux_2_28)yes
Linux aarch64 (manylinux_2_28)yes
macOS arm64 (Apple Silicon, 11.0+)yes
Windows x64yes
macOS x86-64 (Intel)no
Alpine / muslno
32-bit Windowsno

The macOS wheels are Apple Silicon only. An Intel Mac gets no matching distribution — the Operating System :: MacOS classifier is as specific as PyPI allows, so this table is the authority, not the sidebar.

The Linux wheels need glibc 2.28 or newer; the shipped library's own floor is lower (it references no symbol above GLIBC 2.14 / GLIBCXX 3.4.22), so the tag is the binding constraint rather than the binary.

Upgrading from aadc 1.x

2.x is a different engine, not a compatible successor. The 1.x line ended at 1.8.2; 2.x is a ground-up rewrite with its own recording API, and code written against 1.x will not run unchanged. Notably aadc.license() no longer exists — entitlement is resolved from the environment instead (see Licence in one paragraph below).

If you depend on the 1.x behaviour, pin it explicitly:

pip install 'aadc<2'

Migrating is a port rather than an upgrade. Start from Where to look first above; the recording shape — start_recording(), mark_as_input(), mark_as_output(), a workspace per evaluation — is what changed most.

Version 2.2.0 renames the distribution from aadc-ng to aadc, continuing the PyPI aadc 1.x line. The import (import aadc) and every binary name (_aadc_ng, the aadc_ng runtime package, libaadc-ng) are unchanged.

Upgrading from an environment that has aadc-ng installed: uninstall it FIRST (pip uninstall -y aadc-ng), then pip install aadc. pip treats the two as unrelated distributions that own the same files, so installing aadc over aadc-ng works — but a later pip uninstall aadc-ng would then delete the files out from under aadc, leaving an install whose metadata says it is fine and whose import aadc fails.

Licence in one paragraph

Proprietary. The free Community Edition covers non-commercial and academic use only — personal study, hobby projects, publicly available open-source development, and research or teaching at a university or recognised research institute. Everything else is Production Use and needs a commercial licence, including evaluation by a company and any calculation whose output reaches a book, a client report or a regulator.

The Community Edition is fast. On x86-64 with AVX2, and on Apple Silicon, it runs the interpreter and every JIT backend at full speed, and compile() selects a JIT by default — so on those hosts the ordinary path needs no licence and no C compiler on the box. Two hosts are the exception: on non-Apple 64-bit ARM the vector backends compile() picks there need a licence with the arm64 feature, and on pre-AVX2 x86-64 there is no scalar JIT, so compile('scalar') falls back to the C emitter and needs codegen_c. Both report the feature they want, and neither changes your numbers.

What a licence adds is the ahead-of-time code generators (which write a translation unit you keep, inspect and ship), AVX-512 in any form, and double-precision GPU.

Ask for a licensed backend without the licence and those segments replay on the interpreter: identical results, more slowly, with the reason reported in compile()'s unavailable field. Nothing expires and nothing contacts a server. Every numerical answer is the same in every tier — the licence buys speed, never correctness.

Full terms ship inside the wheel at <site-packages>/aadc-<version>.dist-info/licenses/LICENSE.txt, with THIRD-PARTY-NOTICES.txt beside it. Commercial and free full-performance academic licences: info@matlogica.com.

Which version am I running?

Two version strings, because there are two things to version:

import aadc

aadc.__version__          # e.g. '2.9.2' -- the WHEEL you pip-installed
aadc.__engine_version__   # e.g. '2.9.0' -- the aadc-ng C++ engine inside it

__version__ is the distribution version, identical to importlib.metadata.version("aadc") and to what pip freeze reports. __engine_version__ is the version of the compiled aadc-ng engine the wheel carries, recorded at build time from the SDK.

They are allowed to differ, and comparing them is not a health check: a Python-only fix ships a new wheel against an unchanged engine. Record __version__ next to your risk numbers and __engine_version__ when you need to say which arithmetic produced them. Both are also available as aadc_ng.__version__ / aadc_ng.__engine_version__.

For what the loaded library says about itself — a third, independent source — use aadc.license_status()["build_version"]; disagreeing with __engine_version__ means the wheel is carrying a different image than its metadata claims.

Check your entitlement in your own CI

import aadc

s = aadc.license_status()
assert s["state"] == "licensed", s["detail"]

state is unlicensed, licensed or expired. expired means the token is genuine but this build is newer than its version ceiling — the entitlement is to older builds, which keep running at full speed. Compare version_max against build_version to see the gap.

Token location, in order: $AADC_NG_LICENSE, ./aadc-ng.lic, ~/.aadc-ng/license.

One shared library per process

libaadc-ng carries thread-local recording state, so a second copy in one process gives correct values and silently zero gradients. This wheel is the only one that ships it; anything else linking it must resolve it by RPATH. Assert it:

import aadc_ng
aadc_ng.check_single_image()   # raises if more than one is mapped

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
2.22.229 Sept 20262

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 16:51 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:5bdeaad3edf85c26423ac58b5d09ead64f8b952dde2c6350cb10c3e6d1a51d39