Skip to content

feat: introduce Differential operator and deprecate D#27

Open
s-celles wants to merge 4 commits into
mainfrom
068-multivar-d-operator
Open

feat: introduce Differential operator and deprecate D#27
s-celles wants to merge 4 commits into
mainfrom
068-multivar-d-operator

Conversation

@s-celles
Copy link
Copy Markdown
Owner

  • 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-commenter
Copy link
Copy Markdown

codecov-commenter commented May 10, 2026

Codecov Report

❌ Patch coverage is 95.65217% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.46%. Comparing base (681f1ad) to head (bb86bb5).

Files with missing lines Patch % Lines
src/types.jl 94.18% 5 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@s-celles
Copy link
Copy Markdown
Owner Author

@tduretz @jverzani, feel free to comment.

I'll leave this PR open for at least a week to gather feedback, as it's causing a compatibility issue.

@jverzani
Copy link
Copy Markdown
Contributor

@s-celles Seems like a good change to me. SymPy has both diff and Differential following the sympy name and the Symbolics one. (There are a few naming conventions of Symbolics that aren't to my taste---not this one---but keeping consistency where possible is a good idea in my opinion)

@s-celles s-celles changed the title feat: introduce Differential operator and deprecate D (spec 068) feat: introduce Differential operator and deprecate D May 11, 2026
s-celles and others added 3 commits May 18, 2026 14:17
…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.
@tduretz
Copy link
Copy Markdown

tduretz commented May 20, 2026

Same as @jverzani, this is likely a good change, as it aligns better with other tools. Another possibility could maybe be to keep both D() and Differential() (so making D () an alias for Differential()) for those who like short func names, but D should likely not be the default style as it's not super explicit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants