예제 #1
0
    def is_equivalent(self, other):
        if not isinstance(other, Stream):
            return False

        # Test type
        if self.dtype != other.dtype:
            return False

        # Test dimensionality
        if len(self.shape) != len(other.shape):
            return False

        # Test shape
        for dim, otherdim in zip(self.shape, other.shape):
            # If both are symbols, ensure equality
            if symbolic.issymbolic(dim) and symbolic.issymbolic(otherdim):
                if dim != otherdim:
                    return False

            # If one is a symbol and the other is a constant
            # make sure they are equivalent
            elif symbolic.issymbolic(otherdim):
                if symbolic.eval(otherdim) != dim:
                    return False
            elif symbolic.issymbolic(dim):
                if symbolic.eval(dim) != otherdim:
                    return False
            else:
                # Any other case (constant vs. constant), check for equality
                if otherdim != dim:
                    return False
        return True
예제 #2
0
파일: ndarray.py 프로젝트: cpenny42/dace
 def update_resolved_symbol(self, sym):
     """ Notifies an array that a symbol has been resolved so that it
         can be resized. """
     self.resize(
         [symbolic.eval(s, 0) for s in self.descriptor.shape],
         refcheck=False)
     self._symlist = symbolic.symlist(self.descriptor.shape)
예제 #3
0
def ndarray(shape, dtype=numpy.float64, *args, **kwargs):
    """ Returns a numpy ndarray where all symbols have been evaluated to
        numbers and types are converted to numpy types. """

    new_shape = [symbolic.eval(s) for s in shape]
    new_dtype = dtype.type if isinstance(dtype, dtypes.typeclass) else dtype
    return numpy.ndarray(shape=new_shape, dtype=new_dtype, *args, **kwargs)
예제 #4
0
파일: ndarray.py 프로젝트: cpenny42/dace
    def __new__(cls,
                shape,
                dtype=types.float32,
                materialize_func=None,
                allow_conflicts=False,
                *args,
                **kwargs):
        """ Initializes a DaCe ND-array.
            @param shape: The array shape (may contain symbols).
            @param dtype: The array data type.
            @param materialize_func: An optional string that contains a method
                                     to materialize array contents on demand.
                                     If not None, the array is not allocated 
                                     within the DaCe program.
            @param allow_conflicts: If True, suppresses warnings on conflicting
                                    array writes in DaCe programs without a 
                                    matching conflict resolution memlet.
        """
        # Avoiding import loops
        from dace import data

        tmpshape = shape
        shape = [symbolic.eval(s, 0) for s in shape]

        kwargs.update({'dtype': dtype.type})

        res = numpy.ndarray.__new__(cls, shape, *args, **kwargs)
        res._symlist = symbolic.symlist(tmpshape)
        for _, sym in res._symlist.items():
            sym._arrays_to_update.append(res)

        if not isinstance(dtype, types.typeclass):
            dtype = types.typeclass(dtype.type)

        res.descriptor = data.Array(
            dtype,
            tmpshape,
            materialize_func=materialize_func,
            transient=False,
            allow_conflicts=allow_conflicts)
        return res
예제 #5
0
def simulate(dace_program: DaceProgram, *args):
    """ Simulate a DaCe program using Python. 
        :param dace_program: A program function annotated with `@dace.program`.
        :param *args: Program arguments to pass.
    """
    pdp, modules = dace_program.generate_pdp()

    # Transform the decorated AST into working python code (annotated so
    # that debugging works)
    simulated_ast = SimulatorTransformer(pdp).visit(pdp.ast)
    mod = ast.Module(body=simulated_ast, lineno=1)
    mod = ast.fix_missing_locations(mod)

    # Compile the transformed AST
    codeobj = compile(mod, pdp.filename, 'exec')

    fname = dace_program.name

    if Config.get_bool('debugprint'):
        print("Simulating DaCe program with name", fname)

    param_symbols = {}

    if len(pdp.params) != len(args):
        raise SyntaxError('Argument number mismatch in \'' + fname +
                          '\', expecting ' + str(len(args)))

    ##################################################################
    # Disallow external variables
    # EXCEPTIONS:
    #   * The dace module ('import dace')
    #   * The math module ('import math')
    #   * Constants (types int, float, dace.int*, dace.float*)
    #   * DaCe symbols that have been defined in @dace.program args
    ##################################################################

    f_globals = {}

    # WORKAROUND: Works around a bug in CPython 2.x where True and
    # False are undefined
    f_globals['True'] = True
    f_globals['False'] = False
    ######################

    # Allow certain namespaces/modules and constants
    f_globals.update(pdp.globals)

    # Resolve symbols
    symbols = {}
    symbols.update(symbolic.getsymbols(
        args))  # from parameter values (externally defined as "dace.symbol")
    symbols.update(param_symbols)  # from parameter values (constant inputs)

    resolve = {}
    for gname, gval in f_globals.items():
        if isinstance(gval, symbolic.symbol):
            if gval.name in symbols:
                resolve[gname] = gval.get()  # Raise exception if undefined
            else:
                resolve[gname] = None  # Mark unrelated symbols for removal

    f_globals.update(resolve)

    # Remove unrelated symbols from globals
    for rk, rv in resolve.items():
        if rv is None:
            del f_globals[rk]

    # Resolve symbols in arguments as well
    newargs = tuple(symbolic.eval(a) for a in args)
    ##################################################################

    # Store parameter objects
    pdp.arrayobjs = {
        k: v
        for k, v in zip(pdp.params, newargs) if isinstance(v, numpy.ndarray)
    }

    # Simulate f
    ################################
    # Obtain function object
    gen_module = {}
    gen_module.update(f_globals)
    exec(codeobj, gen_module)
    cfunc = gen_module[fname]

    # Run function
    result = cfunc(*newargs)
    ################################

    return result
예제 #6
0
    def _construct_args(self, **kwargs):
        """ Main function that controls argument construction for calling
            the C prototype of the SDFG.

            Organizes arguments first by `sdfg.arglist`, then data descriptors
            by alphabetical order, then symbols by alphabetical order.
        """

        # Argument construction
        sig = self._sdfg.signature_arglist(with_types=False)
        typedict = self._sdfg.arglist()
        if len(kwargs) > 0:
            # Construct mapping from arguments to signature
            arglist = []
            argtypes = []
            argnames = []
            for a in sig:
                try:
                    arglist.append(kwargs[a])
                    argtypes.append(typedict[a])
                    argnames.append(a)
                except KeyError:
                    raise KeyError("Missing program argument \"{}\"".format(a))
        else:
            arglist = []
            argtypes = []
            argnames = []
            sig = []

        # Type checking
        for a, arg, atype in zip(argnames, arglist, argtypes):
            if not isinstance(arg, np.ndarray) and isinstance(atype, dt.Array):
                raise TypeError(
                    'Passing an object (type %s) to an array in argument "%s"'
                    % (type(arg).__name__, a))
            if isinstance(arg, np.ndarray) and not isinstance(atype, dt.Array):
                raise TypeError(
                    'Passing an array to a scalar (type %s) in argument "%s"' %
                    (atype.dtype.ctype, a))
            if not isinstance(atype, dt.Array) and not isinstance(
                    atype.dtype, dace.callback) and not isinstance(
                        arg, atype.dtype.type):
                print('WARNING: Casting scalar argument "%s" from %s to %s' %
                      (a, type(arg).__name__, atype.dtype.type))

        # Call a wrapper function to make NumPy arrays from pointers.
        for index, (arg, argtype) in enumerate(zip(arglist, argtypes)):
            if isinstance(argtype.dtype, dace.callback):
                arglist[index] = argtype.dtype.get_trampoline(arg)

        # Retain only the element datatype for upcoming checks and casts
        argtypes = [t.dtype.as_ctypes() for t in argtypes]

        sdfg = self._sdfg

        # As in compilation, add symbols used in array sizes to parameters
        symparams = {}
        symtypes = {}
        for symname in sdfg.undefined_symbols(False):
            try:
                symval = symbolic.symbol(symname)
                symparams[symname] = symval.get()
                symtypes[symname] = symval.dtype.as_ctypes()
            except UnboundLocalError:
                try:
                    symparams[symname] = kwargs[symname]
                except KeyError:
                    raise UnboundLocalError('Unassigned symbol %s' % symname)

        arglist.extend(
            [symparams[k] for k in sorted(symparams.keys()) if k not in sig])
        argtypes.extend(
            [symtypes[k] for k in sorted(symtypes.keys()) if k not in sig])

        # Obtain SDFG constants
        constants = sdfg.constants

        # Remove symbolic constants from arguments
        callparams = tuple(
            (arg, atype) for arg, atype in zip(arglist, argtypes)
            if not symbolic.issymbolic(arg) or (
                hasattr(arg, 'name') and arg.name not in constants))

        # Replace symbols with their values
        callparams = tuple(
            (atype(symbolic.eval(arg)),
             atype) if symbolic.issymbolic(arg, constants) else (arg, atype)
            for arg, atype in callparams)

        # Replace arrays with their pointers
        newargs = tuple(
            (ctypes.c_void_p(arg.__array_interface__['data'][0]),
             atype) if isinstance(arg, np.ndarray) else (arg, atype)
            for arg, atype in callparams)

        newargs = tuple(
            atype(arg) if (not isinstance(arg, ctypes._SimpleCData)) else arg
            for arg, atype in newargs)

        self._lastargs = newargs
        return self._lastargs
예제 #7
0
    def _construct_args(self, *args, **kwargs):
        """ Main function that controls argument construction for calling
            the C prototype of the SDFG. 
            
            Organizes arguments first by `sdfg.arglist`, then data descriptors
            by alphabetical order, then symbols by alphabetical order.
        """

        if len(kwargs) > 0 and len(args) > 0:
            raise AttributeError(
                'Compiled SDFGs can only be called with either arguments ' +
                '(e.g. "program(a,b,c)") or keyword arguments ' +
                '("program(A=a,B=b)"), but not both')

        # Argument construction
        sig = self._sdfg.signature_arglist(with_types=False)
        typedict = self._sdfg.arglist()
        if len(kwargs) > 0:
            # Construct mapping from arguments to signature
            arglist = []
            argtypes = []
            argnames = []
            for a in sig:
                try:
                    arglist.append(kwargs[a])
                    argtypes.append(typedict[a])
                    argnames.append(a)
                except KeyError:
                    raise KeyError("Missing program argument \"{}\"".format(a))
        elif len(args) > 0:
            arglist = list(args)
            argtypes = [typedict[s] for s in sig]
            argnames = sig
            sig = []
        else:
            arglist = []
            argtypes = []
            argnames = []
            sig = []

        # Type checking
        for a, arg, atype in zip(argnames, arglist, argtypes):
            if not isinstance(arg, np.ndarray) and isinstance(atype, dt.Array):
                raise TypeError(
                    'Passing an object (type %s) to an array in argument "%s"'
                    % (type(arg).__name__, a))
            if isinstance(arg, np.ndarray) and not isinstance(atype, dt.Array):
                raise TypeError(
                    'Passing an array to a scalar (type %s) in argument "%s"' %
                    (atype.dtype.ctype, a))
            if not isinstance(atype, dt.Array) and not isinstance(
                    arg, atype.dtype.type):
                print('WARNING: Casting scalar argument "%s" from %s to %s' %
                      (a, type(arg).__name__, atype.dtype.type))

        # Retain only the element datatype for upcoming checks and casts
        argtypes = [t.dtype.type for t in argtypes]

        sdfg = self._sdfg

        # As in compilation, add symbols used in array sizes to parameters
        symparams = {}
        symtypes = {}
        for symname in sdfg.undefined_symbols(False):
            # Ignore arguments (as they may not be symbols but constants,
            # see below)
            if symname in sdfg.arg_types: continue
            try:
                symval = symbolic.symbol(symname)
                symparams[symname] = symval.get()
                symtypes[symname] = symval.dtype.type
            except UnboundLocalError:
                try:
                    symparams[symname] = kwargs[symname]
                except KeyError:
                    raise UnboundLocalError('Unassigned symbol %s' % symname)

        arglist.extend(
            [symparams[k] for k in sorted(symparams.keys()) if k not in sig])
        argtypes.extend(
            [symtypes[k] for k in sorted(symtypes.keys()) if k not in sig])

        # Obtain SDFG constants
        constants = sdfg.constants

        # Remove symbolic constants from arguments
        callparams = tuple(
            (arg, atype) for arg, atype in zip(arglist, argtypes)
            if not symbolic.issymbolic(arg) or (
                hasattr(arg, 'name') and arg.name not in constants))

        # Replace symbols with their values
        callparams = tuple(
            (atype(symbolic.eval(arg)),
             atype) if symbolic.issymbolic(arg, constants) else (arg, atype)
            for arg, atype in callparams)

        # Replace arrays with their pointers
        newargs = tuple(
            (ctypes.c_void_p(arg.__array_interface__['data'][0]),
             atype) if (isinstance(arg, ndarray.ndarray)
                        or isinstance(arg, np.ndarray)) else (arg, atype)
            for arg, atype in callparams)

        newargs = tuple(types._FFI_CTYPES[atype](arg) if (
            atype in types._FFI_CTYPES
            and not isinstance(arg, ctypes.c_void_p)) else arg
                        for arg, atype in newargs)

        self._lastargs = newargs
        return self._lastargs