ddx-core 0.2.1

Engine-neutral symbolic differentiation of SQL scalar expressions: `grad` & `jvp`.
Documentation
# ddx-core

Engine-neutral symbolic differentiation of SQL scalar expressions — the v1
core of [`ddx`](https://github.com/xqlsystems/ddx), "autograd for composable
databases." Write calculus directly in SQL and let the engine evaluate the
derivative per row (the relational equivalent of `jax.vmap(jax.grad(f))`):

```sql
SELECT i, grad(x * y, x) AS dfdx, grad(x * y, y) AS dfdy FROM g
```

`grad`/`jvp` are **markers**, not row functions: they carry a differentiation
request through parsing and are always rewritten away *before* execution.

```rust
use ddx_core::Ddx;
use ddx_core::sqlparser::dialect::GenericDialect;

let ddx = Ddx::new();
let out = ddx.rewrite_sql("SELECT grad(sin(x), x) AS d FROM t", &GenericDialect {})?;
assert_eq!(out, "SELECT (cos(x)) AS d FROM t");
```

The engine differentiates [`sqlparser::ast::Expr`](https://docs.rs/sqlparser)
directly — the AST *is* the IR, there is no bespoke representation. The primary 
dependency is `sqlparser`, **re-exported** as `ddx_core::sqlparser`
so downstream adapters cannot link a mismatched version.

## What it supports

`+ - * /`; the unary chain rule for the trig / inverse-trig / exp / log /
hyperbolic set plus `abs`; `power` with a constant base or exponent;
higher-order via nesting; through-aggregate via linearity
(`AVG(grad(loss, theta))`). Custom unary rules are registrable
(`ddx.register("myfn", rule)` — the rule supplies `f'(u)`, the engine applies
the chain rule). Anything else is a typed `DiffError`, never a silently-wrong
number.

Scalar `vjp` is deliberately **not** here: the name is reserved for the
query-level reverse-mode operation in `ddx-ad` (design.md §3.6, §4).

## Correctness properties worth knowing

- **Identifier folding is per-dialect** (`Ddx::for_datafusion()` vs
  `Ddx::for_duckdb()`): unquoted identifiers always fold case; DuckDB folds
  quoted ones too. `grad(Temp*Temp, temp)` matches.
- **Ambiguity is a hard error, not a guess**: a `wrt` that can't be pinned
  syntactically (`grad(a.x*b.x, x)`) errors rather than differentiating the
  wrong column.
- **`div` forces floating-point division** (`CAST(<numerator> AS DOUBLE)`), so
  integer columns don't silently truncate the derivative.
- **0/1-folding follows JAX's `Zero`-tangent convention** and differs from
  unfolded SQL only on NULL-bearing rows (documented, tested).

See [`../../docs/design.md`](../../docs/design.md) §3 for the full rationale and
the decision log (`F#`/`G#`) behind each of these.

## Status

M0 (the scalar core) — implemented. The per-engine adapters (`ddx-datafusion`,
`ddx-duckdb`), the Python wheel (`ddxdb`), and the query-level v2 engine
(`ddx-ad`) are later milestones; see the design doc's §8.

Licensed under Apache-2.0.