Example #1
0
 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
Example #2
0
    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)
Example #3
0
 # 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])',
Example #4
0
    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()])
Example #5
0
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