Exemplo n.º 1
0
def detect_flow_directions(exprs):
    """Return a mapper from :class:`Dimension`s to iterables of
    :class:`IterationDirection`s representing the theoretically necessary
    directions to evaluate ``exprs`` so that the information "naturally
    flows" from an iteration to another."""
    exprs = as_tuple(exprs)

    writes = [Access(i.lhs, 'W') for i in exprs]
    reads = flatten(retrieve_indexed(i.rhs, mode='all') for i in exprs)
    reads = [Access(i, 'R') for i in reads]

    # Determine indexed-wise direction by looking at the vector distance
    mapper = defaultdict(set)
    for w in writes:
        for r in reads:
            if r.name != w.name:
                continue
            dimensions = [d for d in w.aindices if d is not None]
            for d in dimensions:
                try:
                    if w.distance(r, d) > 0:
                        mapper[d].add(Forward)
                        break
                    elif w.distance(r, d) < 0:
                        mapper[d].add(Backward)
                        break
                    else:
                        mapper[d].add(Any)
                except TypeError:
                    # Nothing can be deduced
                    mapper[d].add(Any)
                    break
            # Remainder
            for d in dimensions[dimensions.index(d) + 1:]:
                mapper[d].add(Any)

    # Add in any encountered Dimension
    mapper.update({
        d: {Any}
        for d in flatten(i.aindices for i in reads + writes)
        if d is not None and d not in mapper
    })

    # Add in stepping dimensions (just in case they haven't been detected yet)
    # note: stepping dimensions may force a direction on the parent
    assert all(v == {Any} or mapper.get(k.parent, v) in [v, {Any}]
               for k, v in mapper.items() if k.is_Stepping)
    mapper.update({
        k.parent: set(v)
        for k, v in mapper.items()
        if k.is_Stepping and mapper.get(k.parent) == {Any}
    })

    # Add in derived dimensions parents
    mapper.update({
        k.parent: set(v)
        for k, v in mapper.items() if k.is_Derived and k.parent not in mapper
    })

    return mapper
Exemplo n.º 2
0
def detect_flow_directions(exprs):
    """
    Return a mapper from Dimensions to Iterables of IterationDirections
    representing the theoretically necessary directions to evaluate ``exprs``
    so that the information "naturally flows" from an iteration to another.
    """
    exprs = as_tuple(exprs)

    writes = [Access(i.lhs, 'W') for i in exprs]
    reads = flatten(retrieve_indexed(i.rhs) for i in exprs)
    reads = [Access(i, 'R') for i in reads]

    # Determine indexed-wise direction by looking at the distance vector
    mapper = defaultdict(set)
    for w in writes:
        for r in reads:
            if r.name != w.name:
                continue
            dimensions = [d for d in w.aindices if d is not None]
            if not dimensions:
                continue
            for d in dimensions:
                distance = None
                for i in d._defines:
                    try:
                        distance = w.distance(r, i, view=i)
                    except TypeError:
                        pass
                try:
                    if distance > 0:
                        mapper[d].add(Forward)
                        break
                    elif distance < 0:
                        mapper[d].add(Backward)
                        break
                    else:
                        mapper[d].add(Any)
                except TypeError:
                    # Nothing can be deduced
                    mapper[d].add(Any)
                    break
            # Remainder
            for d in dimensions[dimensions.index(d) + 1:]:
                mapper[d].add(Any)

    # Add in any encountered Dimension
    mapper.update({d: {Any} for d in flatten(i.aindices for i in reads + writes)
                   if d is not None and d not in mapper})

    # Add in derived-dimensions parents, in case they haven't been detected yet
    mapper.update({k.parent: set(v) for k, v in mapper.items()
                   if k.is_Derived and mapper.get(k.parent, {Any}) == {Any}})

    # Add in:
    # - free Dimensions, ie Dimensions used as symbols rather than as array indices
    # - implicit Dimensions, ie Dimensions that do not explicitly appear in `exprs`
    #   (typically used for inline temporaries)
    for i in exprs:
        candidates = {s for s in i.free_symbols if isinstance(s, Dimension)}
        candidates.update(set(i.implicit_dims))
        mapper.update({d: {Any} for d in candidates if d not in mapper})

    return mapper