def compute_intervals(expr): """Return an iterable of :class:`Interval`s representing the data items accessed by the :class:`sympy.Eq` ``expr``.""" # Detect the indexeds' offsets along each dimension stencil = Stencil() for e in retrieve_indexed(expr, mode='all', deep=True): for a in e.indices: if isinstance(a, Dimension): stencil[a].update([0]) d = None off = [0] for i in a.args: if isinstance(i, Dimension): d = i elif i.is_integer: off += [int(i)] if d is not None: stencil[d].update(off) # Determine intervals and their iterators iterators = OrderedDict() for i in stencil.dimensions: if i.is_NonlinearDerived: iterators.setdefault(i.parent, []).append(stencil.entry(i)) else: iterators.setdefault(i, []) intervals = [] for k, v in iterators.items(): offs = set.union(set(stencil.get(k)), *[i.ofs for i in v]) intervals.append(Interval(k, min(offs), max(offs))) return intervals, iterators
def detect_accesses(expr): """ Return a mapper ``M : F -> S``, where F are Functions appearing in ``expr`` and S are Stencils. ``M[f]`` represents all data accesses to ``f`` within ``expr``. Also map ``M[None]`` to all Dimensions used in ``expr`` as plain symbols, rather than as array indices. """ # Compute M : F -> S mapper = defaultdict(Stencil) for e in retrieve_indexed(expr, deep=True): f = e.function for a in e.indices: if isinstance(a, Dimension): mapper[f][a].update([0]) d = None off = [] for i in a.args: if isinstance(i, Dimension): d = i elif i.is_integer: off += [int(i)] if d is not None: mapper[f][d].update(off or [0]) # Compute M[None] other_dims = [i for i in retrieve_terminals(expr) if isinstance(i, Dimension)] other_dims.extend(list(expr.implicit_dims)) mapper[None] = Stencil([(i, 0) for i in other_dims]) return mapper
def detect_free_dimensions(expr): """ Return a degenerate :class:`Stencil` for the :class:`Dimension`s used as plain symbols, rather than as array indices, in ``expr``. """ return Stencil([(i, 0) for i in retrieve_terminals(expr) if isinstance(i, Dimension)])
def build_intervals(mapper): """ Given M as produced by :func:`detect_accesses`, return: :: * An iterable of :class:`Interval`s, representing the data items accessed in each :class:`Dimension` in M; * A dictionary of ``iterators``, suitable to build an :class:`IterationSpace`. """ iterators = OrderedDict() stencil = Stencil.union(*mapper.values()) for i in stencil.dimensions: if i.is_NonlinearDerived: iterators.setdefault(i.parent, []).append(stencil.entry(i)) else: iterators.setdefault(i, []) intervals = [] for k, v in iterators.items(): offs = set.union(set(stencil.get(k)), *[i.ofs for i in v]) intervals.append(Interval(k, min(offs), max(offs))) return intervals, iterators