Skip to content

Commit 8f22349

Browse files
committed
api: fix buffering with multiple conditions
1 parent 24ffedf commit 8f22349

5 files changed

Lines changed: 71 additions & 23 deletions

File tree

devito/ir/equations/equation.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
)
1616
from devito.symbolics import IntDiv, limits_mapper, uxreplace
1717
from devito.tools import Pickable, Tag, frozendict
18-
from devito.types import Eq, Inc, ReduceMax, ReduceMin, ReduceMinMax, relational_min, relational_shift
18+
from devito.types import (
19+
Eq, Inc, ReduceMax, ReduceMin, ReduceMinMax, relational_min, relational_shift
20+
)
1921

2022
__all__ = [
2123
'ClusterizedEq',
@@ -294,7 +296,7 @@ def __new__(cls, *args, **kwargs):
294296
relations=ordering.relations, mode='partial')
295297
ispace = IterationSpace(intervals, iterators)
296298

297-
# Construct the conditionals and replace the ConditionalDimensions in `expr`
299+
# Construct the conditionals
298300
conditionals = {}
299301
for d in ordering:
300302
if not d.is_Conditional:
@@ -306,14 +308,6 @@ def __new__(cls, *args, **kwargs):
306308
if d._factor is not None:
307309
cond = d.relation(cond, GuardFactor(d))
308310
conditionals[d] = cond
309-
# Replace dimension with index
310-
index = d.index
311-
if d.condition is not None and d in expr.free_symbols:
312-
index = index - relational_min(d.condition, d.parent)
313-
shift = relational_shift(d.condition, d.parent)
314-
else:
315-
shift = 0
316-
expr = uxreplace(expr, {d: IntDiv(index, d.symbolic_factor) + shift})
317311

318312
# Merge conditionals when possible. E.g if we have an implicit_dim
319313
# and there is a dimension with the same parent, we ca merged
@@ -330,6 +324,14 @@ def __new__(cls, *args, **kwargs):
330324

331325
conditionals = frozendict(conditionals)
332326

327+
# Replace the ConditionalDimensions in `expr`
328+
for d, cond in conditionals.items():
329+
# Replace dimension with index
330+
index = d.index
331+
index = index - relational_min(cond, d.parent)
332+
shift = relational_shift(cond, d.parent)
333+
expr = uxreplace(expr, {d: IntDiv(index, d.symbolic_factor) + shift})
334+
333335
# Lower all Differentiable operations into SymPy operations
334336
rhs = diff2sympy(expr.rhs)
335337

devito/ir/support/vector.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def __lt__(self, other):
128128
return True
129129
elif q_positive(i):
130130
return False
131+
131132
raise TypeError("Non-comparable index functions") from e
132133

133134
return False
@@ -164,6 +165,7 @@ def __gt__(self, other):
164165
return True
165166
elif q_negative(i):
166167
return False
168+
167169
raise TypeError("Non-comparable index functions") from e
168170

169171
return False
@@ -203,6 +205,7 @@ def __le__(self, other):
203205
return True
204206
elif q_positive(i):
205207
return False
208+
206209
raise TypeError("Non-comparable index functions") from e
207210

208211
# Note: unlike `__lt__`, if we end up here, then *it is* <=. For example,

devito/passes/clusters/cse.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,9 @@ def cse(cluster, sregistry=None, options=None, **kwargs):
103103
if cluster.is_fence:
104104
return cluster
105105

106-
<<<<<<< HEAD
107106
def make(e):
108107
edtype = cse_dtype(e.dtype, dtype)
109108
return CTemp(name=sregistry.make_name(), dtype=edtype)
110-
=======
111-
make_dtype = lambda e: cse_dtype(e.dtype, dtype)
112-
make = lambda e: CTemp(name=sregistry.make_name(), dtype=make_dtype(e))
113-
>>>>>>> 54c5e49e2 (api: fix interpolate with complex dtype)
114109

115110
exprs = _cse(cluster, make, min_cost=min_cost, mode=mode)
116111

devito/types/relational.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,22 @@ def relational_shift(expr, s):
302302
if not expr.has(s):
303303
return 0
304304

305-
try:
306-
return expr._as_min
307-
except (TypeError, AttributeError):
305+
return _relational_shift(expr, s)
306+
307+
308+
@singledispatch
309+
def _relational_shift(s, expr):
310+
return 0
311+
312+
313+
@_relational_shift.register(sympy.Or)
314+
@_relational_shift.register(sympy.And)
315+
def _(expr, s):
316+
return sum([_relational_shift(e, s) for e in expr.args])
317+
318+
319+
@_relational_shift.register(sympy.Eq)
320+
def _(expr, s):
321+
if isinstance(expr.lhs, sympy.Mod):
308322
return 0
323+
return expr._as_min

tests/test_buffering.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ def test_buffer_reuse():
754754
assert all(np.all(vsave.data[i-1] == i + 1) for i in range(1, nt + 1))
755755

756756

757-
def test_multi_cond():
757+
def test_multi_cond_v0():
758758
grid = Grid((3, 3))
759759
nt = 5
760760

@@ -774,14 +774,47 @@ def test_multi_cond():
774774
T = TimeFunction(grid=grid, name='T', time_order=0, space_order=0)
775775

776776
eqs = [Eq(T, grid.time_dim)]
777-
# this to save times from 0 to nt - 2
777+
# This saves
778+
# - All subsampled times since ct1 is the dimension of f
779+
# - The last time step (ntmod - 2) through ctend (since it's set as ct1 or ctend)
780+
eqs.append(Eq(f, T, implicit_dims=ctend))
781+
782+
# run operator with buffering
783+
op = Operator(eqs, opt='buffering')
784+
op.apply(time_m=0, time_M=ntmod-2)
785+
786+
for i in range(nt-1):
787+
assert np.allclose(f.data[i], i*2)
788+
assert np.allclose(f.data[nt-1], ntmod - 2)
789+
790+
791+
def test_multi_cond_v1():
792+
grid = Grid((3, 3))
793+
nt = 5
794+
795+
x, y = grid.dimensions
796+
797+
factor = 2
798+
ntmod = (nt - 1) * factor + 1
799+
800+
ct1 = ConditionalDimension(name="ct1", parent=grid.time_dim,
801+
factor=factor, relation=Or,
802+
condition=CondEq(grid.time_dim, ntmod - 2))
803+
804+
f = TimeFunction(grid=grid, name='f', time_order=0,
805+
space_order=0, save=nt, time_dim=ct1)
806+
T = TimeFunction(grid=grid, name='T', time_order=0, space_order=0)
807+
808+
eqs = [Eq(T, grid.time_dim)]
809+
# This saves
810+
# - All subsampled times since ct1 is the dimension of f with factor 2
811+
# - The last time step (ntmod - 2) since ct1 also has the condition for ntmod - 2
778812
eqs.append(Eq(f, T))
779-
# this to save the last time sample nt - 1
780-
eqs.append(Eq(f.forward, T+1, implicit_dims=ctend))
781813

782814
# run operator with buffering
783815
op = Operator(eqs, opt='buffering')
784816
op.apply(time_m=0, time_M=ntmod-2)
785817

786-
for i in range(nt):
818+
for i in range(nt-1):
787819
assert np.allclose(f.data[i], i*2)
820+
assert np.allclose(f.data[nt-1], ntmod - 2)

0 commit comments

Comments
 (0)