예제 #1
0
파일: graph.py 프로젝트: nw0/devito
    def __init__(self, exprs, **kwargs):
        # Check input legality
        mapper = OrderedDict([(i.lhs, i) for i in exprs])
        if len(set(mapper)) != len(mapper):
            raise DSEException(
                "Found redundant node, cannot build TemporariesGraph.")

        # Construct Temporaries, tracking reads and readby
        tensor_map = DefaultOrderedDict(list)
        for i in mapper:
            tensor_map[as_symbol(i)].append(i)
        reads = DefaultOrderedDict(set)
        readby = DefaultOrderedDict(set)
        for k, v in mapper.items():
            handle = retrieve_terminals(v.rhs)
            for i in list(handle):
                if i.is_Indexed:
                    for idx in i.indices:
                        handle |= retrieve_terminals(idx)
            reads[k].update(
                set(flatten([tensor_map.get(as_symbol(i), [])
                             for i in handle])))
            for i in reads[k]:
                readby[i].add(k)

        # Make sure read-after-writes are honored for scalar temporaries
        processed = [i for i in mapper if i.is_Indexed]
        queue = [i for i in mapper if i not in processed]
        while queue:
            k = queue.pop(0)
            if not readby[k]:
                processed.insert(0, k)
            elif all(i in processed for i in readby[k]):
                index = min(processed.index(i) for i in readby[k])
                processed.insert(index, k)
            else:
                queue.append(k)

        # Build up the TemporariesGraph
        temporaries = [(i,
                        Temporary(*mapper[i].args,
                                  inc=q_inc(mapper[i]),
                                  reads=reads[i],
                                  readby=readby[i])) for i in processed]
        super(TemporariesGraph, self).__init__(temporaries, **kwargs)

        # Determine indices along the space and time dimensions
        terms = [
            v for k, v in self.items() if v.is_tensor and not q_indirect(k)
        ]
        indices = filter_ordered(flatten([i.function.indices for i in terms]))
        self.space_indices = tuple(i for i in indices if i.is_Space)
        self.time_indices = tuple(i for i in indices if i.is_Time)
예제 #2
0
파일: graph.py 프로젝트: woxin5295/devito
    def __init__(self, exprs, **kwargs):
        # Always convert to SSA
        exprs = convert_to_SSA(exprs)
        mapper = OrderedDict([(i.lhs, i) for i in exprs])
        assert len(set(mapper)) == len(exprs), "not SSA Cluster?"

        # Construct the Nodes, tracking reads and readby
        tensor_map = DefaultOrderedDict(list)
        for i in mapper:
            tensor_map[as_symbol(i)].append(i)
        reads = DefaultOrderedDict(set)
        readby = DefaultOrderedDict(set)
        for k, v in mapper.items():
            handle = retrieve_terminals(v.rhs)
            for i in list(handle):
                if i.is_Indexed:
                    for idx in i.indices:
                        handle |= retrieve_terminals(idx)
            reads[k].update(
                set(flatten([tensor_map.get(as_symbol(i), [])
                             for i in handle])))
            for i in reads[k]:
                readby[i].add(k)

        # Make sure read-after-writes are honored for scalar temporaries
        processed = [i for i in mapper if i.is_Indexed]
        queue = [i for i in mapper if i not in processed]
        while queue:
            k = queue.pop(0)
            if not readby[k]:
                processed.insert(0, k)
            elif all(i in processed for i in readby[k]):
                index = min(processed.index(i) for i in readby[k])
                processed.insert(index, k)
            else:
                queue.append(k)

        # Build up the FlowGraph
        temporaries = [(i,
                        Node(*mapper[i].args,
                             inc=q_inc(mapper[i]),
                             reads=reads[i],
                             readby=readby[i])) for i in processed]
        super(FlowGraph, self).__init__(temporaries, **kwargs)

        # Determine indices along the space and time dimensions
        terms = [
            v for k, v in self.items() if v.is_tensor and not q_indirect(k)
        ]
        indices = filter_ordered(flatten([i.function.indices for i in terms]))
        self.space_indices = tuple(i for i in indices if i.is_Space)
        self.time_indices = tuple(i for i in indices if i.is_Time)
예제 #3
0
    def __init__(self, exprs, rules=None):
        """
        A Scope enables data dependence analysis on a totally ordered sequence
        of expressions.
        """
        exprs = as_tuple(exprs)

        self.reads = {}
        self.writes = {}

        self.initialized = set()

        for i, e in enumerate(exprs):
            # Reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.function, [])
                mode = 'RI' if e.is_Increment and j.function is e.lhs.function else 'R'
                v.append(TimedAccess(j, mode, i, e.ispace))

            # Write
            if q_terminal(e.lhs):
                v = self.writes.setdefault(e.lhs.function, [])
                mode = 'WI' if e.is_Increment else 'W'
                v.append(TimedAccess(e.lhs, mode, i, e.ispace))

            # If an increment, we got one implicit read
            if e.is_Increment:
                v = self.reads.setdefault(e.lhs.function, [])
                v.append(TimedAccess(e.lhs, 'RI', i, e.ispace))

            # If writing to a scalar, we have an initialization
            if not e.is_Increment and e.is_scalar:
                self.initialized.add(e.lhs.function)

            # Look up ConditionalDimensions
            for v in e.conditionals.values():
                for j in retrieve_terminals(v):
                    v = self.reads.setdefault(j.function, [])
                    v.append(TimedAccess(j, 'R', -1, e.ispace))

        # The iteration symbols too
        dimensions = set().union(*[e.dimensions for e in exprs])
        for d in dimensions:
            for i in d._defines_symbols:
                for j in i.free_symbols:
                    v = self.reads.setdefault(j.function, [])
                    v.append(TimedAccess(j, 'R', -1))

        # A set of rules to drive the collection of dependencies
        self.rules = as_tuple(rules)
        assert all(callable(i) for i in self.rules)
예제 #4
0
파일: operator.py 프로젝트: nw0/devito
    def _retrieve_symbols(self, expressions):
        """
        Retrieve the symbolic functions read or written by the Operator,
        as well as all traversed dimensions.
        """
        terms = flatten(retrieve_terminals(i) for i in expressions)

        input = []
        for i in terms:
            try:
                input.append(i.base.function)
            except AttributeError:
                pass
        input = filter_sorted(input, key=attrgetter('name'))

        output = [i.lhs.base.function for i in expressions if i.lhs.is_Indexed]

        indexeds = [i for i in terms if i.is_Indexed]
        dimensions = []
        for indexed in indexeds:
            for i in indexed.indices:
                dimensions.extend(
                    [k for k in i.free_symbols if isinstance(k, Dimension)])
            dimensions.extend(list(indexed.base.function.indices))
        dimensions.extend([d.parent for d in dimensions if d.is_Stepping])
        dimensions = filter_sorted(dimensions, key=attrgetter('name'))

        return input, output, dimensions
예제 #5
0
파일: utils.py 프로젝트: ggorman/trytravis
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)])
예제 #6
0
파일: utils.py 프로젝트: opesci/devito
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, mode='all', 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
예제 #7
0
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
예제 #8
0
    def __init__(self, exprs):
        """
        A Scope enables data dependence analysis on a totally ordered sequence
        of expressions.
        """
        exprs = as_tuple(exprs)

        self.reads = {}
        self.writes = {}

        for i, e in enumerate(exprs):
            # Reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.function, [])
                mode = 'RI' if e.is_Increment and j.function is e.lhs.function else 'R'
                v.append(TimedAccess(j, mode, i, e.ispace))

            # Write
            v = self.writes.setdefault(e.lhs.function, [])
            mode = 'WI' if e.is_Increment else 'W'
            v.append(TimedAccess(e.lhs, mode, i, e.ispace))

            # If an increment, we got one implicit read
            if e.is_Increment:
                v = self.reads.setdefault(e.lhs.function, [])
                v.append(TimedAccess(e.lhs, 'RI', i, e.ispace))

        # The iterators read symbols too
        dimensions = set().union(*[e.dimensions for e in exprs])
        for d in dimensions:
            for j in d.symbolic_size.free_symbols:
                v = self.reads.setdefault(j.function, [])
                v.append(TimedAccess(j, 'R', -1))
예제 #9
0
    def __init__(self, exprs):
        """
        A Scope represents a group of TimedAcces objects extracted
        from some IREq ``exprs``. The expressions must be provided
        in program order.
        """
        exprs = as_tuple(exprs)

        self.reads = {}
        self.writes = {}

        for i, e in enumerate(exprs):
            # Reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.function, [])
                mode = 'RI' if e.is_Increment and j.function is e.lhs.function else 'R'
                v.append(TimedAccess(j, mode, i, e.ispace.directions))

            # Write
            v = self.writes.setdefault(e.lhs.function, [])
            mode = 'WI' if e.is_Increment else 'W'
            v.append(TimedAccess(e.lhs, mode, i, e.ispace.directions))

            # If an increment, we got one implicit read
            if e.is_Increment:
                v = self.reads.setdefault(e.lhs.function, [])
                v.append(TimedAccess(e.lhs, 'RI', i, e.ispace.directions))

        # The iterators read symbols too
        dimensions = set().union(*[e.dimensions for e in exprs])
        for d in dimensions:
            for j in d.symbolic_size.free_symbols:
                v = self.reads.setdefault(j.function, [])
                v.append(TimedAccess(j, 'R', -1, {}))
예제 #10
0
def retrieve_symbols(expressions):
    """
    Return the :class:`Function` and :class:`Dimension` objects appearing
    in ``expressions``.
    """
    terms = flatten(retrieve_terminals(i) for i in expressions)

    input = []
    for i in terms:
        try:
            function = i.base.function
        except AttributeError:
            continue
        if function.is_Constant or function.is_TensorFunction:
            input.append(function)
    input = filter_sorted(input, key=attrgetter('name'))

    output = [i.lhs.base.function for i in expressions if i.lhs.is_Indexed]
    output = filter_sorted(output, key=attrgetter('name'))

    indexeds = [i for i in terms if i.is_Indexed]
    dimensions = []
    for indexed in indexeds:
        for i in indexed.indices:
            dimensions.extend(
                [k for k in i.free_symbols if isinstance(k, Dimension)])
        dimensions.extend(list(indexed.base.function.indices))
    dimensions.extend([d.parent for d in dimensions if d.is_Stepping])
    dimensions = filter_sorted(dimensions, key=attrgetter('name'))

    return input, output, dimensions
예제 #11
0
파일: utils.py 프로젝트: italoaug/devito
    def is_time_invariant(mapper, expr):
        if any(
                isinstance(i, Dimension) and i.is_Time
                for i in expr.free_symbols):
            return False

        queue = [expr.rhs if expr.is_Equality else expr]
        seen = set()
        while queue:
            item = queue.pop()
            nodes = set()
            for i in retrieve_terminals(item):
                if i in seen:
                    # Already inspected, nothing more can be inferred
                    continue
                elif any(
                        isinstance(j, Dimension) and j.is_Time
                        for j in i.free_symbols):
                    # Definitely not time-invariant
                    return False
                elif i in mapper:
                    # Go on with the search
                    nodes.add(i)
                elif isinstance(i, Dimension):
                    # Go on with the search, as `i` is not a time dimension
                    pass
                elif not (i.function.is_DiscreteFunction
                          or i.function.is_Symbol and i.function.is_const):
                    # It didn't come from the outside and it's not in `mapper`, so
                    # cannot determine if time-invariant; assume time-varying then
                    return False
                seen.add(i)
            queue.extend([mapper[i].rhs for i in nodes])
        return True
예제 #12
0
def topological_sort(exprs):
    """Topologically sort the temporaries in a list of equations."""
    mapper = {e.lhs: e for e in exprs}
    assert len(mapper) == len(exprs)  # Expect SSA

    # Build DAG and topologically-sort temporaries
    temporaries, tensors = split(exprs, lambda e: not e.lhs.is_Indexed)
    dag = DAG(nodes=temporaries)
    for e in temporaries:
        for r in retrieve_terminals(e.rhs):
            if r not in mapper:
                continue
            elif mapper[r] is e:
                # Avoid cyclic dependences, such as
                # Eq(f, f + 1)
                continue
            elif r.is_Indexed:
                # Only scalars enforce an ordering
                continue
            else:
                dag.add_edge(mapper[r], e, force_add=True)
    processed = dag.topological_sort()

    # Append tensor equations at the end in user-provided order
    processed.extend(tensors)

    return processed
예제 #13
0
파일: graph.py 프로젝트: opesci/devito
 def unknown(self):
     """
     Return all symbols appearing in self for which a node is not available.
     """
     known = {v.function for v in self.values()}
     reads = set([i.function for i in
                  flatten(retrieve_terminals(v.rhs) for v in self.values())])
     return reads - known
 def unknown(self):
     """
     Return all symbols appearing in self for which a temporary is not available.
     """
     known = {v.function for v in self.values()}
     reads = set([i.base.function for i in
                  flatten(retrieve_terminals(v.rhs) for v in self.values())])
     return reads - known
예제 #15
0
파일: graph.py 프로젝트: opesci/devito
    def __init__(self, exprs, **kwargs):
        # Always convert to SSA
        exprs = makeit_ssa(exprs)
        mapper = OrderedDict([(i.lhs, i) for i in exprs])
        assert len(set(mapper)) == len(exprs), "not SSA Cluster?"

        # Construct the Nodes, tracking reads and readby
        tensor_map = DefaultOrderedDict(list)
        for i in mapper:
            tensor_map[as_symbol(i)].append(i)
        reads = DefaultOrderedDict(set)
        readby = DefaultOrderedDict(set)
        for k, v in mapper.items():
            handle = retrieve_terminals(v.rhs)
            for i in list(handle):
                if i.is_Indexed:
                    for idx in i.indices:
                        handle |= retrieve_terminals(idx)
            reads[k].update(set(flatten([tensor_map.get(as_symbol(i), [])
                                         for i in handle])))
            for i in reads[k]:
                readby[i].add(k)

        # Make sure read-after-writes are honored for scalar nodes
        processed = [i for i in mapper if i.is_Indexed]
        queue = [i for i in mapper if i not in processed]
        while queue:
            k = queue.pop(0)
            if not readby[k] or k in readby[k]:
                processed.insert(0, k)
            elif all(i in processed for i in readby[k]):
                index = min(processed.index(i) for i in readby[k])
                processed.insert(index, k)
            else:
                queue.append(k)

        # Build up the FlowGraph
        nodes = [(i, Node(mapper[i], reads=reads[i], readby=readby[i]))
                 for i in processed]
        super(FlowGraph, self).__init__(nodes, **kwargs)

        # Determine indices along the space and time dimensions
        terms = [v for k, v in self.items() if v.is_Tensor and not q_indirect(k)]
        indices = filter_ordered(flatten([i.function.indices for i in terms]))
        self.space_indices = tuple(i for i in indices if i.is_Space)
        self.time_indices = tuple(i for i in indices if i.is_Time)
예제 #16
0
def detect_io(exprs, relax=False):
    """
    ``{exprs} -> ({reads}, {writes})``

    Parameters
    ----------
    exprs : expr-like or list of expr-like
        The searched expressions.
    relax : bool, optional
        If False, as by default, collect only Constants and Functions.
        Otherwise, collect any Basic object.
    """
    exprs = as_tuple(exprs)
    if relax is False:
        rule = lambda i: i.is_Input
    else:
        rule = lambda i: i.is_Scalar or i.is_Tensor

    # Don't forget the nasty case with indirections on the LHS:
    # >>> u[t, a[x]] = f[x]  -> (reads={a, f}, writes={u})

    roots = []
    for i in exprs:
        try:
            roots.append(i.rhs)
            roots.extend(list(i.lhs.indices))
            roots.extend(list(i.conditionals.values()))
        except AttributeError:
            # E.g., FunctionFromPointer
            roots.append(i)

    reads = []
    terminals = flatten(retrieve_terminals(i, deep=True) for i in roots)
    for i in terminals:
        candidates = i.free_symbols
        try:
            candidates.update({i.function})
        except AttributeError:
            pass
        for j in candidates:
            try:
                if rule(j):
                    reads.append(j)
            except AttributeError:
                pass

    writes = []
    for i in exprs:
        try:
            f = i.lhs.function
        except AttributeError:
            continue
        if rule(f):
            writes.append(f)

    return filter_sorted(reads), filter_sorted(writes)
예제 #17
0
파일: utils.py 프로젝트: opesci/devito
def detect_io(exprs, relax=False):
    """
    ``{exprs} -> ({reads}, {writes})``

    Parameters
    ----------
    exprs : expr-like or list of expr-like
        The searched expressions.
    relax : bool, optional
        If False, as by default, collect only Constants and Functions.
        Otherwise, collect any Basic object.
    """
    exprs = as_tuple(exprs)
    if relax is False:
        rule = lambda i: i.is_Input
    else:
        rule = lambda i: i.is_Scalar or i.is_Tensor

    # Don't forget this nasty case, with indirections on the LHS:
    # >>> u[t, a[x]] = f[x]  -> (reads={a, f}, writes={u})

    roots = []
    for i in exprs:
        try:
            roots.append(i.rhs)
            roots.extend(list(i.lhs.indices))
        except AttributeError:
            # E.g., FunctionFromPointer
            roots.append(i)

    reads = []
    terminals = flatten(retrieve_terminals(i, deep=True) for i in roots)
    for i in terminals:
        candidates = i.free_symbols
        try:
            candidates.update({i.function})
        except AttributeError:
            pass
        for j in candidates:
            try:
                if rule(j):
                    reads.append(j)
            except AttributeError:
                pass

    writes = []
    for i in exprs:
        try:
            f = i.lhs.function
        except AttributeError:
            continue
        if rule(f):
            writes.append(f)

    return filter_sorted(reads), filter_sorted(writes)
예제 #18
0
    def __init__(self, expr, dtype=None):
        assert isinstance(expr, Eq)
        assert isinstance(expr.lhs, (Symbol, Indexed))
        self.expr = expr
        self.dtype = dtype

        # Traverse /expression/ to determine meta information
        # Note: at this point, expressions have already been indexified
        self.reads = [i for i in retrieve_terminals(self.expr.rhs)
                      if isinstance(i, (types.Indexed, types.Symbol))]
        self.reads = filter_ordered(self.reads)
        # Filter collected dimensions and functions
        self.dimensions = flatten(i.indices for i in self.functions)
        self.dimensions = filter_ordered(self.dimensions)
예제 #19
0
    def extract(cls, expr):
        """
        Compute the stencil of ``expr``.
        """
        assert expr.is_Equality

        # Collect all indexed objects appearing in /expr/
        terminals = retrieve_terminals(expr, mode='all')
        indexeds = [i for i in terminals if i.is_Indexed]
        indexeds += flatten([retrieve_indexed(i) for i in e.indices]
                            for e in indexeds)

        # Enforce deterministic dimension ordering...
        dims = OrderedDict()
        for e in terminals:
            if isinstance(e, Dimension):
                dims[(e, )] = e
            elif e.is_Indexed:
                d = []
                for a in e.indices:
                    found = [
                        i for i in a.free_symbols if isinstance(i, Dimension)
                    ]
                    d.extend([i for i in found if i not in d])
                dims[tuple(d)] = e
        # ... giving higher priority to TimeFunction objects; time always go first
        dims = sorted(
            list(dims),
            key=lambda i: not (isinstance(dims[i], Dimension) or dims[i].base.
                               function.is_TimeFunction))
        stencil = Stencil([(i, set()) for i in partial_order(dims)])

        # Determine the points accessed along each dimension
        for e in indexeds:
            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 += [i]
                if d is not None:
                    stencil[d].update(off)

        return stencil
예제 #20
0
    def __init__(self, exprs):
        """
        A Scope enables data dependence analysis on a totally ordered sequence
        of expressions.

        A Scope may be used only if IterationSpaces and Function's Dimensions
        follow the same ordering.  For example, given ``f(x, y, z)`` and ``g(x,
        y)``, the IterationSpace must be ``[x, y, z]`` (and not ``[x, z, y]``).
        In Devito, this is guaranteed by construction -- IterationSpaces are
        built from a deterministic partial ordering of Dimensions. This
        condition ensures that the lexicographic ordering of the iterations for
        the iteration vector ``(x, y, z)`` is ``(0, 0, 0), (0, 0, 1), ..., (0,
        1, 0), (0, 1, 1), ...``, which greatly simplifies the collection and
        classification of data dependences.
        """
        exprs = as_tuple(exprs)

        self.reads = {}
        self.writes = {}

        for i, e in enumerate(exprs):
            # Reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.function, [])
                mode = 'RI' if e.is_Increment and j.function is e.lhs.function else 'R'
                v.append(TimedAccess(j, mode, i, e.ispace))

            # Write
            v = self.writes.setdefault(e.lhs.function, [])
            mode = 'WI' if e.is_Increment else 'W'
            v.append(TimedAccess(e.lhs, mode, i, e.ispace))

            # If an increment, we got one implicit read
            if e.is_Increment:
                v = self.reads.setdefault(e.lhs.function, [])
                v.append(TimedAccess(e.lhs, 'RI', i, e.ispace))

        # The iterators read symbols too
        dimensions = set().union(*[e.dimensions for e in exprs])
        for d in dimensions:
            for j in d.symbolic_size.free_symbols:
                v = self.reads.setdefault(j.function, [])
                v.append(TimedAccess(j, 'R', -1))
예제 #21
0
def detect_io(exprs, relax=False):
    """
    ``{exprs} -> ({reads}, {writes})

    Parameters
    ----------
    exprs : expr-like or list of expr-like
        The searched expressions.
    relax : bool, optional
        If False, as by default, collect only :class:`Constant`s and
        :class:`Function`s. Otherwise, collect any :class:`types.Basic`s.
    """
    exprs = as_tuple(exprs)
    if relax is False:
        rule = lambda i: i.is_Input
    else:
        rule = lambda i: i.is_Scalar or i.is_Tensor

    reads = []
    for i in flatten(retrieve_terminals(i, deep=True) for i in exprs):
        candidates = i.free_symbols
        try:
            candidates.update({i.base.function})
        except AttributeError:
            pass
        for j in candidates:
            try:
                if rule(j):
                    reads.append(j)
            except AttributeError:
                pass

    writes = []
    for i in exprs:
        try:
            f = i.lhs.base.function
        except AttributeError:
            continue
        if rule(f):
            writes.append(f)

    return filter_sorted(reads), filter_sorted(writes)
예제 #22
0
파일: basic.py 프로젝트: skkamyab/devito
    def __init__(self, exprs):
        """
        A Scope represents a group of :class:`TimedAccess` objects extracted
        from some :class:`IREq` ``exprs``. The expressions must be provided
        in program order.
        """
        exprs = as_tuple(exprs)

        self.reads = {}
        self.writes = {}
        for i, e in enumerate(exprs):
            # reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.base.function, [])
                mode = 'R' if not q_inc(e) else 'RI'
                v.append(TimedAccess(j, mode, i, e.ispace.directions))
            # write
            v = self.writes.setdefault(e.lhs.base.function, [])
            mode = 'W' if not q_inc(e) else 'WI'
            v.append(TimedAccess(e.lhs, mode, i, e.ispace.directions))
예제 #23
0
    def __init__(self, exprs):
        """
        Initialize a Scope, which represents a group of :class:`Access` objects
        extracted from some expressions ``exprs``. The expressions are to be
        provided as they appear in program order.
        """
        exprs = as_tuple(exprs)
        assert all(isinstance(i, Eq) for i in exprs)

        self.reads = {}
        self.writes = {}
        for i, e in enumerate(exprs):
            # reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.base.function, [])
                mode = 'R' if not q_inc(e) else 'RI'
                v.append(TimedAccess(j, mode, i))
            # write
            v = self.writes.setdefault(e.lhs.base.function, [])
            mode = 'W' if not q_inc(e) else 'WI'
            v.append(TimedAccess(e.lhs, mode, i))
예제 #24
0
파일: graph.py 프로젝트: woxin5295/devito
    def time_invariant(self, expr=None):
        """
        Check if ``expr`` is time invariant. ``expr`` may be an expression ``e``
        explicitly tracked by the FlowGraph or even a generic subexpression
        of ``e``. If no ``expr`` is provided, then time invariance of the entire
        FlowGraph is assessed.
        """
        if expr is None:
            return all(self.time_invariant(v) for v in self.values())

        if any(q_timedimension(i) for i in expr.free_symbols):
            return False

        queue = [expr.rhs if expr.is_Equality else expr]
        seen = set()
        while queue:
            item = queue.pop()
            temporaries = set()
            for i in retrieve_terminals(item):
                if i in seen:
                    # Already inspected, nothing more can be inferred
                    continue
                elif any(
                        isinstance(j, Dimension) and j.is_Time
                        for j in i.free_symbols):
                    # Definitely not time-invariant
                    return False
                elif i in self:
                    # Go on with the search
                    temporaries.add(i)
                elif isinstance(i, Dimension):
                    # Go on with the search, as /i/ is not a time dimension
                    pass
                elif not i.base.function.is_TensorFunction:
                    # It didn't come from the outside and it's not in self, so
                    # cannot determine if time-invariant; assume time-varying
                    return False
                seen.add(i)
            queue.extend([self[i].rhs for i in temporaries])
        return True
예제 #25
0
파일: graph.py 프로젝트: opesci/devito
    def time_invariant(self, expr=None):
        """
        Check if ``expr`` is time invariant. ``expr`` may be an expression ``e``
        explicitly tracked by the FlowGraph or even a generic subexpression
        of ``e``. If no ``expr`` is provided, then time invariance of the entire
        FlowGraph is assessed.
        """
        if expr is None:
            return all(self.time_invariant(v) for v in self.values())

        if any(q_timedimension(i) for i in expr.free_symbols):
            return False

        queue = [expr.rhs if expr.is_Equality else expr]
        seen = set()
        while queue:
            item = queue.pop()
            nodes = set()
            for i in retrieve_terminals(item):
                if i in seen:
                    # Already inspected, nothing more can be inferred
                    continue
                elif any(isinstance(j, Dimension) and j.is_Time for j in i.free_symbols):
                    # Definitely not time-invariant
                    return False
                elif i in self:
                    # Go on with the search
                    nodes.add(i)
                elif isinstance(i, Dimension):
                    # Go on with the search, as /i/ is not a time dimension
                    pass
                elif not i.function.is_DiscreteFunction:
                    # It didn't come from the outside and it's not in self, so
                    # cannot determine if time-invariant; assume time-varying
                    return False
                seen.add(i)
            queue.extend([self[i].rhs for i in nodes])
        return True
예제 #26
0
def topological_sort(exprs):
    """Topologically sort a list of equations."""
    mapper = {e.lhs: e for e in exprs}
    assert len(mapper) == len(exprs)  # Expect SSA

    dag = DAG(nodes=exprs)
    for e in exprs:
        for r in retrieve_terminals(e.rhs):
            if r not in mapper:
                continue
            elif mapper[r] is e:
                # Avoid cyclic dependences, such as
                # Eq(f, f + 1)
                continue
            elif r.is_Indexed:
                # Only scalars enforce an ordering
                continue
            else:
                dag.add_edge(mapper[r], e, force_add=True)

    processed = dag.topological_sort()

    return processed
예제 #27
0
파일: graph.py 프로젝트: jrt54/devito
    def __init__(self, exprs, **kwargs):
        # Always convert to SSA
        exprs = makeit_ssa(exprs)
        mapper = OrderedDict([(i.lhs, i) for i in exprs])
        assert len(set(mapper)) == len(exprs), "not SSA Cluster?"

        # Construct the Nodes, tracking reads and readby
        tensor_map = DefaultOrderedDict(list)
        for i in mapper:
            tensor_map[as_symbol(i)].append(i)
        reads = DefaultOrderedDict(set)
        readby = DefaultOrderedDict(set)
        for k, v in mapper.items():
            handle = retrieve_terminals(v.rhs, deep=True)
            reads[k].update(
                set(flatten([tensor_map.get(as_symbol(i), [])
                             for i in handle])))
            for i in reads[k]:
                readby[i].add(k)

        # Make sure read-after-writes are honored for scalar nodes
        processed = [i for i in mapper if i.is_Indexed]
        queue = [i for i in mapper if i not in processed]
        while queue:
            k = queue.pop(0)
            if not readby[k] or k in readby[k]:
                processed.insert(0, k)
            elif all(i in processed for i in readby[k]):
                index = min(processed.index(i) for i in readby[k])
                processed.insert(index, k)
            else:
                queue.append(k)

        # Build up the FlowGraph
        nodes = [(i, Node(mapper[i], reads=reads[i], readby=readby[i]))
                 for i in processed]
        super(FlowGraph, self).__init__(nodes, **kwargs)
예제 #28
0
    def __init__(self, exprs):
        """
        A Scope represents a group of TimedAcces objects extracted
        from some IREq ``exprs``. The expressions must be provided
        in program order.
        """
        exprs = as_tuple(exprs)

        self.reads = {}
        self.writes = {}
        for i, e in enumerate(exprs):
            # reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.function, [])
                mode = 'RI' if e.is_Increment and j.function is e.lhs.function else 'R'
                v.append(TimedAccess(j, mode, i, e.ispace.directions))
            # write
            v = self.writes.setdefault(e.lhs.function, [])
            mode = 'WI' if e.is_Increment else 'W'
            v.append(TimedAccess(e.lhs, mode, i, e.ispace.directions))
            # if an increment, we got one implicit read
            if e.is_Increment:
                v = self.reads.setdefault(e.lhs.function, [])
                v.append(TimedAccess(e.lhs, 'RI', i, e.ispace.directions))
예제 #29
0
파일: basic.py 프로젝트: opesci/devito
    def __init__(self, exprs):
        """
        A Scope represents a group of TimedAcces objects extracted
        from some IREq ``exprs``. The expressions must be provided
        in program order.
        """
        exprs = as_tuple(exprs)

        self.reads = {}
        self.writes = {}
        for i, e in enumerate(exprs):
            # reads
            for j in retrieve_terminals(e.rhs):
                v = self.reads.setdefault(j.function, [])
                mode = 'RI' if e.is_Increment and j.function is e.lhs.function else 'R'
                v.append(TimedAccess(j, mode, i, e.ispace.directions))
            # write
            v = self.writes.setdefault(e.lhs.function, [])
            mode = 'WI' if e.is_Increment else 'W'
            v.append(TimedAccess(e.lhs, mode, i, e.ispace.directions))
            # if an increment, we got one implicit read
            if e.is_Increment:
                v = self.reads.setdefault(e.lhs.function, [])
                v.append(TimedAccess(e.lhs, 'RI', i, e.ispace.directions))