Skip to content

api: fix interp/eval of expressions#2843

Open
mloubout wants to merge 1 commit intomainfrom
stagg-encore
Open

api: fix interp/eval of expressions#2843
mloubout wants to merge 1 commit intomainfrom
stagg-encore

Conversation

@mloubout
Copy link
Contributor

@mloubout mloubout commented Feb 4, 2026

No description provided.

@mloubout mloubout added the API api (symbolics, types, ...) label Feb 4, 2026
@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

❌ Patch coverage is 97.40260% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.97%. Comparing base (676b8bf) to head (3fc5b91).

Files with missing lines Patch % Lines
devito/finite_differences/differentiable.py 96.07% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2843      +/-   ##
==========================================
- Coverage   78.97%   78.97%   -0.01%     
==========================================
  Files         248      248              
  Lines       50901    50936      +35     
  Branches     4395     4404       +9     
==========================================
+ Hits        40199    40226      +27     
- Misses       9904     9909       +5     
- Partials      798      801       +3     

☔ 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.

@mloubout mloubout force-pushed the stagg-encore branch 3 times, most recently from f2e36fa to 171969e Compare February 5, 2026 00:55
@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@mloubout mloubout force-pushed the stagg-encore branch 2 times, most recently from 018e9d3 to 10eac67 Compare February 5, 2026 02:42
Copy link
Contributor

@FabioLuporini FabioLuporini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's quite a few changes here, but not as many new tests covering them?

for i in self._args_diff)))
if not self._args_diff:
return DimensionTuple()
# Get indices of all args and merge them
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: blank line

for a in self._args_diff:
for d, i in a.indices.getters.items():
mapper.setdefault(d, []).append(i)
# Filter unique indices
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: blank line

# Filter unique indices
mapper = {k: v[0] if len(v) == 1 else tuple(filter_ordered(v))
for k, v in mapper.items()}
return DimensionTuple(*mapper.values(), getters=tuple(mapper.keys()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: blank line

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: can just be getters=tuple(mapper)

def dimensions(self):
return tuple(filter_ordered(flatten(getattr(i, 'dimensions', ())
for i in self._args_diff)))
if not self._args_diff:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need these two lines? highest_priority(self).dimensions should already return it, or there's something non-consistent about it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because a generic Differentiable does not necessarily has an _args_diff. For. example 1/h_x is a Differentiable but it doesn't have any argument that is Differentiable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but the property is still there, it's not that you are exposing yourself to an AttributeError... so (1/h_x)._args_diff will return the empty tuple and it should just be fine no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty tuple doesn't have a .staggered or .dimension property. And on top of it (1/h_x)._args_diff will return 1/h_x which wiull be an infinite recursion


@cached_property
def staggered(self):
if not self._args_diff:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same story as before, I think

... unless I'm missing something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

def highest_priority(DiffOp):
if not DiffOp._args_diff:
return DiffOp
# We want to get the object with highest priority
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line

@@ -475,12 +487,19 @@ def has_free(self, *patterns):


def highest_priority(DiffOp):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small letters diff_op as it's an instance


@interp_for_fd.register(Mul)
def _(expr, x0, **kwargs):
# For a expression (e.g Mul or Add), we interpolate the whole expression
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"an expression"

so the comment says "Mul or Add" but the dispatcher only targets Mul. Is it expected?

# Filter unique indices
mapper = {k: v[0] if len(v) == 1 else tuple(filter_ordered(v))
for k, v in mapper.items()}
return DimensionTuple(*mapper.values(), getters=tuple(mapper.keys()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: can just be getters=tuple(mapper)


# Split args between those that need interp and those that don't
def test0(a):
return all(a.indices[d] is i for d, i in x0.items() if d in a.dimensions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: blank line

f"'{expr}' must be of type Differentiable, not {type(expr)}"
) from None
except Exception as e:
raise type(e)(f"Error while computing finite-difference for expr={expr}: "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reporting the type of expr here would make this error message more useful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean the message is raise type(e) ... that's type already

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

Labels

API api (symbolics, types, ...)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants