feat: introduce Differential operator and deprecate D#27
Conversation
s-celles
commented
May 10, 2026
- Add Giac.Differential, the canonical SciML/MTK-style partial-differentiation operator. Differential(var)(operand) accepts function-form expressions (returns DerivativeExpr) and bare GiacExpr operands (returns plain GiacExpr via Commands.diff), matching SymPy.jl's diff(expr, var) and Symbolics.jl's Differential. Two-argument shorthand Differential(var, n) matches Symbolics' Differential(x, 2).
- Widen DerivativeExpr internally to steps::Vector{Tuple{String, Int}}. Adjacent same-variable steps collapse, mixed variables compose freely so cross/higher-order partials work uniformly.
- Deprecate D: every D(...) call shape now emits Base.depwarn pointing to Differential. Multi-arg D(f) on a function f(x, y) raises ArgumentError instead of silently picking the first variable. D removal scheduled for the next published release.
- Display: derivative orders >= 4 render as f^(n)(x) rather than long prime strings; DerivativePoint string output keeps prime form (GIAC consumes it in initial conditions).
- Docs: new migration guide (docs/src/migration/d_to_differential.md); Differential coverage in mathematics/calculus.md; ODE doc rewritten to lead with Differential; new Pluto notebook examples/07_odes_pdes.jl with worked symbolic ODE/PDE walkthroughs; CHANGELOG [Unreleased] entries under Added / Deprecated / Changed.
- Tests: 9078 passing under Pkg.test() (+91 over baseline), zero failing regressions. Doc build clean.
- Add Giac.Differential, the canonical SciML/MTK-style partial-differentiation
operator. Differential(var)(operand) accepts function-form expressions
(returns DerivativeExpr) and bare GiacExpr operands (returns plain GiacExpr
via Commands.diff), matching SymPy.jl's diff(expr, var) and Symbolics.jl's
Differential. Two-argument shorthand Differential(var, n) matches
Symbolics' Differential(x, 2).
- Widen DerivativeExpr internally to steps::Vector{Tuple{String, Int}}.
Adjacent same-variable steps collapse, mixed variables compose freely so
cross/higher-order partials work uniformly.
- Deprecate D: every D(...) call shape now emits Base.depwarn pointing to
Differential. Multi-arg D(f) on a function f(x, y) raises ArgumentError
instead of silently picking the first variable. D removal scheduled for
the next published release.
- Display: derivative orders >= 4 render as f^(n)(x) rather than long prime
strings; DerivativePoint string output keeps prime form (GIAC consumes it
in initial conditions).
- Docs: new migration guide (docs/src/migration/d_to_differential.md);
Differential coverage in mathematics/calculus.md; ODE doc rewritten to
lead with Differential; new Pluto notebook examples/07_odes_pdes.jl with
worked symbolic ODE/PDE walkthroughs; CHANGELOG [Unreleased] entries
under Added / Deprecated / Changed.
- Tests: 9078 passing under Pkg.test() (+91 over baseline), zero failing
regressions. Doc build clean.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #27 +/- ##
==========================================
+ Coverage 79.76% 80.46% +0.70%
==========================================
Files 23 24 +1
Lines 2891 2985 +94
==========================================
+ Hits 2306 2402 +96
+ Misses 585 583 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@s-celles Seems like a good change to me. SymPy has both |
…ive display
Multi-step `Base.show` on `DerivativeExpr` previously rendered
`Differential(y)(Differential(x)(f))` as `D: ∂²f/∂x∂y`, which matches the
index/`f_{xy}` convention but conflicts with the operator-product reading
`(∂/∂y)(∂/∂x)f = ∂²f/∂y∂x`. The two conventions are equivalent in value
(Schwarz/Clairaut) but the notational mismatch made the displayed form
look inverted relative to the application order.
Adopt the right-to-left Leibniz convention everywhere user-facing: in
`∂ⁿf/∂v₁…∂vₙ` the rightmost variable is applied first, the leftmost
last. So `Differential(y)(Differential(x)(f))` (apply x first, then y)
now prints as `D: ∂²f/∂y∂x`. The internal `steps` field (innermost-first)
and the GIAC-side `diff(diff(f,x),y)` string are unchanged.
Updates:
- `Base.show(::DerivativeExpr)` iterates `steps` in reverse for the
denominator
- docstrings in `src/differential.jl` and `docs/src/mathematics/calculus.md`
call out the convention explicitly under a new "Notation" section
- migration guide updated; existing `test/test_types.jl` assertions
updated to match the new output; new `test/test_differential.jl`
testset locks the convention with 2- and 3-variable composition cases
- CHANGELOG documents the notation flip under Fixed.
…ives` Round out the `Differential` operator surface to match Symbolics.jl so code written for one runs on the other without rewrites. Operators on `Differential`: - `Differential(t)^n` for `n ≥ 0` — `Differential(t)^2 === Differential(t, 2)` and `Differential(t)^0 === identity`. Negative powers throw `ArgumentError` (anti-derivatives need an explicit constant). - `Differential(y) * Differential(x)` — composition, defined as `Differential(y) ∘ Differential(x)`. Julia's generic `∘` already does the right thing on callables; the explicit `*` method gives uniform delegation and cleaner stack traces. `expand_derivatives`: - `expand_derivatives(d::DerivativeExpr)` forces evaluation by delegating to GIAC's `diff` and returns a plain `GiacExpr`. - `expand_derivatives(x)` is the identity on anything else — so `expand_derivatives(Differential(x)(expr))` written in the Symbolics style runs unchanged on Giac.jl, where the bare-expression branch already evaluates eagerly. Tests cover `^` (n = 0, 1, 2, 3 and same-variable collapse via the existing `_append_step`), `*` and `∘` (cross and same-variable cases), and `expand_derivatives` on `GiacExpr` (identity) and `DerivativeExpr` (forced evaluation, asserting on type + `diff(...)` content rather than exact string since GIAC may renormalize `diff(f(x,y),x)` to its internal `diff(f,0)(x,y)` operator-then-evaluate form). Docs + CHANGELOG updated under Added.
|
Same as @jverzani, this is likely a good change, as it aligns better with other tools. Another possibility could maybe be to keep both |