def __new__(cls, *args, **kwargs): if len(args) == 1 and isinstance(args[0], LoweredEq): # origin: LoweredEq(devito.LoweredEq, **kwargs) input_expr = args[0] expr = sympy.Eq.__new__(cls, *input_expr.args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.get(i) or getattr(input_expr, i)) return expr elif len(args) == 1 and isinstance(args[0], Eq): # origin: LoweredEq(devito.Eq) input_expr = expr = args[0] elif len(args) == 2: expr = sympy.Eq.__new__(cls, *args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.pop(i)) return expr else: raise ValueError("Cannot construct LoweredEq from args=%s " "and kwargs=%s" % (str(args), str(kwargs))) # Well-defined dimension ordering ordering = dimension_sort(expr) # Analyze the expression mapper = detect_accesses(expr) oobs = detect_oobs(mapper) conditionals = [i for i in ordering if i.is_Conditional] # The iteration space is constructed so that information always flows # from an iteration to another (i.e., no anti-dependences are created) directions, _ = force_directions(detect_flow_directions(expr), lambda i: Any) iterators = build_iterators(mapper) intervals = build_intervals(Stencil.union(*mapper.values())) intervals = IntervalGroup(intervals, relations=ordering.relations) ispace = IterationSpace(intervals.zero(), iterators, directions) # The data space is relative to the computational domain. Note that we # are deliberately dropping the intervals ordering (by turning `intervals` # into a list), as this is irrelevant (even more: dangerous) for data spaces intervals = [i if i.dim in oobs else i.zero() for i in intervals] intervals += [Interval(i, 0, 0) for i in ordering if i not in ispace.dimensions + conditionals] parts = {k: IntervalGroup(build_intervals(v)) for k, v in mapper.items() if k} dspace = DataSpace(intervals, parts) # Finally create the LoweredEq with all metadata attached expr = super(LoweredEq, cls).__new__(cls, expr.lhs, expr.rhs, evaluate=False) expr._dspace = dspace expr._ispace = ispace expr._conditionals = tuple(conditionals) expr._reads, expr._writes = detect_io(expr) expr._is_Increment = input_expr.is_Increment expr._implicit_dims = input_expr.implicit_dims return expr
def __new__(cls, *args, **kwargs): if len(args) == 1 and isinstance(args[0], LoweredEq): # origin: LoweredEq(devito.LoweredEq, **kwargs) input_expr = args[0] expr = Eq.__new__(cls, *input_expr.args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.get(i) or getattr(input_expr, i)) return expr elif len(args) == 1 and isinstance(args[0], Eq): # origin: LoweredEq(sympy.Eq) input_expr = expr = args[0] elif len(args) == 2: expr = Eq.__new__(cls, *args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.pop(i)) return expr else: raise ValueError("Cannot construct LoweredEq from args=%s " "and kwargs=%s" % (str(args), str(kwargs))) # Well-defined dimension ordering ordering = dimension_sort(expr) # Analyze the expression mapper = detect_accesses(expr) oobs = detect_oobs(mapper) conditionals = [i for i in ordering if i.is_Conditional] # The iteration space is constructed so that information always flows # from an iteration to another (i.e., no anti-dependences are created) directions, _ = force_directions(detect_flow_directions(expr), lambda i: Any) iterators = build_iterators(mapper) intervals = build_intervals(Stencil.union(*mapper.values())) intervals = IntervalGroup(intervals, relations=ordering.relations) ispace = IterationSpace(intervals.zero(), iterators, directions) # The data space is relative to the computational domain. Note that we # are deliberately dropping the intervals ordering (by turning `intervals` # into a list), as this is irrelevant (even more: dangerous) for data spaces intervals = [i if i.dim in oobs else i.zero() for i in intervals] intervals += [Interval(i, 0, 0) for i in ordering if i not in ispace.dimensions + conditionals] parts = {k: IntervalGroup(build_intervals(v)) for k, v in mapper.items() if k} dspace = DataSpace(intervals, parts) # Finally create the LoweredEq with all metadata attached expr = super(LoweredEq, cls).__new__(cls, expr.lhs, expr.rhs, evaluate=False) expr._is_Increment = getattr(input_expr, 'is_Increment', False) expr._dspace = dspace expr._ispace = ispace expr._conditionals = tuple(conditionals) expr._reads, expr._writes = detect_io(expr) return expr
def test_dimension_sort(self, expr, expected): """ Tests that ``dimension_sort()`` provides meaningful Dimension orderings. """ grid = Grid(shape=(10, 10)) p = Dimension('p') r = Dimension('r') d = Dimension('d') time = grid.time_dim # noqa x, y = grid.dimensions a = Function(name='a', dimensions=(time, p), shape=(10, 1)) # noqa b = Function(name='b', dimensions=(time, x, y), shape=(10, 10, 10)) # noqa c = Function(name='c', shape=(1, 2), # noqa dimensions=(p, d), dtype=np.int32) f = Function(name='f', dimensions=(p, r), shape=(1, 1)) # noqa expr = eval(expr) assert list(dimension_sort(expr)) == eval(expected)
def test_dimension_sort(self, expr, expected): """ Tests that ``dimension_sort()`` provides meaningful :class:`Dimension` orderings. """ grid = Grid(shape=(10, 10)) p = Dimension('p') r = Dimension('r') d = Dimension('d') time = grid.time_dim # noqa x, y = grid.dimensions a = Function(name='a', dimensions=(time, p), shape=(10, 1)) # noqa b = Function(name='b', dimensions=(time, x, y), shape=(10, 10, 10)) # noqa c = Function(name='c', shape=(1, 2), # noqa dimensions=(p, d), dtype=np.int32) f = Function(name='f', dimensions=(p, r), shape=(1, 1)) # noqa expr = eval(expr) assert list(dimension_sort(expr)) == eval(expected)
def __new__(cls, *args, **kwargs): if len(args) == 1 and isinstance(args[0], LoweredEq): # origin: LoweredEq(devito.LoweredEq, **kwargs) input_expr = args[0] expr = sympy.Eq.__new__(cls, *input_expr.args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.get(i) or getattr(input_expr, i)) return expr elif len(args) == 1 and isinstance(args[0], Eq): # origin: LoweredEq(devito.Eq) input_expr = expr = args[0] elif len(args) == 2: expr = sympy.Eq.__new__(cls, *args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.pop(i)) return expr else: raise ValueError("Cannot construct LoweredEq from args=%s " "and kwargs=%s" % (str(args), str(kwargs))) # Well-defined dimension ordering ordering = dimension_sort(expr) # Analyze the expression mapper = detect_accesses(expr) oobs = detect_oobs(mapper) conditionals = [i for i in ordering if i.is_Conditional] # Construct Intervals for IterationSpace and DataSpace intervals = build_intervals(Stencil.union(*mapper.values())) iintervals = [] # iteration Intervals dintervals = [] # data Intervals for i in intervals: d = i.dim if d in oobs: iintervals.append(i.zero()) dintervals.append(i) else: iintervals.append(i.zero()) dintervals.append(i.zero()) # Construct the IterationSpace iintervals = IntervalGroup(iintervals, relations=ordering.relations) iterators = build_iterators(mapper) ispace = IterationSpace(iintervals, iterators) # Construct the DataSpace dintervals.extend([ Interval(i, 0, 0) for i in ordering if i not in ispace.dimensions + conditionals ]) parts = { k: IntervalGroup(build_intervals(v)).add(iintervals) for k, v in mapper.items() if k } dspace = DataSpace(dintervals, parts) # Lower all Differentiable operations into SymPy operations rhs = diff2sympy(expr.rhs) # Finally create the LoweredEq with all metadata attached expr = super(LoweredEq, cls).__new__(cls, expr.lhs, rhs, evaluate=False) expr._dspace = dspace expr._ispace = ispace expr._conditionals = tuple(conditionals) expr._reads, expr._writes = detect_io(expr) expr._is_Increment = input_expr.is_Increment expr._implicit_dims = input_expr.implicit_dims return expr
def __new__(cls, *args, **kwargs): if len(args) == 1 and isinstance(args[0], LoweredEq): # origin: LoweredEq(devito.LoweredEq, **kwargs) input_expr = args[0] expr = sympy.Eq.__new__(cls, *input_expr.args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.get(i) or getattr(input_expr, i)) return expr elif len(args) == 1 and isinstance(args[0], Eq): # origin: LoweredEq(devito.Eq) input_expr = expr = args[0] elif len(args) == 2: expr = sympy.Eq.__new__(cls, *args, evaluate=False) for i in cls._state: setattr(expr, '_%s' % i, kwargs.pop(i)) return expr else: raise ValueError("Cannot construct LoweredEq from args=%s " "and kwargs=%s" % (str(args), str(kwargs))) # Well-defined dimension ordering ordering = dimension_sort(expr) # Analyze the expression accesses = detect_accesses(expr) dimensions = Stencil.union(*accesses.values()) # Separate out the SubIterators from the main iteration Dimensions, that # is those which define an actual iteration space iterators = {} for d in dimensions: if d.is_SubIterator: iterators.setdefault(d.root, set()).add(d) elif d.is_Conditional: # Use `parent`, and `root`, because a ConditionalDimension may # have a SubDimension as parent iterators.setdefault(d.parent, set()) else: iterators.setdefault(d, set()) # Construct the IterationSpace intervals = IntervalGroup([Interval(d, 0, 0) for d in iterators], relations=ordering.relations) ispace = IterationSpace(intervals, iterators) # Construct the conditionals and replace the ConditionalDimensions in `expr` conditionals = {} for d in ordering: if not d.is_Conditional: continue if d.condition is None: conditionals[d] = GuardFactor(d) else: conditionals[d] = diff2sympy(lower_exprs(d.condition)) if d.factor is not None: expr = uxreplace(expr, {d: IntDiv(d.index, d.factor)}) conditionals = frozendict(conditionals) # Lower all Differentiable operations into SymPy operations rhs = diff2sympy(expr.rhs) # Finally create the LoweredEq with all metadata attached expr = super(LoweredEq, cls).__new__(cls, expr.lhs, rhs, evaluate=False) expr._ispace = ispace expr._conditionals = conditionals expr._reads, expr._writes = detect_io(expr) expr._is_Increment = input_expr.is_Increment expr._implicit_dims = input_expr.implicit_dims return expr
def __new__(cls, *args, **kwargs): if len(args) == 1: # origin: LoweredEq(expr) expr = input_expr = args[0] assert not isinstance(expr, LoweredEq) and isinstance(expr, Eq) elif len(args) == 2: # origin: LoweredEq(lhs, rhs, stamp=...) stamp = kwargs.pop('stamp') expr = Eq.__new__(cls, *args, evaluate=False) assert isinstance(stamp, Eq) expr.is_Increment = stamp.is_Increment expr._ispace, expr._dspace = stamp.ispace, stamp.dspace expr.reads, expr.writes = stamp.reads, stamp.writes return expr elif len(args) == 5: # origin: LoweredEq(expr, ispace, space) input_expr, ispace, dspace, reads, writes = args assert isinstance(ispace, IterationSpace) and isinstance(dspace, DataSpace) expr = Eq.__new__(cls, *input_expr.args, evaluate=False) expr.is_Increment = input_expr.is_Increment expr._ispace, expr._dspace = ispace, dspace expr.reads, expr.writes = reads, writes return expr else: raise ValueError("Cannot construct LoweredEq from args=%s " "and kwargs=%s" % (str(args), str(kwargs))) # Well-defined dimension ordering ordering = dimension_sort(expr, key=lambda i: not i.is_Time) # Introduce space sub-dimensions if need to region = getattr(input_expr, '_region', DOMAIN) if region == INTERIOR: mapper = {i: SubDimension.middle("%si" % i, i, 1, 1) for i in ordering if i.is_Space} expr = expr.xreplace(mapper) for k, v in mapper.items(): ordering.insert(ordering.index(k) + 1, v) # Analyze the expression mapper = detect_accesses(expr) oobs = detect_oobs(mapper) # The iteration space is constructed so that information always flows # from an iteration to another (i.e., no anti-dependences are created) directions, _ = force_directions(detect_flow_directions(expr), lambda i: Any) iterators = build_iterators(mapper) intervals = build_intervals(Stencil.union(*mapper.values())) intervals = sorted(intervals, key=lambda i: ordering.index(i.dim)) ispace = IterationSpace([i.zero() for i in intervals], iterators, directions) # The data space is relative to the computational domain intervals = [i if i.dim in oobs else i.zero() for i in intervals] intervals += [Interval(i, 0, 0) for i in ordering if i not in ispace.dimensions] parts = {k: IntervalGroup(build_intervals(v)) for k, v in mapper.items() if k} dspace = DataSpace(intervals, parts) # Finally create the LoweredEq with all metadata attached expr = super(LoweredEq, cls).__new__(cls, expr.lhs, expr.rhs, evaluate=False) expr.is_Increment = getattr(input_expr, 'is_Increment', False) expr._dspace = dspace expr._ispace = ispace expr.reads, expr.writes = detect_io(expr) return expr