def anti_stencil(self): ret = Stencil() for k, v in self.Tdistances: ret[k].update(set(v)) for k, v in self.ghost_offsets.items(): ret[k].update(v) return ret
def __init__(self, alias, aliased=None, distances=None, ghost_offsets=None): self.alias = alias self.aliased = aliased or [] self.distances = distances or [] self.ghost_offsets = ghost_offsets or Stencil() assert len(self.aliased) == len(self.distances) # Transposed distances self.Tdistances = LabeledVector.transpose(*distances)
# none (different dimension) (['Eq(t0, fa[x] + fb[x])', 'Eq(t1, fa[x] + fb[y])'], { 'fa[x] + fb[x]': None, 'fa[x] + fb[y]': None }), # none (different operation) (['Eq(t0, fa[x] + fb[x])', 'Eq(t1, fa[x] - fb[x])'], { 'fa[x] + fb[x]': None, 'fa[x] - fb[x]': None }), # simple ([ 'Eq(t0, fa[x] + fb[x])', 'Eq(t1, fa[x+1] + fb[x+1])', 'Eq(t2, fa[x-1] + fb[x-1])' ], { 'fa[x] + fb[x]': Stencil([(x, {-1, 0, 1})]) }), # 2D simple (['Eq(t0, fc[x,y] + fd[x,y])', 'Eq(t1, fc[x+1,y+1] + fd[x+1,y+1])'], { 'fc[x,y] + fd[x,y]': Stencil([(x, {0, 1}), (y, {0, 1})]) }), # 2D with stride ([ 'Eq(t0, fc[x,y] + fd[x+1,y+2])', 'Eq(t1, fc[x+1,y+1] + fd[x+2,y+3])' ], { 'fc[x,y] + fd[x+1,y+2]': Stencil([(x, {0, 1}), (y, {0, 1})]) }), # complex (two 2D aliases with stride inducing relaxation) ([ 'Eq(t0, fc[x,y] + fd[x+1,y+2])',
assert str(pow_to_mul(eval(expr))) == expected @pytest.mark.parametrize('exprs,expected', [ # none (different distance) (['Eq(t0, fa[x] + fb[x])', 'Eq(t1, fa[x+1] + fb[x])'], {'fa[x] + fb[x]': None, 'fa[x+1] + fb[x]': None}), # none (different dimension) (['Eq(t0, fa[x] + fb[x])', 'Eq(t1, fa[x] + fb[y])'], {'fa[x] + fb[x]': None, 'fa[x] + fb[y]': None}), # none (different operation) (['Eq(t0, fa[x] + fb[x])', 'Eq(t1, fa[x] - fb[x])'], {'fa[x] + fb[x]': None, 'fa[x] - fb[x]': None}), # simple (['Eq(t0, fa[x] + fb[x])', 'Eq(t1, fa[x+1] + fb[x+1])', 'Eq(t2, fa[x-1] + fb[x-1])'], {'fa[x] + fb[x]': Stencil([(x, {-1, 0, 1})])}), # 2D simple (['Eq(t0, fc[x,y] + fd[x,y])', 'Eq(t1, fc[x+1,y+1] + fd[x+1,y+1])'], {'fc[x,y] + fd[x,y]': Stencil([(x, {0, 1}), (y, {0, 1})])}), # 2D with stride (['Eq(t0, fc[x,y] + fd[x+1,y+2])', 'Eq(t1, fc[x+1,y+1] + fd[x+2,y+3])'], {'fc[x,y] + fd[x+1,y+2]': Stencil([(x, {0, 1}), (y, {0, 1})])}), # complex (two 2D aliases with stride inducing relaxation) (['Eq(t0, fc[x,y] + fd[x+1,y+2])', 'Eq(t1, fc[x+1,y+1] + fd[x+2,y+3])', 'Eq(t2, fc[x-2,y-2]*3. + fd[x+2,y+2])', 'Eq(t3, fc[x-4,y-4]*3. + fd[x,y])'], {'fc[x,y] + fd[x+1,y+2]': Stencil([(x, {-1, 0, 1}), (y, {-1, 0, 1})]), '3.*fc[x-3,y-3] + fd[x+1,y+1]': Stencil([(x, {-1, 0, 1}), (y, {-1, 0, 1})])}), ]) def test_collect_aliases(fa, fb, fc, fd, t0, t1, t2, t3, exprs, expected): scope = [fa, fb, fc, fd, t0, t1, t2, t3] mapper = dict([(EVAL(k, *scope), v) for k, v in expected.items()])
def collect(exprs): """ Determine groups of aliasing expressions in ``exprs``. An expression A aliases an expression B if both A and B perform the same arithmetic operations over the same input operands, with the possibility for Indexeds to access locations at a fixed constant offset in each Dimension. For example: :: exprs = (a[i+1] + b[i+1], a[i+1] + b[j+1], a[i] + c[i], a[i+2] - b[i+2], a[i+2] + b[i], a[i-1] + b[i-1]) The following expressions in ``exprs`` alias to ``a[i] + b[i]``: * a[i+1] + b[i+1] : same operands and operations, distance along i = 1 * a[i-1] + b[i-1] : same operands and operations, distance along i = -1 Whereas the following do not: * a[i+1] + b[j+1] : because at least one index differs * a[i] + c[i] : because at least one of the operands differs * a[i+2] - b[i+2] : because at least one operation differs * a[i+2] + b[i] : because distance along ``i`` differ (+2 and +0) """ # Determine the potential aliases candidates = [] for expr in exprs: candidate = analyze(expr) if candidate is not None: candidates.append(candidate) # Group together the aliasing expressions (ultimately build an Alias for each # group of aliasing expressions) aliases = Aliases() unseen = list(candidates) while unseen: c = unseen.pop(0) # Find aliasing expressions group = [c] for i in list(unseen): if compare_ops(c.expr, i.expr) and is_translated(c, i): group.append(i) unseen.remove(i) # Try creating a basis spanning the aliasing expressions' iteration vectors try: COM, distances = calculate_COM(group) except ValueError: # Ignore these aliasing expressions and move on continue # Create an alias expression centering `c`'s Indexeds at the COM subs = { i: i.function[[x + v.fromlabel(x, 0) for x in b]] for i, b, v in zip(c.indexeds, c.bases, COM) } alias = c.expr.xreplace(subs) aliased = [i.expr for i in group] aliases[alias] = Alias(alias, aliased, distances) # Heuristically attempt to relax the Aliases offsets to maximize the # likelyhood of loop fusion groups = OrderedDict() for i in aliases.values(): groups.setdefault(i.dimensions, []).append(i) for group in groups.values(): ideal_anti_stencil = Stencil.union(*[i.anti_stencil for i in group]) for i in group: if i.anti_stencil.subtract(ideal_anti_stencil).empty: aliases[i.alias] = i.relax(ideal_anti_stencil) return aliases