devito icon indicating copy to clipboard operation
devito copied to clipboard

dsl: Expand derivative

Open JDBetteridge opened this issue 9 months ago • 3 comments

I want to be able to manipulate Devito derivative objects, more like sympy derivative objects.

(possibly only optionally)

JDBetteridge avatar Mar 28 '25 15:03 JDBetteridge

Codecov Report

:x: Patch coverage is 89.58333% with 30 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 91.31%. Comparing base (e1fefb2) to head (1268740). :warning: Report is 35 commits behind head on main.

Files with missing lines Patch % Lines
devito/finite_differences/derivative.py 85.00% 11 Missing and 7 partials :warning:
devito/mpatches/as_independent.py 75.51% 7 Missing and 5 partials :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2559      +/-   ##
==========================================
- Coverage   92.01%   91.31%   -0.71%     
==========================================
  Files         247      248       +1     
  Lines       49158    49387     +229     
  Branches     4325     4355      +30     
==========================================
- Hits        45234    45096     -138     
- Misses       3221     3559     +338     
- Partials      703      732      +29     
Flag Coverage Δ
pytest-gpu-aomp-amdgpuX 72.37% <49.70%> (-0.12%) :arrow_down:
pytest-gpu-nvc-nvidiaX ?

Flags with carried forward coverage won't be shown. Click here to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

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

codecov[bot] avatar Mar 28 '25 15:03 codecov[bot]

Do you have some MFE (minimal failing example) of where this is popping up?

mloubout avatar Mar 30 '25 12:03 mloubout

Here is a wonderful list of failing examples that this PR now addresses:

import devito as dv
import sympy as sym

grid = dv.Grid(shape=(11,), extent=(1,))
x = grid.dimensions[0]

u = dv.Function(name='u', grid=grid, space_order=4)

a = u.dx
b = a.subs({u: -5*u.dx + 4*u + 3})

# Substitution works!
print(b)

# Unintuitive results:

# .as_independent method on devito.finite_differences.differentiable.Mul doesn't work
print((-a).as_independent(x))
# Result:
## (1, -Derivative(u(x), x))

# devito.Derivatives aren't reconstructable from func and args (as per sympy docs)
du = u.dx
print(du.func(*du.args))
print(du.func(*du.args).args)
# Result
## Derivative(u(x), (x, 1))
## (u(x), ((x, 1), 1))

# default simplification causes different results:
du11 = dv.Derivative(u, x, x)
print(du11)
print(du11.deriv_order)
# Result
## Derivative(u(x), (x, 2))
## (1, 1)
du2 = dv.Derivative(u, (x, 2))
print(du2)
print(du2.deriv_order)
# Result
## Derivative(u(x), (x, 2))
## (2,)

# Whut!?
print(dv.Derivative(u, x, deriv_order=(2,4)))
# Result
## Derivative(u(x), (x, 2))

# Also pretty wild
print(dv.Derivative(u, (x, 0)))
# Result
## Derivative(u(x), x)

# Really? Double check this...
print(dv.Derivative(-1))
# Result
## Traceback (most recent call last):
##   File "<stdin>", line 1, in <module>
##   File "/media/devito/devito_py312/src/devito/devito/finite_differences/derivative.py", line 98, in __new__
##     raise ValueError("`expr` must be a Differentiable object")
## ValueError: `expr` must be a Differentiable object

# Maybe it's sufficient to handle the case:
print(dv.Derivative(sym.sympify(-1)))

# Cannot expand
print(b.expand())
# Result
## ...
## RecursionError: maximum recursion depth exceeded

JDBetteridge avatar May 02 '25 17:05 JDBetteridge

The missing functionality in Sympy is now addressed in the following PR:

https://github.com/sympy/sympy/pull/28248

JDBetteridge avatar Jul 16 '25 15:07 JDBetteridge

The missing functionality in Sympy is now addressed in the following PR:

sympy/sympy#28248

This has been merged

JDBetteridge avatar Jul 22 '25 11:07 JDBetteridge

Results of profiling:

See all resources in the compressed folder

$ ./profiling_demo.sh | tee output.txt
Switched to branch 'worktree_py312'
Your branch is up to date with 'main'.
Operator `Kernel` generated in 13.10 s
  * lowering.Clusters: 8.07 s (61.7 %)
     * specializing.Clusters: 6.26 s (47.9 %)
        * cire: 3.79 s (29.0 %)
  * lowering.Expressions: 4.70 s (35.9 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 12.88 s
  * lowering.Clusters: 8.11 s (63.0 %)
     * specializing.Clusters: 6.19 s (48.1 %)
        * cire: 3.95 s (30.7 %)
  * lowering.Expressions: 4.46 s (34.7 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 2.29 s
  * lowering.Clusters: 1.44 s (63.0 %)
     * specializing.Clusters: 0.95 s (41.5 %)
        * cire: 0.69 s (30.2 %)
  * lowering.Expressions: 0.59 s (25.8 %)
Flops reduction after symbolic optimization: [7302 --> 291]

real	0m29.538s
user	0m31.264s
sys	0m0.277s
Operator `Kernel` generated in 30.31 s
  * lowering.Clusters: 19.87 s (65.6 %)
     * specializing.Clusters: 15.42 s (50.9 %)
        * cire: 9.47 s (31.3 %)
  * lowering.Expressions: 9.71 s (32.1 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 29.79 s
  * lowering.Clusters: 19.68 s (66.1 %)
     * specializing.Clusters: 15.13 s (50.8 %)
        * cire: 9.55 s (32.1 %)
  * lowering.Expressions: 9.39 s (31.6 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 5.39 s
  * lowering.Clusters: 3.52 s (65.4 %)
     * specializing.Clusters: 2.40 s (44.6 %)
        * cire: 1.78 s (33.1 %)
  * lowering.Expressions: 1.21 s (22.5 %)
Flops reduction after symbolic optimization: [7302 --> 291]

real	1m12.504s
user	1m13.780s
sys	0m0.482s
py-spy> Sampling process 500 times a second. Press Control-C to exit.

Operator `Kernel` generated in 25.37 s
  * lowering.Clusters: 15.15 s (59.8 %)
     * specializing.Clusters: 11.92 s (47.1 %)
        * cire: 7.05 s (27.8 %)
  * lowering.Expressions: 9.55 s (37.7 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 25.28 s
  * lowering.Clusters: 15.65 s (62.0 %)
     * specializing.Clusters: 12.46 s (49.3 %)
        * cire: 7.34 s (29.1 %)
  * lowering.Expressions: 9.00 s (35.7 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 4.38 s
  * lowering.Clusters: 2.55 s (58.3 %)
     * specializing.Clusters: 1.51 s (34.6 %)
        * cire: 1.04 s (23.8 %)
  * lowering.Expressions: 1.25 s (28.6 %)
Flops reduction after symbolic optimization: [7302 --> 291]

py-spy> Stopped sampling because process exited
py-spy> Wrote flamegraph data to 'main_pys.svg'. Samples: 28478 Errors: 35
Error: No child process (os error 10)

real	0m57.425s
user	0m40.719s
sys	0m28.169s
Switched to branch 'JDBetteridge/expand_derivative'
Your branch and 'origin/JDBetteridge/expand_derivative' have diverged,
and have 143 and 31 different commits each, respectively.
  (use "git pull" if you want to integrate the remote branch with yours)
Operator `Kernel` generated in 13.09 s
  * lowering.Clusters: 8.11 s (62.0 %)
     * specializing.Clusters: 6.29 s (48.1 %)
        * cire: 3.91 s (29.9 %)
  * lowering.Expressions: 4.66 s (35.7 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 12.96 s
  * lowering.Clusters: 8.23 s (63.6 %)
     * specializing.Clusters: 6.30 s (48.7 %)
        * cire: 4.01 s (31.0 %)
  * lowering.Expressions: 4.42 s (34.2 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 2.31 s
  * lowering.Clusters: 1.44 s (62.5 %)
     * specializing.Clusters: 0.95 s (41.3 %)
        * cire: 0.68 s (29.6 %)
  * lowering.Expressions: 0.60 s (26.1 %)
Flops reduction after symbolic optimization: [7302 --> 291]

real	0m29.629s
user	0m31.293s
sys	0m0.267s
Operator `Kernel` generated in 29.64 s
  * lowering.Clusters: 19.37 s (65.4 %)
     * specializing.Clusters: 14.98 s (50.6 %)
        * cire: 9.15 s (30.9 %)
  * lowering.Expressions: 9.55 s (32.3 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 29.27 s
  * lowering.Clusters: 19.12 s (65.4 %)
     * specializing.Clusters: 14.70 s (50.3 %)
        * cire: 9.26 s (31.7 %)
  * lowering.Expressions: 9.47 s (32.4 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 5.19 s
  * lowering.Clusters: 3.34 s (64.5 %)
     * specializing.Clusters: 2.29 s (44.2 %)
        * cire: 1.70 s (32.8 %)
  * lowering.Expressions: 1.22 s (23.6 %)
Flops reduction after symbolic optimization: [7302 --> 291]

real	1m10.286s
user	1m11.559s
sys	0m0.511s
py-spy> Sampling process 500 times a second. Press Control-C to exit.

Operator `Kernel` generated in 25.57 s
  * lowering.Clusters: 14.91 s (58.4 %)
     * specializing.Clusters: 11.76 s (46.1 %)
        * cire: 7.12 s (27.9 %)
  * lowering.Expressions: 9.82 s (38.5 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 24.50 s
  * lowering.Clusters: 15.30 s (62.5 %)
     * specializing.Clusters: 12.01 s (49.1 %)
        * cire: 7.02 s (28.7 %)
  * lowering.Expressions: 8.66 s (35.4 %)
Flops reduction after symbolic optimization: [10128 --> 215]
Operator `Kernel` generated in 4.20 s
  * lowering.Clusters: 2.44 s (58.2 %)
     * specializing.Clusters: 1.41 s (33.6 %)
        * cire: 0.92 s (22.0 %)
  * lowering.Expressions: 1.17 s (27.9 %)
Flops reduction after symbolic optimization: [7302 --> 291]

py-spy> Stopped sampling because process exited
py-spy> Wrote flamegraph data to 'expand_pys.svg'. Samples: 28088 Errors: 28
Error: No child process (os error 10)

real	0m56.759s
user	0m39.889s
sys	0m27.775s

main_pys expand_pys

profiling.zip

JDBetteridge avatar Jul 30 '25 13:07 JDBetteridge