def reorder(cls, items, relations): if not all(isinstance(i, AbstractInterval) for i in items): raise ValueError("Cannot create an IntervalGroup from objects of type [%s]" % ', '.join(str(type(i)) for i in items)) # The relations are between dimensions, not intervals. So we take # care of that here ordering = filter_ordered(toposort(relations) + [i.dim for i in items]) return sorted(items, key=lambda i: ordering.index(i.dim))
def dimension_sort(expr, key=None): """ Topologically sort the :class:`Dimension`s in ``expr``, based on the order in which they appear within :class:`Indexed`s. :param expr: The :class:`devito.Eq` from which the :class:`Dimension`s are extracted. :param key: A callable used as key to enforce a final ordering. """ def handle_indexed(indexed): constraint = [] for i in indexed.indices: try: maybe_dim = split_affine(i).var if isinstance(maybe_dim, Dimension): constraint.append(maybe_dim) except ValueError: # Maybe there are some nested Indexeds (e.g., the situation is A[B[i]]) nested = flatten(handle_indexed(n) for n in retrieve_indexed(i)) if nested: constraint.extend(nested) else: # Fallback: Just insert all the Dimensions we find, regardless of # what the user is attempting to do constraint.extend([d for d in filter_sorted(i.free_symbols) if isinstance(d, Dimension)]) return constraint constraints = [handle_indexed(i) for i in retrieve_indexed(expr, mode='all')] ordering = toposort(constraints) # Add in leftover free dimensions (not an Indexed' index) extra = set([i for i in expr.free_symbols if isinstance(i, Dimension)]) # Add in pure data dimensions (e.g., those accessed only via explicit values, # such as A[3]) indexeds = retrieve_indexed(expr, deep=True) if indexeds: extra.update(set.union(*[set(i.function.indices) for i in indexeds])) # Enforce determinism extra = filter_sorted(extra, key=attrgetter('name')) ordering.extend([i for i in extra if i not in ordering]) # Add in parent dimensions for i in list(ordering): if i.is_Derived and i.parent not in ordering: ordering.insert(ordering.index(i), i.parent) return sorted(ordering, key=key)
def reorder(cls, items, relations): # The relations are between dimensions, not intervals. So we take # care of that here ordering = filter_ordered(toposort(relations) + [i.dim for i in items]) return sorted(items, key=lambda i: ordering.index(i.dim))
def test_toposort(elements, expected): try: ordering = toposort(elements) assert ordering == expected except ValueError: assert expected is None