Skip to content

Commit db8b31e

Browse files
committed
Merge branch 'main' into pbrubeck/merge-upstream
2 parents c69482e + 4bc7f0d commit db8b31e

6 files changed

Lines changed: 50 additions & 17 deletions

File tree

test/test_derivative.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
from ufl.algorithms.apply_derivatives import apply_derivatives
6161
from ufl.algorithms.apply_geometry_lowering import apply_geometry_lowering
6262
from ufl.classes import Indexed, MultiIndex, ReferenceGrad
63-
from ufl.constantvalue import as_ufl
63+
from ufl.constantvalue import Zero, as_ufl
6464
from ufl.domain import extract_unique_domain
6565
from ufl.finiteelement import FiniteElement, MixedElement
6666
from ufl.pullback import identity_pullback
@@ -902,6 +902,39 @@ def test_index_simplification_reference_grad(self):
902902
assert expr.ufl_shape == ()
903903

904904

905+
def test_zero_shape(self):
906+
cell = triangle
907+
shape = (2, 3, 4)
908+
P1 = FiniteElement("Lagrange", cell, 1, shape, identity_pullback, H1)
909+
domain = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1))
910+
V = FunctionSpace(domain, P1)
911+
v = TestFunction(V)
912+
u = Coefficient(V)
913+
w = Coefficient(V)
914+
915+
(i,) = indices(1)
916+
z = zero(shape)
917+
zi = z[:, i, :]
918+
wi = w[:, i, :]
919+
assert isinstance(zi, Zero)
920+
assert wi.ufl_shape == (shape[0], shape[-1])
921+
assert wi.ufl_shape == zi.ufl_shape
922+
923+
a = derivative(conditional(u[0, 0, 0] < 1, zi, wi), u, v)
924+
assert not isinstance(a, Zero)
925+
926+
assert a.ufl_shape == zi.ufl_shape
927+
assert a.ufl_free_indices == zi.ufl_free_indices
928+
assert a.ufl_index_dimensions == zi.ufl_index_dimensions
929+
930+
expr = apply_derivatives(apply_geometry_lowering(apply_algebra_lowering(a)))
931+
932+
assert isinstance(expr, Zero)
933+
assert expr.ufl_shape == a.ufl_shape
934+
assert expr.ufl_free_indices == a.ufl_free_indices
935+
assert expr.ufl_index_dimensions == a.ufl_index_dimensions
936+
937+
905938
# --- Scratch space
906939

907940

ufl/algorithms/apply_derivatives.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ def independent_operator(self, o):
179179
# Constants are independent of any differentiation
180180
constant = independent_terminal
181181

182+
# Zero may have free indices
183+
zero = independent_operator
184+
182185
# Rules for form arguments must be specified in specialized rule set
183186
form_argument = override
184187

ufl/algorithms/remove_component_tensors.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ufl.classes import ComponentTensor, Index, MultiIndex, Zero
1515
from ufl.corealg.map_dag import map_expr_dag
1616
from ufl.corealg.multifunction import MultiFunction
17+
from ufl.index_combination_utils import unique_sorted_indices
1718

1819

1920
class IndexReplacer(MultiFunction):
@@ -38,18 +39,19 @@ def zero(self, o):
3839
# Reuse if untouched
3940
return o
4041

41-
free_indices = []
42-
index_dimensions = []
42+
fi = []
4343
for i, d in zip(indices, o.ufl_index_dimensions):
4444
j = self.fimap.get(i, i)
4545
if isinstance(j, Index):
46-
free_indices.append(j.count())
47-
index_dimensions.append(d)
46+
fi.append((j.count(), d))
47+
48+
fi = unique_sorted_indices(sorted(fi))
49+
free_indices, index_dimensions = zip(*fi)
4850

4951
return Zero(
5052
shape=o.ufl_shape,
51-
free_indices=tuple(free_indices),
52-
index_dimensions=tuple(index_dimensions),
53+
free_indices=free_indices,
54+
index_dimensions=index_dimensions,
5355
)
5456

5557
def multi_index(self, o):

ufl/conditional.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from ufl.core.operator import Operator
1414
from ufl.core.ufl_type import ufl_type
1515
from ufl.exprequals import expr_equals
16-
from ufl.indexed import Indexed
1716
from ufl.precedence import parstr
1817

1918
# --- Condition classes ---
@@ -292,7 +291,7 @@ def __init__(self, condition, true_value, false_value):
292291
raise ValueError("Shape mismatch between conditional branches.")
293292
tfi = true_value.ufl_free_indices
294293
ffi = false_value.ufl_free_indices
295-
if tuple(sorted(tfi)) != tuple(sorted(ffi)):
294+
if tfi != ffi:
296295
raise ValueError("Free index mismatch between conditional branches.")
297296
if isinstance(condition, (EQ, NE)):
298297
if not all(
@@ -307,10 +306,6 @@ def __init__(self, condition, true_value, false_value):
307306
Operator.__init__(self, (condition, true_value, false_value))
308307
self._initialised = True
309308

310-
def _simplify_indexed(self, multiindex):
311-
(c, a, b) = self.ufl_operands
312-
return Conditional(c, Indexed(a, multiindex), Indexed(b, multiindex))
313-
314309
def evaluate(self, x, mapping, component, index_values):
315310
"""Evaluate."""
316311
c = self.ufl_operands[0].evaluate(x, mapping, component, index_values)

ufl/exprequals.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def expr_equals(self, other):
2020
return False
2121

2222
# Large objects are costly to compare with themselves
23-
if self is other or self.ufl_operands is other.ufl_operands:
23+
if (self is other) or (self.ufl_operands is other.ufl_operands):
2424
return True
2525

2626
# Modelled after pre_traversal to avoid recursion:
@@ -37,7 +37,7 @@ def expr_equals(self, other):
3737
# Delve into subtrees
3838
so = s.ufl_operands
3939
oo = o.ufl_operands
40-
# Skip subtrees if operands are the same
40+
# Skip subtree if operands are the same
4141
if so is oo:
4242
continue
4343
if len(so) != len(oo):
@@ -48,7 +48,7 @@ def expr_equals(self, other):
4848
if s._ufl_typecode_ != o._ufl_typecode_:
4949
return False
5050
# Skip subtree if objects are the same
51-
if s is o or s.ufl_operands is o.ufl_operands:
51+
if s is o:
5252
continue
5353
if (id(s), id(o)) in equal_pairs:
5454
continue

ufl/sorting.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def cmp_expr(a, b):
143143
# Delve into subtrees
144144
aops = a.ufl_operands
145145
bops = b.ufl_operands
146-
# Skip subtrees if operands are the same
146+
# Skip subtree if operands are the same
147147
if aops is bops:
148148
continue
149149

0 commit comments

Comments
 (0)