Skip to content

feat: introduce Differential operator and deprecate D - #27

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

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

Conversation

@s-celles

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

codecov-commenter commented May 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.65217% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.23%. Comparing base (ba6d30a) to head (d7298a1).

Files with missing lines Patch % Lines
src/types.jl 94.18% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #27      +/-   ##
==========================================
+ Coverage   80.64%   81.23%   +0.58%     
==========================================
  Files          24       25       +1     
  Lines        3018     3112      +94     
==========================================
+ Hits         2434     2528      +94     
  Misses        584      584              

☔ View full report in Codecov by Harness.
📢 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
Collaborator 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

tduretz commented May 20, 2026

Copy link
Copy Markdown

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.

Two conflicts, both structural rather than semantic.

docs/make.jl: main restructured the page list into a `_pages` variable
while this branch still edited the inline `pages = [...]`. Took main's
file and re-applied this branch's only change to it — the Migration
section pointing at docs/src/migration/d_to_differential.md, which is
present. Syntax checked.

CHANGELOG.md: the conflict hunk spanned past [Unreleased] into the
published 0.14.2 block, so a naive resolution would have filed this
branch's entries under a released version. Kept everything inside
[Unreleased] and consolidated it: main and this branch each carried
several sections of the same name, giving duplicate ### Added and
### Fixed headers. Now one section per type in Keep a Changelog order —
Added, Changed, Deprecated, Fixed — with all 20 entries preserved
(asserted by count, not by eye).

Brings in the LibPARI bridge, TermInterface head/children, the STRNG
conversion fix, CompatHelper/Dependabot/downgrade CI, macOS aarch64 and
the four action bumps.
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