Source code for ufl.algorithms.renumbering
"""Algorithms for renumbering of counted objects, currently variables and indices."""
# Copyright (C) 2008-2024 Martin Sandve Alnæs, Anders Logg, Jørgen S. Dokken and Lawrence Mitchell
#
# This file is part of UFL (https://www.fenicsproject.org)
#
# SPDX-License-Identifier: LGPL-3.0-or-later
from collections import defaultdict
from itertools import count as _count
from ufl.algorithms.map_integrands import map_integrand_dags
from ufl.core.multiindex import Index
from ufl.corealg.multifunction import MultiFunction
[docs]class IndexRelabeller(MultiFunction):
"""Renumber indices to have a consistent index numbering starting from 0."""
def __init__(self):
"""Initialize index relabeller with a zero count."""
super().__init__()
count = _count()
self.index_cache = defaultdict(lambda: Index(next(count)))
expr = MultiFunction.reuse_if_untouched
[docs] def multi_index(self, o):
"""Apply to multi-indices."""
return type(o)(
tuple(self.index_cache[i] if isinstance(i, Index) else i for i in o.indices())
)
[docs] def zero(self, o):
"""Apply to zero."""
fi = o.ufl_free_indices
fid = o.ufl_index_dimensions
new_indices = [self.index_cache[Index(i)].count() for i in fi]
if fi == () and fid == ():
return o
new_fi, new_fid = zip(*sorted(zip(new_indices, fid), key=lambda x: x[0]))
return type(o)(o.ufl_shape, tuple(new_fi), tuple(new_fid))
[docs]def renumber_indices(form):
"""Renumber indices to have a consistent index numbering starting from 0.
This is useful to avoid multiple kernels for the same integrand,
but with different subdomain ids.
Args:
form: A UFL form, integral or expression.
Returns:
A new form, integral or expression with renumbered indices.
"""
reindexer = IndexRelabeller()
return map_integrand_dags(reindexer, form)