Example #1
0
def get_dims_and_symbol(expr):
    if isinstance(expr, Indexed):
        dims = tuple([(S.Zero, dim - 1) for dim in expr.shape])
        symbol = expr.base.label
    elif isinstance(expr, Symbol):
        dims = []
        symbol = expr
    elif isinstance(expr, MatrixSymbol):
        dims = tuple([(S.Zero, dim - 1) for dim in expr.shape if dim != 1])
        symbol = expr
    elif isinstance(expr, MatrixBase):
        # if we have a Matrix, we set line by line the code
        # useful when you have indexes like
        # A[i, j, 0] = B[i, j, 4]

        # todo: regarder que les matrices pour le in et out ont la meme taille
        # todo: regarder si le symbole est toujours le meme dans le terme de gauche (expr)
        for i in range(expr.shape[0]):
            symbol = expr[i].base.label
            dims = tuple([(S.Zero, dim - 1) for dim in expr[i].base.shape
                          if dim != 1])
    elif isinstance(expr, MatrixSlice):
        symbol = expr.parent
        dims = tuple([(S.Zero, dim - 1) for dim in symbol.shape if dim != 1])
    else:
        raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol "
                           "can define output arguments.")
    return dims, symbol
Example #2
0
    def _get_routine_opening(self, routine):
        """Returns the opening statements of the routine."""
        code_list = []
        export = True
        # export = self.settings.pop('export', True)
        if export:
            code_list.append("def ")
        else:
            code_list.append("cdef void ")

        # Inputs
        args = []
        for i, arg in enumerate(routine.arguments):
            if isinstance(arg, OutputArgument):
                raise CodeGenError("Cython: invalid argument of type %s" %
                                   str(type(arg)))

            if isinstance(arg, (InputArgument, InOutArgument)):
                name = self._get_symbol(arg.name)
                if not arg.dimensions:
                    # If it is a scalar
                    if isinstance(arg, ResultBase):
                        # if it is an output
                        args.append((arg.get_datatype('C'), "*%s" % name))
                    else:
                        # if it is an output
                        args.append((arg.get_datatype('C'), name))
                else:
                    if not export and len(arg.dimensions) == 1:
                        # if the dimension is 1
                        args.append((arg.get_datatype('C'), "*%s" % name))
                    else:
                        args.append(
                            (arg.get_datatype('C') + '[' +
                             ', '.join([':'] * len(arg.dimensions)) + ':1]',
                             "%s" % name))

        args = ", ".join(["%s %s" % t for t in args])
        code_list.append("%s(%s)%s\n" %
                         (routine.name, args, ":" if export else " nogil:"))
        code_list = ["".join(code_list)]

        return code_list
Example #3
0
    def _get_routine_opening(self, routine):
        """Returns the opening statements of the routine."""
        code_list = []
        code_list.append("def ")

        # Inputs
        args = []
        for i, arg in enumerate(routine.arguments):
            if isinstance(arg, OutputArgument):
                raise CodeGenError("Numpy: invalid argument of type %s" %
                                   str(type(arg)))

            if isinstance(arg, (InputArgument, InOutArgument)):
                name = self._get_symbol(arg.name)
                args.append(name)
        args = ", ".join(args)
        code_list.append("%s(%s):\n" % (routine.name, args))
        code_list = ["".join(code_list)]

        return code_list
Example #4
0
    def routine(self, name, expr, argument_sequence, global_vars):
        """Creates an Routine object that is appropriate for this language.

        This implementation is appropriate for at least C/Fortran.  Subclasses
        can override this if necessary.

        Here, we assume at most one return value (the l-value) which must be
        scalar.  Additional outputs are OutputArguments (e.g., pointers on
        right-hand-side or pass-by-reference).  Matrices are always returned
        via OutputArguments.  If ``argument_sequence`` is None, arguments will
        be ordered alphabetically, but with all InputArguments first, and then
        OutputArgument and InOutArguments.

        This implementation is almost the same as the CodeGen class, but
        expensive calls to Basic.atoms() have been replaced with
        cheaper equivalents.

        """

        if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)):
            if not expr:
                raise ValueError("No expression given")
            expressions = Tuple(*expr)
        else:
            expressions = Tuple(expr)

        expr_free_symbols = expressions.free_symbols

        # local variables
        local_vars = {i.label for i in expr_free_symbols if isinstance(i, Idx)}

        # global variables
        global_vars = set() if global_vars is None else set(global_vars)

        # symbols that should be arguments
        symbols = expr_free_symbols - local_vars - global_vars
        new_symbols = set([])
        new_symbols.update(symbols)

        for symbol in symbols:
            if isinstance(symbol, Idx):
                new_symbols.remove(symbol)
                new_symbols.update(symbol.args[1].free_symbols)
            if isinstance(symbol, Indexed):
                new_symbols.remove(symbol)
        symbols = new_symbols

        # Decide whether to use output argument or return value
        return_val = []
        output_args = []
        for expr in expressions:
            if isinstance(expr, Equality):
                out_arg = expr.lhs
                expr = expr.rhs
                if isinstance(out_arg, Indexed):
                    dims = tuple([ (S.Zero, dim - 1) for dim in out_arg.shape])
                    symbol = out_arg.base.label
                elif isinstance(out_arg, Symbol):
                    dims = []
                    symbol = out_arg
                elif isinstance(out_arg, MatrixSymbol):
                    dims = tuple([ (S.Zero, dim - 1) for dim in out_arg.shape])
                    symbol = out_arg
                else:
                    raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol "
                                       "can define output arguments.")

                if expr.has(symbol):
                    output_args.append(
                        InOutArgument(symbol, out_arg, expr, dimensions=dims))
                else:
                    output_args.append(
                        OutputArgument(symbol, out_arg, expr, dimensions=dims))

                # avoid duplicate arguments
                symbols.remove(symbol)
            elif isinstance(expr, (ImmutableMatrix, MatrixSlice)):
                # Create a "dummy" MatrixSymbol to use as the Output arg
                out_arg = MatrixSymbol('out_%s' % abs(hash(expr)), *expr.shape)
                dims = tuple([(S.Zero, dim - 1) for dim in out_arg.shape])
                output_args.append(
                    OutputArgument(out_arg, out_arg, expr, dimensions=dims))
            else:
                return_val.append(Result(expr))

        arg_list = []

        # setup input argument list
        array_symbols = {}
        for array in [i for i in expr_free_symbols if isinstance(i, Indexed)]:
            array_symbols[array.base.label] = array
        for array in [i for i in expr_free_symbols if isinstance(i, MatrixSymbol)]:
            array_symbols[array] = array

        for symbol in sorted(symbols, key=str):
            if symbol in array_symbols:
                dims = []
                array = array_symbols[symbol]
                for dim in array.shape:
                    dims.append((S.Zero, dim - 1))
                metadata = {'dimensions': dims}
            else:
                metadata = {}

            arg_list.append(InputArgument(symbol, **metadata))

        output_args.sort(key=lambda x: str(x.name))
        arg_list.extend(output_args)

        if argument_sequence is not None:
            # if the user has supplied IndexedBase instances, we'll accept that
            new_sequence = []
            for arg in argument_sequence:
                if isinstance(arg, IndexedBase):
                    new_sequence.append(arg.label)
                else:
                    new_sequence.append(arg)
            argument_sequence = new_sequence

            missing = [x for x in arg_list if x.name not in argument_sequence]
            if missing:
                msg = "Argument list didn't specify: {0} "
                msg = msg.format(", ".join([str(m.name) for m in missing]))
                raise CodeGenArgumentListError(msg, missing)

            # create redundant arguments to produce the requested sequence
            name_arg_dict = {x.name: x for x in arg_list}
            new_args = []
            for symbol in argument_sequence:
                try:
                    new_args.append(name_arg_dict[symbol])
                except KeyError:
                    new_args.append(InputArgument(symbol))
            arg_list = new_args

        return Routine(name, arg_list, return_val, local_vars, global_vars)
Example #5
0
    def _get_routine_ending(self, routine):
        code_list = []
        code_list.append('""",')

        # Inputs
        args = []
        dtypes = []
        for i, arg in enumerate(routine.arguments):
            if isinstance(arg, OutputArgument):
                raise CodeGenError("Loopy: invalid argument of type %s" %
                                   str(type(arg)))

            if isinstance(arg, (InputArgument, InOutArgument)):
                name = self._get_symbol(arg.name)
                if arg.dimensions:
                    dims = [
                        "{}".format(d[1] - d[0] + 1) for d in arg.dimensions
                    ]
                    dtype = arg.get_datatype('PYTHON')
                    if dtype == 'int':
                        dtype = 'np.int32'
                    args.append(
                        'lp.GlobalArg("{name}", dtype={dtype}, shape="{shape}")'
                        .format(name=name, dtype=dtype, shape=", ".join(dims)))
                else:
                    args.append('lp.ValueArg("{name}", dtype={dtype})'.format(
                        name=name, dtype=arg.get_datatype('PYTHON')))
        for i, arg in enumerate(routine.local_vars):
            if isinstance(arg, Symbol):
                args.append(
                    'lp.TemporaryVariable("{name}", dtype=float)'.format(
                        name=self._get_symbol(arg)))
            else:
                dims = [d for d in arg.shape if d != 1]
                args.append(
                    'lp.TemporaryVariable("{name}", dtype=float, shape="{shape}")'
                    .format(name=self._get_symbol(arg),
                            shape=','.join("%s" % s for s in dims)))

        code_list.append('[')
        args = ",\n".join(args)
        code_list.append(args)
        code_list.append('])#endArg\n')

        # add type
        dim = len(routine.idx_vars)
        if dim == 1:
            block_size = [256]
        if dim == 2:
            block_size = [16, 16]
        if dim == 3:
            block_size = [4, 4, 4]

        for i, idx in enumerate(routine.idx_vars[-1::-1]):
            code_list.append(
                '{name} = lp.split_iname({name}, "{label}", {block}, outer_tag="g.{ilabel}", inner_tag="l.{ilabel}")'
                .format(name=routine.name,
                        label="%s_" % idx.label,
                        ilabel=i,
                        block=block_size[i]))
        code_list.append(
            '{name} = lp.expand_subst({name})\n'.format(name=routine.name))
        code_list.append(
            '{name} = lp.set_options({name}, no_numpy = True)\n'.format(
                name=routine.name))

        prefetch = routine.settings.get("prefetch", None)

        if prefetch:
            for var in prefetch:
                indices = []
                for idx in routine.idx_vars:
                    indices.append("%s__inner" % idx.label)
                # for i in range(var.rank):
                #     if isinstance(var.indices[i], Idx):
                #         indices.append("%s__inner"%var.indices[i].label)
                code_list.append(
                    '{name} = lp.add_prefetch({name}, "{var}", "{label}", fetch_bounding_box=True)\n'
                    .format(name=routine.name,
                            var=var.base.label,
                            label=",".join(indices)))


#            print("PREFETCH")
#     label = []
#     for var in self._settings["prefetch"]:
#         indices = []
#         for i in var.indices:
#             if isinstance(i, Idx):
#                 indices.append("%s__inner"%i.label)
#         code_list.append('{name} = lp.add_prefetch({name}, "{var}", "{label}", fetch_bounding_box=True)'.format(name=routine.name, var=var.label, label=",".join(indices)))
#print(LoopyCodePrinter()._sort_optimized(routine.local_vars, routine.instructions))
# one_time_step = lp.split_iname(one_time_step, "ii", 16, outer_tag="g.1", inner_tag="l.1")
# one_time_step = lp.split_iname(one_time_step, "jj", 16, outer_tag="g.0", inner_tag="l.0")
# one_time_step = lp.expand_subst(one_time_step)
# one_time_step = lp.add_prefetch(one_time_step, "f", "ii_inner,jj_inner", fetch_bounding_box=True)
        code_list = ["\n".join(code_list)]
        return code_list