def new_ops_arg(self, indexed, is_write): """ Create an Indexed node using OPS representation. Parameters ---------- indexed : Indexed Indexed object using devito representation. Returns ------- Indexed Indexed node using OPS representation. """ # Build the OPS arg identifier time_index = split_affine(indexed.indices[TimeFunction._time_position]) ops_arg_id = ('%s%s%s' % (indexed.name, time_index.var, time_index.shift) if indexed.function.is_TimeFunction else indexed.name) if ops_arg_id not in self.ops_args: symbol_to_access = OpsAccessible( ops_arg_id, dtype=indexed.dtype, read_only=not is_write ) accessible_info = AccessibleInfo( symbol_to_access, time_index.var if indexed.function.is_TimeFunction else None, time_index.shift if indexed.function.is_TimeFunction else None, indexed.function.name) self.ops_args[ops_arg_id] = accessible_info self.ops_params.append(symbol_to_access) else: symbol_to_access = self.ops_args[ops_arg_id].accessible # Get the space indices space_indices = [ split_affine(i).shift for i in indexed.indices if isinstance(split_affine(i).var, SpaceDimension) ] if space_indices not in self.ops_args_accesses[symbol_to_access]: self.ops_args_accesses[symbol_to_access].append(space_indices) return OpsAccess(symbol_to_access, space_indices)
def new_ops_arg(self, indexed): """ Create an :class:`Indexed` node using OPS representation. Parameters ---------- indexed : :class:`Indexed` Indexed object using devito representation. Returns ------- :class:`Indexed` Indexed node using OPS representation. """ # Build the OPS arg identifier time_index = split_affine(indexed.indices[TimeFunction._time_position]) ops_arg_id = '%s%s%s' % (indexed.name, time_index.var, time_index.shift) if ops_arg_id not in self.ops_args: # Create the indexed object ops_arg = Array(name=ops_arg_id, dimensions=[Dimension(name=namespace['ops_acc'])], dtype=indexed.dtype) self.ops_args[ops_arg_id] = ops_arg else: ops_arg = self.ops_args[ops_arg_id] # Get the space indices space_indices = [ e for i, e in enumerate(indexed.indices) if i != TimeFunction._time_position ] # Define the Macro used in OPS arg index access_macro = Macro( 'OPS_ACC%d(%s)' % (list(self.ops_args).index(ops_arg_id), ','.join( str(split_affine(i).shift) for i in space_indices))) # Create Indexed object representing the OPS arg access new_indexed = Indexed(ops_arg.indexed, access_macro) return new_indexed
def new_ops_arg(self, indexed): """ Create an :class:`Indexed` node using OPS representation. Parameters ---------- indexed : :class:`Indexed` Indexed object using devito representation. Returns ------- :class:`Indexed` Indexed node using OPS representation. """ # Build the OPS arg identifier time_index = split_affine(indexed.indices[TimeFunction._time_position]) ops_arg_id = '%s%s%s' % (indexed.name, time_index.var, time_index.shift) if ops_arg_id not in self.ops_args: # Create the indexed object ops_arg = Array(name=ops_arg_id, dimensions=[Dimension(name=namespace['ops_acc'])], dtype=indexed.dtype) self.ops_args[ops_arg_id] = ops_arg else: ops_arg = self.ops_args[ops_arg_id] # Get the space indices space_indices = [e for i, e in enumerate( indexed.indices) if i != TimeFunction._time_position] # Define the Macro used in OPS arg index access_macro = Macro('OPS_ACC%d(%s)' % (list(self.ops_args).index(ops_arg_id), ','.join(str(split_affine(i).shift) for i in space_indices))) # Create Indexed object representing the OPS arg access new_indexed = Indexed(ops_arg.indexed, access_macro) return new_indexed
def handle_indexed(indexed): relation = [] for i in indexed.indices: try: maybe_dim = split_affine(i).var if isinstance(maybe_dim, Dimension): relation.append(maybe_dim) except ValueError: # Maybe there are some nested Indexeds (e.g., the situation is A[B[i]]) nested = flatten(handle_indexed(n) for n in retrieve_indexed(i)) if nested: relation.extend(nested) else: # Fallback: Just insert all the Dimensions we find, regardless of # what the user is attempting to do relation.extend([d for d in filter_sorted(i.free_symbols) if isinstance(d, Dimension)]) return tuple(relation)
def handle_indexed(indexed): relation = [] for i in indexed.indices: try: maybe_dim = split_affine(i).var if isinstance(maybe_dim, Dimension): relation.append(maybe_dim) except ValueError: # Maybe there are some nested Indexeds (e.g., the situation is A[B[i]]) nested = flatten(handle_indexed(n) for n in retrieve_indexed(i)) if nested: relation.extend(nested) else: # Fallback: Just insert all the Dimensions we find, regardless of # what the user is attempting to do relation.extend([d for d in filter_sorted(i.free_symbols) if isinstance(d, Dimension)]) return tuple(relation)
def make_yask_ast(expr, yc_soln, mapper): def nary2binary(args, op): r = make_yask_ast(args[0], yc_soln, mapper) return r if len(args) == 1 else op(r, nary2binary(args[1:], op)) if expr.is_Integer: return nfac.new_const_number_node(int(expr)) elif expr.is_Float: return nfac.new_const_number_node(float(expr)) elif expr.is_Rational: a, b = expr.as_numer_denom() return nfac.new_const_number_node(float(a)/float(b)) elif expr.is_Symbol: function = expr.function if function.is_Constant: if function not in mapper: mapper[function] = yc_soln.new_grid(function.name, []) return mapper[function].new_grid_point([]) elif function.is_Dimension: if expr.is_Time: return nfac.new_step_index(expr.name) elif expr.is_Space: return nfac.new_domain_index(expr.name) else: return nfac.new_misc_index(expr.name) else: # A DSE-generated temporary, which must have already been # encountered as a LHS of a previous expression assert function in mapper return mapper[function] elif expr.is_Indexed: # Create a YASK compiler grid if it's the first time we encounter a Function function = expr.function if function not in mapper: dimensions = [make_yask_ast(i, yc_soln, mapper) for i in function.indices] mapper[function] = yc_soln.new_grid(function.name, dimensions) # Convert the Indexed into a YASK grid access indices = [] for i in expr.indices: if i.is_integer: # Typically, if we end up here it's because we have a misc dimension indices.append(make_yask_ast(i, yc_soln, mapper)) else: # We must always use the parent ("main") dimension when creating # YASK expressions af = split_affine(i) dim = af.var.parent if af.var.is_Derived else af.var indices.append(make_yask_ast(dim + af.shift, yc_soln, mapper)) return mapper[function].new_grid_point(indices) elif expr.is_Add: return nary2binary(expr.args, nfac.new_add_node) elif expr.is_Mul: return nary2binary(expr.args, nfac.new_multiply_node) elif expr.is_Pow: base, exp = expr.as_base_exp() if not exp.is_integer: raise NotImplementedError("Non-integer powers unsupported in " "Devito-YASK translation") if int(exp) < 0: num, den = expr.as_numer_denom() return nfac.new_divide_node(make_yask_ast(num, yc_soln, mapper), make_yask_ast(den, yc_soln, mapper)) elif int(exp) >= 1: return nary2binary([base] * exp, nfac.new_multiply_node) else: warning("0-power found in Devito-YASK translation? setting to 1") return nfac.new_const_number_node(1) elif expr.is_Equality: if expr.lhs.is_Symbol: function = expr.lhs.base.function assert function not in mapper mapper[function] = make_yask_ast(expr.rhs, yc_soln, mapper) else: return nfac.new_equation_node(*[make_yask_ast(i, yc_soln, mapper) for i in expr.args]) else: raise NotImplementedError("Missing handler in Devito-YASK translation")