def cse(expr): """ symplify a complicated sympy expression into a list of expression using the cse sympy function """ ls = list(expr.atoms(Sum)) if not ls: return [expr] ls += [expr] (ls, _) = sympy_cse(ls) (vars_old, stmts) = map(list, zip(*ls)) vars_new = [] free_gl = expr.free_symbols free_gl.update(expr.atoms(IndexedBase)) free_gl.update(vars_old) stmts.append(expr) for i in range(len(stmts) - 1): free = stmts[i].free_symbols free = free.difference(free_gl) free = list(free) var = create_variable(stmts[i]) if len(free) > 0: var = IndexedBase(var)[free] vars_new.append(var) for i in range(len(stmts) - 1): stmts[i + 1] = stmts[i + 1].replace(vars_old[i], vars_new[i]) stmts[-1] = stmts[-1].replace(stmts[i], vars_new[i]) allocate = [] for i in range(len(stmts) - 1): stmts[i] = Assign(vars_new[i], stmts[i]) stmts[i] = pyccel_sum(stmts[i]) if isinstance(vars_new[i], Indexed): ind = vars_new[i].indices tp = list(stmts[i + 1].atoms(Tuple)) size = None size = [None] * len(ind) for (j, k) in enumerate(ind): for t in tp: if k == t[0]: size[j] = t[2] - t[1] + 1 break if not all(size): raise ValueError('Unable to find range of index') name = str(vars_new[i].base) var = Symbol(name) stmt = Assign(var, Function('empty')(size[0])) allocate.append(stmt) stmts[i] = For(ind[0], Function('range')(size[0]), [stmts[i]], strict=False) lhs = create_variable(expr) stmts[-1] = Assign(lhs, stmts[-1]) imports = [Import('empty', 'numpy')] return imports + allocate + stmts
def _body_optional_variable(self, tmp_variable, variable, collect_var, check_type=False): """ Responsible for collecting value and managing error and create the body of optional arguments in format if (pyobject == Py_None){ collect Null }else if(Type Check == False){ Print TypeError Wrong Type return Null }else{ assign pyobject value to tmp variable collect the adress of the tmp variable } Parameters: ---------- tmp_variable : Variable The temporary variable to hold result Variable : Variable The optional variable collect_var : variable the pyobject type variable holder of value check_type : Boolean True if the type is needed Returns ------- body : list A list of statements """ body = [(PyccelEq(VariableAddress(collect_var), VariableAddress(Py_None)), [Assign(VariableAddress(variable), Nil())])] if check_type: # Type check check = PyccelNot( PyccelOr(NumpyType_Check(variable, collect_var), PythonType_Check(variable, collect_var))) error = PyErr_SetString( 'PyExc_TypeError', '"{} must be {}"'.format(variable, variable.dtype)) body += [(check, [error, Return([Nil()])])] body += [(LiteralTrue(), [ self._create_collecting_value_body(variable, collect_var, tmp_variable), Assign(VariableAddress(variable), VariableAddress(tmp_variable)) ])] body = [If(*body)] return body
def _visit_Assign(self, stmt): lhs = self._visit(stmt.targets) if len(lhs) == 1: lhs = lhs[0] else: lhs = PythonTuple(*lhs) rhs = self._visit(stmt.value) expr = Assign(lhs, rhs) # we set the fst to keep track of needed information for errors expr.set_fst(stmt) return expr
def doprint(self, expr, assign_to=None): """ Print the expression as code. expr : Expression The expression to be printed. assign_to : Symbol, MatrixSymbol, or string (optional) If provided, the printed code will set the expression to a variable with name ``assign_to``. """ if isinstance(assign_to, str): assign_to = Symbol(assign_to) elif not isinstance(assign_to, (Basic, type(None))): raise TypeError("{0} cannot assign to object of type {1}".format( type(self).__name__, type(assign_to))) if assign_to: expr = Assign(assign_to, expr) else: expr = _sympify(expr) # Do the actual printing lines = self._print(expr).splitlines(True) # Format the output return ''.join(self._format_code(lines))
def lambdify(expr, args): if isinstance(args, Lambda): new_expr = args.expr new_expr = Return(new_expr) new_expr.set_fst(expr) f_arguments = args.variables func = FunctionDef('lambda', f_arguments, [], [new_expr]) return func code = compile(args.body[0], '', 'single') g = {} eval(code, g) f_name = str(args.name) code = g[f_name] new_args = args.arguments new_expr = code(*new_args) f_arguments = list(new_expr.free_symbols) stmts = cse(new_expr) if isinstance(stmts[-1], (Assign, GC)): var = stmts[-1].lhs else: var = create_variable(expr) stmts[-1] = Assign(var, stmts[-1]) stmts += [Return([var])] set_fst(stmts, args.fst) func = FunctionDef(f_name, new_args, [], stmts, decorators=args.decorators) return func
def _print_PythonPrint(self, expr): self._additional_imports.add("stdio") args_format = [] args = [] end = '\n' sep = ' ' for f in expr.expr: if isinstance(f, ValuedVariable): if f.name == 'sep': sep = str(f.value) elif f.name == 'end': end = str(f.value) elif isinstance(f, FunctionCall) and isinstance( f.dtype, NativeTuple): tmp_list = self.extract_function_call_results(f) tmp_arg_format_list = [] for a in tmp_list: arg_format, arg = self.get_print_format_and_arg(a) tmp_arg_format_list.append(arg_format) args.append(arg) args_format.append('({})'.format( ', '.join(tmp_arg_format_list))) assign = Assign(tmp_list, f) self._additional_code += self._print(assign) + '\n' else: arg_format, arg = self.get_print_format_and_arg(f) args_format.append(arg_format) args.append(arg) args_format = sep.join(args_format) args_format += end args_format = self._print(LiteralString(args_format)) code = ', '.join([args_format, *args]) return "printf({});".format(code)
def as_static_function_call(func, mod_name, name=None): assert isinstance(func, FunctionDef) assert isinstance(mod_name, str) # create function alias by prepending 'mod_' to its name func_alias = func.clone('mod_' + str(func.name)) # from module import func as func_alias imports = [Import(target=AsName(func.name, func_alias.name), source=mod_name)] # function arguments args = sanitize_arguments(func.arguments) # function body call = FunctionCall(func_alias, args) results = func.results results = results[0] if len(results) == 1 else results stmt = call if len(func.results) == 0 else Assign(results, call) body = [stmt] # new function declaration new_func = FunctionDef(func.name, list(args), func.results, body, arguments_inout = func.arguments_inout, functions = func.functions, interfaces = func.interfaces, imports = imports, doc_string = func.doc_string, ) # make it compatible with c static_func = as_static_function(new_func, name) return static_func
def _create_collecting_value_body(self, variable, collect_var, tmp_variable = None): """ Create If block to differentiate between python and numpy data types when collecting value format : if (collect_var is numpy_scalar) collect_value from numpy type else collect value from python type Parameters: ---------- variable: variable the variable needed to collect collect_var : variable the pyobject variable tmp_variable : variable temporary variable to hold value default None Returns ------- body : If block """ var = tmp_variable if tmp_variable else variable python_type_collect_func_call = self.get_collect_function_call(variable, collect_var) numpy_type_collect_func_call = FunctionCall(PyArray_ScalarAsCtype, [collect_var, var]) check_scalar_type = FunctionCall(PyArray_CheckScalar, [collect_var]) body = If((check_scalar_type, [numpy_type_collect_func_call]), (LiteralTrue() , [Assign(var, python_type_collect_func_call)])) return body
def _get_static_function(self, used_names, function, collect_dict): """ Create arguments and functioncall for arguments rank > 0 in fortran. Format : a is numpy array func(a) ==> static_func(a.DIM , a.DATA) where a.DATA = buffer holding data a.DIM = size of array """ additional_body = [] if self._target_language == 'fortran': static_args = [] for a in function.arguments: if isinstance(a, Variable) and a.rank > 0: # Add shape arguments for static function for i in range(collect_dict[a].rank): var = Variable(dtype=NativeInteger(), name=self.get_new_name( used_names, a.name + "_dim")) body = FunctionCall(numpy_get_dim, [collect_dict[a], i]) if a.is_optional: body = IfTernaryOperator( VariableAddress(collect_dict[a]), body, LiteralInteger(0)) body = Assign(var, body) additional_body.append(body) static_args.append(var) static_args.append(a) static_function = as_static_function_call(function, self._module_name, name=function.name) else: static_function = function static_args = function.arguments return static_function, static_args, additional_body
def _create_wrapper_check(self, check_var, parse_args, types_dict, used_names, func_name): check_func_body = [] flags = (len(types_dict) - 1) * 4 for arg in types_dict: var_name = "" body = [] types = [] arg_type_check_list = list(types_dict[arg]) arg_type_check_list.sort(key= lambda x : x[0].precision) for elem in arg_type_check_list: var_name = elem[0].name value = elem[2] << flags body.append((elem[1], [AugAssign(check_var, '+' ,value)])) types.append(elem[0]) flags -= 4 error = ' or '.join(['{} bit {}'.format(v.precision * 8 , str_dtype(v.dtype)) if not isinstance(v.dtype, NativeBool) else str_dtype(v.dtype) for v in types]) body.append((LiteralTrue(), [PyErr_SetString('PyExc_TypeError', '"{} must be {}"'.format(var_name, error)), Return([LiteralInteger(0)])])) check_func_body += [If(*body)] check_func_body = [Assign(check_var, LiteralInteger(0))] + check_func_body check_func_body.append(Return([check_var])) # Creating check function definition check_func_name = self.get_new_name(used_names.union(self._global_names), 'type_check') self._global_names.add(check_func_name) check_func_def = FunctionDef(name = check_func_name, arguments = parse_args, results = [check_var], body = check_func_body, local_vars = []) return check_func_def
def _body_management(self, used_names, variable, collect_var, cast_function, check_type=False): """ Responsible for calling functions that take care of body creation """ tmp_variable = None body = [] if variable.rank > 0: body = self._body_array(variable, collect_var, check_type) elif variable.is_optional: tmp_variable = Variable(dtype=variable.dtype, name=self.get_new_name( used_names, variable.name + "_tmp")) body = self._body_optional_variable(tmp_variable, variable, collect_var, check_type) elif isinstance(variable, ValuedVariable): body = self._body_valued_variable(variable, collect_var, check_type) elif isinstance(collect_var.dtype, PyccelPyObject): body = [self._create_collecting_value_body(variable, collect_var)] elif cast_function is not None: body = [Assign(variable, cast_function)] return body, tmp_variable
def get_default_assign(self, arg, func_arg): if arg.rank > 0 : return AliasAssign(arg, Nil()) elif func_arg.is_optional: return AliasAssign(arg, Py_None) elif isinstance(arg.dtype, (NativeReal, NativeInteger, NativeBool)): return Assign(arg, func_arg.value) elif isinstance(arg.dtype, PyccelPyObject): return AliasAssign(arg, Py_None) else: raise NotImplementedError('Default values are not implemented for this datatype : {}'.format(func_arg.dtype))
def _visit_GeneratorExp(self, stmt): result = self._visit(stmt.elt) generators = self._visit(stmt.generators) parent = self._scope[-3] if not isinstance(parent, ast.Call): raise NotImplementedError( "GeneratorExp is not the argument of a function call") name = str(self._visit(parent.func)) grandparent = self._scope[-4] if isinstance(grandparent, ast.Assign): if len(grandparent.targets) != 1: raise NotImplementedError( "Cannot unpack function with generator expression argument" ) lhs = self._visit(grandparent.targets[0]) else: lhs = self.get_new_variable() body = result if name == 'sum': body = AugAssign(lhs, '+', body) else: body = Function(name)(lhs, body) body = Assign(lhs, body) body.set_fst(parent) indices = [] generators = list(generators) while len(generators) > 0: indices.append(generators[-1].target) generators[-1].insert2body(body) body = generators.pop() indices = indices[::-1] body = [body] if name == 'sum': expr = FunctionalSum(body, result, lhs, indices, None) elif name == 'min': expr = FunctionalMin(body, result, lhs, indices, None) elif name == 'max': expr = FunctionalMax(body, result, lhs, indices, None) else: errors.report(PYCCEL_RESTRICTION_TODO, symbol=name, bounding_box=(stmt.lineno, stmt.col_offset), severity='fatal') expr.set_fst(stmt) return expr
def __new__(cls, generator): # ... define the name for the shape and the statements to be able to # compute it inside the python interface if isinstance(generator, VariableGenerator): var = generator.length stmts = [Assign(var, Len(generator.arguments))] elif isinstance(generator, ZipGenerator): var = generator.length stmts = [Assign(var, Len(generator.arguments[0]))] elif isinstance(generator, ProductGenerator): arguments = generator.arguments length = generator.length stmts = [Assign(l, Len(a)) for l, a in zip(length, arguments)] if generator.is_list: n = 1 for i in length: n *= i else: n = length var = Dummy() stmts += [Assign(var, n)] else: msg = 'not available for {}'.format(type(generator)) raise NotImplementedError(msg) stmts = Tuple(*stmts) return Basic.__new__(cls, var, stmts)
def _visit_ListComp(self, stmt): result = self._visit(stmt.elt) generators = list(self._visit(stmt.generators)) if not isinstance(self._scope[-2], ast.Assign): errors.report(PYCCEL_RESTRICTION_LIST_COMPREHENSION_ASSIGN, symbol=stmt, severity='error') lhs = self.get_new_variable() else: lhs = self._visit(self._scope[-2].targets) if len(lhs) == 1: lhs = lhs[0] else: raise NotImplementedError( "A list comprehension cannot be unpacked") index = self.get_new_variable() args = [index] target = IndexedBase(lhs)[args] target = Assign(target, result) assign1 = Assign(index, LiteralInteger(0)) assign1.set_fst(stmt) target.set_fst(stmt) generators[-1].insert2body(target) assign2 = Assign(index, PyccelAdd(index, LiteralInteger(1))) assign2.set_fst(stmt) generators[-1].insert2body(assign2) indices = [generators[-1].target] while len(generators) > 1: F = generators.pop() generators[-1].insert2body(F) indices.append(generators[-1].target) indices = indices[::-1] return FunctionalFor([assign1, generators[-1]], target.rhs, target.lhs, indices, index)
def _print_FunctionCall(self, expr): func = expr.funcdef # Ensure the correct syntax is used for pointers args = [] for a, f in zip(expr.arguments, func.arguments): if isinstance(a, Variable) and self.stored_in_c_pointer(f): args.append(VariableAddress(a)) elif f.is_optional and not isinstance(a, Nil): tmp_var = self.create_tmp_var(f) assign = Assign(tmp_var, a) self._additional_code += self._print(assign) + '\n' args.append(VariableAddress(tmp_var)) else: args.append(a) args += self._temporary_args self._temporary_args = [] args = ', '.join(['{}'.format(self._print(a)) for a in args]) if not func.results: return '{}({});'.format(func.name, args) return '{}({})'.format(func.name, args)
def __new__(cls, block, reduction, lhs, **kwargs): # ... settings = kwargs.copy() accelerator = settings.pop('accelerator') # ... assert (isinstance(reduction, Reduction)) # ... if isinstance(lhs, (list, tuple, Tuple)): raise NotImplementedError() # ... # ... generator = block.generator decs = block.decs body = block.body private_vars = generator.private # ... # ... lhs_name = lhs.name assign_stmts = list(block.body.atoms(Assign)) # ... # ... ls = [i for i in assign_stmts if _get_name(i.lhs) == lhs_name] if len(ls) > 1: raise NotImplementedError() assign_iterable = ls[0] rhs = assign_iterable.rhs new_stmt = AugAssign(lhs, reduction.op, rhs) body = block.body.subs(assign_iterable, new_stmt) decs = block.decs # ... # ... add initial values for reduced variables _reduction_init = lambda i: _get_default_value(i, op=reduction.op) reduction_stmts = [ Assign(r, _reduction_init(r)) for r in reduction.arguments ] # update declarations decs = list(decs) + reduction_stmts decs = Tuple(*decs) # ... # ... define private variables of the current block # TODO add private vars from internal blocks private_vars = Tuple(*private_vars) # ... # ... add parallel loop if accelerator: if not (accelerator == 'omp'): raise NotImplementedError('Only OpenMP is available') # ... omp_fors = list(body.atoms(OMP_For)) omp_for = [i for i in body if isinstance(i, OMP_For)] assert (len(omp_for) == 1) omp_for = omp_for[0] loop = omp_for.loop clauses = list(omp_for.clauses) nowait = omp_for.nowait # ... reduction_args = [reduction.op] + list(reduction.arguments) clauses += [OMP_Reduction(*reduction_args)] clauses = Tuple(*clauses) # ... new = OMP_For(loop, clauses, nowait) body = body.subs(omp_for, new) # ... decs = Tuple(*decs) body = Tuple(*body) return Basic.__new__(cls, generator, decs, body, private_vars)
def _visit_ProductMap(self, stmt): func = stmt.func args = stmt.target # ... if isinstance(func, BasicMap): raise TypeError("'map' object is not callable") # ... # ... get the codomain type type_codomain = self.main_type type_domain = self.d_domain_types[type_codomain] # ... # ... construct the generator target = [self._visit(i) for i in args] generator = ProductGenerator(*target) # ... # ... construct the results results = self._visit(type_codomain) # compute depth of the type list # TODO do we still need this? depth_out = len(list(type_codomain.atoms(TypeList))) # ... # ... index = generator.index iterator = generator.iterator # ... # ... list of all statements stmts = [] # ... # ... use a multi index in the case of zip length = generator.length multi_index = generator.multi_index generator.set_as_list() # TODO check formula value = index[0] for ix, nx in zip(index[1:], length[::-1][:-1]): value = nx * value + ix stmts += [Assign(multi_index, value)] # update index to use multi index index = multi_index # ... # ... we set the generator after we treat map/tmap self.set_generator(results, generator) # ... # ... apply the function to arguments rhs = Call(func, iterator) # ... # ... create lhs lhs = generator.iterator # TODO check this if isinstance(lhs, Tuple) and len(lhs) == 1: lhs = lhs[0] # ... # ... create lhs for storing the result if isinstance(results, Variable): results = [results] else: msg = '{} not available'.format(type(results)) raise NotImplementedError(msg) if not isinstance(index, Tuple): index = [index] else: index = list([i for i in index]) lhs = [] for r in results: m = r.rank - depth_out ind = index + [Slice(None, None)] * m if len(ind) == 1: ind = ind[0] lhs.append(IndexedBase(r.name)[ind]) lhs = Tuple(*lhs) if len(lhs) == 1: lhs = lhs[0] # ... # ... create core statement stmts += [Assign(lhs, rhs)] # ... # TODO USE THIS # expr = self.get_expr_from_type() # return the associated for loops return GeneratorBlock(generator, stmts, accelerator=self.accelerator, nowait=self.nowait, schedule=self.schedule, chunk=self.chunk)
def __new__(cls, func, import_lambda): # ... m_results = func.m_results name = 'interface_{}'.format(func.name) args = [i for i in func.arguments if not i in m_results] s_results = func.results results = list(s_results) + list(m_results) # ... # ... imports = [import_lambda] stmts = [] # ... # ... out argument if len(results) == 1: outs = [Symbol('out')] else: outs = [Symbol('out_{}'.format(i)) for i in range(0, len(results))] # ... # ... generators = func.generators d_shapes = {} for i in m_results: d_shapes[i] = compute_shape(i, generators) # ... # ... TODO build statements if_cond = Is(Symbol('out'), Nil()) if_body = [] # TODO add imports from numpy if_body += [Import('zeros', 'numpy')] if_body += [Import('float64', 'numpy')] for i, var in enumerate(results): if var in m_results: shaping = d_shapes[var] if_body += shaping.stmts if_body += [Assign(outs[i], Zeros(shaping.var, var.dtype))] # update statements stmts = [If((if_cond, if_body))] # ... # ... add call to the python or pyccelized function stmts += [FunctionCall(func, args + outs)] # ... # ... add return out if len(outs) == 1: stmts += [Return(outs[0])] else: stmts += [Return(outs)] # ... # ... body = imports + stmts # ... # update arguments with optional args += [Assign(Symbol('out'), Nil())] return FunctionDef(name, args, results, body)
def _print_FunctionDef(self, expr): # Save all used names used_names = set([a.name for a in expr.arguments] + [r.name for r in expr.results] + [expr.name.name]) # Find a name for the wrapper function wrapper_name = self._get_wrapper_name(used_names, expr) used_names.add(wrapper_name) # Collect local variables wrapper_vars = {a.name: a for a in expr.arguments} wrapper_vars.update({r.name: r for r in expr.results}) python_func_args = self.get_new_PyObject("args", used_names) python_func_kwargs = self.get_new_PyObject("kwargs", used_names) python_func_selfarg = self.get_new_PyObject("self", used_names) # Collect arguments and results wrapper_args = [ python_func_selfarg, python_func_args, python_func_kwargs ] wrapper_results = [self.get_new_PyObject("result", used_names)] if expr.is_private: wrapper_func = FunctionDef( name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=[ PyErr_SetString( 'PyExc_NotImplementedError', '"Private functions are not accessible from python"'), AliasAssign(wrapper_results[0], Nil()), Return(wrapper_results) ]) return CCodePrinter._print_FunctionDef(self, wrapper_func) if any(isinstance(arg, FunctionAddress) for arg in expr.arguments): wrapper_func = FunctionDef( name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=[ PyErr_SetString('PyExc_NotImplementedError', '"Cannot pass a function as an argument"'), AliasAssign(wrapper_results[0], Nil()), Return(wrapper_results) ]) return CCodePrinter._print_FunctionDef(self, wrapper_func) # Collect argument names for PyArgParse arg_names = [a.name for a in expr.arguments] keyword_list_name = self.get_new_name(used_names, 'kwlist') keyword_list = PyArgKeywords(keyword_list_name, arg_names) wrapper_body = [keyword_list] wrapper_body_translations = [] parse_args = [] collect_vars = {} for arg in expr.arguments: collect_var, cast_func = self.get_PyArgParseType(used_names, arg) collect_vars[arg] = collect_var body, tmp_variable = self._body_management(used_names, arg, collect_var, cast_func, True) if tmp_variable: wrapper_vars[tmp_variable.name] = tmp_variable # If the variable cannot be collected from PyArgParse directly wrapper_vars[collect_var.name] = collect_var # Save cast to argument variable wrapper_body_translations.extend(body) parse_args.append(collect_var) # Write default values if isinstance(arg, ValuedVariable): wrapper_body.append( self.get_default_assign(parse_args[-1], arg)) # Parse arguments parse_node = PyArg_ParseTupleNode(python_func_args, python_func_kwargs, expr.arguments, parse_args, keyword_list) wrapper_body.append(If((PyccelNot(parse_node), [Return([Nil()])]))) wrapper_body.extend(wrapper_body_translations) # Call function static_function, static_args, additional_body = self._get_static_function( used_names, expr, collect_vars) wrapper_body.extend(additional_body) for var in static_args: wrapper_vars[var.name] = var if len(expr.results) == 0: func_call = FunctionCall(static_function, static_args) else: results = expr.results if len( expr.results) > 1 else expr.results[0] func_call = Assign(results, FunctionCall(static_function, static_args)) wrapper_body.append(func_call) # Loop over results to carry out necessary casts and collect Py_BuildValue type string res_args = [] for a in expr.results: collect_var, cast_func = self.get_PyBuildValue(used_names, a) if cast_func is not None: wrapper_vars[collect_var.name] = collect_var wrapper_body.append(AliasAssign(collect_var, cast_func)) res_args.append( VariableAddress(collect_var) if collect_var. is_pointer else collect_var) # Call PyBuildNode wrapper_body.append( AliasAssign(wrapper_results[0], PyBuildValueNode(res_args))) # Call free function for python type wrapper_body += [ FunctionCall(Py_DECREF, [i]) for i in self._to_free_PyObject_list ] self._to_free_PyObject_list.clear() #Return wrapper_body.append(Return(wrapper_results)) # Create FunctionDef and write using classic method wrapper_func = FunctionDef(name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=wrapper_body, local_vars=wrapper_vars.values()) return CCodePrinter._print_FunctionDef(self, wrapper_func)
def _print_Interface(self, expr): # Collecting all functions funcs = expr.functions # Save all used names used_names = set(n.name for n in funcs) # Find a name for the wrapper function wrapper_name = self._get_wrapper_name(used_names, expr) self._global_names.add(wrapper_name) # Collect local variables python_func_args = self.get_new_PyObject("args", used_names) python_func_kwargs = self.get_new_PyObject("kwargs", used_names) python_func_selfarg = self.get_new_PyObject("self", used_names) # Collect wrapper arguments and results wrapper_args = [ python_func_selfarg, python_func_args, python_func_kwargs ] wrapper_results = [self.get_new_PyObject("result", used_names)] # Collect parser arguments wrapper_vars = {} # Collect argument names for PyArgParse arg_names = [a.name for a in funcs[0].arguments] keyword_list_name = self.get_new_name(used_names, 'kwlist') keyword_list = PyArgKeywords(keyword_list_name, arg_names) wrapper_body = [keyword_list] wrapper_body_translations = [] body_tmp = [] # To store the mini function responsible of collecting value and calling interfaces functions and return the builded value funcs_def = [] default_value = { } # dict to collect all initialisation needed in the wrapper check_var = Variable(dtype=NativeInteger(), name=self.get_new_name(used_names, "check")) wrapper_vars[check_var.name] = check_var types_dict = OrderedDict( (a, set()) for a in funcs[0].arguments ) #dict to collect each variable possible type and the corresponding flags # collect parse arg parse_args = [ Variable(dtype=PyccelPyArrayObject(), is_pointer=True, rank=a.rank, order=a.order, name=self.get_new_name(used_names, a.name + "_tmp")) if a.rank > 0 else Variable(dtype=PyccelPyObject(), name=self.get_new_name(used_names, a.name + "_tmp"), is_pointer=True) for a in funcs[0].arguments ] # Managing the body of wrapper for func in funcs: mini_wrapper_func_body = [] res_args = [] mini_wrapper_func_vars = {a.name: a for a in func.arguments} flags = 0 collect_vars = {} # Loop for all args in every functions and create the corresponding condition and body for p_arg, f_arg in zip(parse_args, func.arguments): collect_vars[f_arg] = p_arg body, tmp_variable = self._body_management( used_names, f_arg, p_arg, None) if tmp_variable: mini_wrapper_func_vars[tmp_variable.name] = tmp_variable # get check type function check = self._get_check_type_statement(f_arg, p_arg) # If the variable cannot be collected from PyArgParse directly wrapper_vars[p_arg.name] = p_arg # Save the body wrapper_body_translations.extend(body) # Write default values if isinstance(f_arg, ValuedVariable): wrapper_body.append( self.get_default_assign(parse_args[-1], f_arg)) flag_value = flags_registry[(f_arg.dtype, f_arg.precision)] flags = (flags << 4) + flag_value # shift by 4 to the left types_dict[f_arg].add( (f_arg, check, flag_value)) # collect variable type for each arguments mini_wrapper_func_body += body # create the corresponding function call static_function, static_args, additional_body = self._get_static_function( used_names, func, collect_vars) mini_wrapper_func_body.extend(additional_body) for var in static_args: mini_wrapper_func_vars[var.name] = var if len(func.results) == 0: func_call = FunctionCall(static_function, static_args) else: results = func.results if len( func.results) > 1 else func.results[0] func_call = Assign(results, FunctionCall(static_function, static_args)) mini_wrapper_func_body.append(func_call) # Loop for all res in every functions and create the corresponding body and cast for r in func.results: collect_var, cast_func = self.get_PyBuildValue(used_names, r) mini_wrapper_func_vars[collect_var.name] = collect_var if cast_func is not None: mini_wrapper_func_vars[r.name] = r mini_wrapper_func_body.append( AliasAssign(collect_var, cast_func)) res_args.append( VariableAddress(collect_var) if collect_var. is_pointer else collect_var) # Building PybuildValue and freeing the allocated variable after. mini_wrapper_func_body.append( AliasAssign(wrapper_results[0], PyBuildValueNode(res_args))) mini_wrapper_func_body += [ FunctionCall(Py_DECREF, [i]) for i in self._to_free_PyObject_list ] mini_wrapper_func_body.append(Return(wrapper_results)) self._to_free_PyObject_list.clear() # Building Mini wrapper function mini_wrapper_func_name = self.get_new_name( used_names.union(self._global_names), func.name.name + '_mini_wrapper') self._global_names.add(mini_wrapper_func_name) mini_wrapper_func_def = FunctionDef( name=mini_wrapper_func_name, arguments=parse_args, results=wrapper_results, body=mini_wrapper_func_body, local_vars=mini_wrapper_func_vars.values()) funcs_def.append(mini_wrapper_func_def) # append check condition to the functioncall body_tmp.append((PyccelEq(check_var, LiteralInteger(flags)), [ AliasAssign(wrapper_results[0], FunctionCall(mini_wrapper_func_def, parse_args)) ])) # Errors / Types management # Creating check_type function check_func_def = self._create_wrapper_check(check_var, parse_args, types_dict, used_names, funcs[0].name.name) funcs_def.append(check_func_def) # Create the wrapper body with collected informations body_tmp = [((PyccelNot(check_var), [Return([Nil()])]))] + body_tmp body_tmp.append((LiteralTrue(), [ PyErr_SetString('PyExc_TypeError', '"Arguments combinations don\'t exist"'), Return([Nil()]) ])) wrapper_body_translations = [If(*body_tmp)] # Parsing Arguments parse_node = PyArg_ParseTupleNode(python_func_args, python_func_kwargs, funcs[0].arguments, parse_args, keyword_list, True) wrapper_body += list(default_value.values()) wrapper_body.append(If((PyccelNot(parse_node), [Return([Nil()])]))) #finishing the wrapper body wrapper_body.append( Assign(check_var, FunctionCall(check_func_def, parse_args))) wrapper_body.extend(wrapper_body_translations) wrapper_body.append(Return(wrapper_results)) # Return # Create FunctionDef funcs_def.append( FunctionDef(name=wrapper_name, arguments=wrapper_args, results=wrapper_results, body=wrapper_body, local_vars=wrapper_vars.values())) sep = self._print(SeparatorComment(40)) return sep + '\n'.join( CCodePrinter._print_FunctionDef(self, f) for f in funcs_def)
def mpify(stmt, **options): """ Converts some statements to MPI statments. stmt: stmt, list statement or a list of statements """ if isinstance(stmt, (list, tuple, Tuple)): return [mpify(i, **options) for i in stmt] if isinstance(stmt, MPI): return stmt if isinstance(stmt, Tensor): options['label'] = stmt.name return stmt if isinstance(stmt, ForIterator): iterable = mpify(stmt.iterable, **options) target = stmt.target body = mpify(stmt.body, **options) return ForIterator(target, iterable, body, strict=False) if isinstance(stmt, For): iterable = mpify(stmt.iterable, **options) target = stmt.target body = mpify(stmt.body, **options) return For(target, iterable, body, strict=False) if isinstance(stmt, list): return [mpify(a, **options) for a in stmt] if isinstance(stmt, While): test = mpify(stmt.test, **options) body = mpify(stmt.body, **options) return While(test, body) if isinstance(stmt, If): args = [] for block in stmt.args: test = block[0] stmts = block[1] t = mpify(test, **options) s = mpify(stmts, **options) args.append((t, s)) return If(*args) if isinstance(stmt, FunctionDef): return stmt # TODO uncomment this # name = mpify(stmt.name, **options) # arguments = mpify(stmt.arguments, **options) # results = mpify(stmt.results, **options) # body = mpify(stmt.body, **options) # local_vars = mpify(stmt.local_vars, **options) # global_vars = mpify(stmt.global_vars, **options) # # return FunctionDef(name, arguments, results, \ # body, local_vars, global_vars) if isinstance(stmt, ClassDef): name = mpify(stmt.name, **options) attributs = mpify(stmt.attributs, **options) methods = mpify(stmt.methods, **options) options = mpify(stmt.options, **options) return ClassDef(name, attributs, methods, options) if isinstance(stmt, Assign): if isinstance(stmt.rhs, Tensor): lhs = stmt.lhs options['label'] = lhs.name rhs = mpify(stmt.rhs, **options) return Assign(lhs, rhs, \ strict=stmt.strict, \ status=stmt.status, \ like=stmt.like) if isinstance(stmt, Del): variables = [mpify(a, **options) for a in stmt.variables] return Del(variables) if isinstance(stmt, Ones): if stmt.grid: lhs = stmt.lhs shape = stmt.shape grid = mpify(stmt.grid, **options) return Ones(lhs, grid=grid) if isinstance(stmt, Zeros): if stmt.grid: lhs = stmt.lhs shape = stmt.shape grid = mpify(stmt.grid, **options) return Zeros(lhs, grid=grid) if isinstance(stmt, Module): name = mpify(stmt.name, **options) variables = mpify(stmt.variables, **options) funcs = mpify(stmt.funcs, **options) classes = mpify(stmt.classes, **options) imports = mpify(stmt.imports, **options) imports += [Import('mpi')] # TODO add stdlib_parallel_mpi module return Module(name, variables, funcs, classes, imports=imports) if isinstance(stmt, Program): name = mpify(stmt.name, **options) variables = mpify(stmt.variables, **options) funcs = mpify(stmt.funcs, **options) classes = mpify(stmt.classes, **options) imports = mpify(stmt.imports, **options) body = mpify(stmt.body, **options) modules = mpify(stmt.modules, **options) imports += [Import('mpi')] # TODO improve this import, without writing 'mod_...' # maybe we should create a new class for this import imports += [Import('mod_pyccel_stdlib_parallel_mpi')] return Program(name, variables, funcs, classes, body, imports=imports, modules=modules) return stmt
def _build_block(generator, stmts): # ... decs = [] body = [] # ... # TODO USE stmts # ... iterable = generator.arguments index = generator.index iterator = generator.iterator length = generator.length if not isinstance(iterable, (list, tuple, Tuple)): iterable = [iterable] if not isinstance(index, (list, tuple, Tuple)): index = [index] if not isinstance(iterator, (list, tuple, Tuple)): iterator = [iterator] if not isinstance(length, (list, tuple, Tuple)): length = [length] # ... # print('------------- BEFORE') # print(' iterable = ', iterable) # print(' index = ', index ) # print(' iterator = ', iterator) # print(' length = ', length ) # ... TODO use shape_stmts for n, xs in zip(length, iterable): decs += [Assign(n, Len(xs))] # ... # ... append the same length for product if isinstance(generator, ProductGenerator): length = length * len(generator) # ... # print('------------- AFTER') # print(' iterable = ', iterable) # print(' index = ', index ) # print(' iterator = ', iterator) # print(' length = ', length ) # ... body += list(stmts) # ... # ... if isinstance(generator, ZipGenerator): for i, n in zip(index, length): for x, xs in zip(iterator, iterable): if not isinstance(xs, (list, tuple, Tuple)): body = [Assign(x, IndexedBase(xs.name)[i])] + body else: for v in xs: body = [Assign(x, IndexedBase(v.name)[i])] + body body = [For(i, Range(0, n), Tuple(*body), strict=False)] else: for i, n, x, xs in zip(index, length, iterator, iterable): if not isinstance(xs, (list, tuple, Tuple)): body = [Assign(x, IndexedBase(xs.name)[i])] + body else: for v in xs: body = [Assign(x, IndexedBase(v.name)[i])] + body body = [For(i, Range(0, n), Tuple(*body), strict=False)] # ... return decs, body
def _visit_Map(self, stmt): func = stmt.func args = stmt.target # ... if isinstance(func, BasicMap): raise TypeError("'map' object is not callable") # ... # ... get the codomain type type_codomain = self.main_type type_domain = self.d_domain_types[type_codomain] # ... # ... construct the generator target = [self._visit(i) for i in args] if len(target) == 1: target = target[0] assert (isinstance(target, Variable)) generator = VariableGenerator(target) else: generator = ZipGenerator(*target) # ... # ... construct the results results = self._visit(type_codomain) # compute depth of the type list # TODO do we still need this? depth_out = len(list(type_codomain.atoms(TypeList))) # ... # ... index = generator.index iterator = generator.iterator # ... # ... list of all statements stmts = [] # ... # ... we set the generator after we treat map/tmap self.set_generator(results, generator) # ... # ... apply the function to arguments rhs = Call(func, iterator) # ... # print('PAR ICI') # print(func) # print(func.name) ## import sys; sys.exit(0) # ... create lhs lhs = generator.iterator # TODO check this if isinstance(lhs, Tuple) and len(lhs) == 1: lhs = lhs[0] # ... # ... create lhs for storing the result if isinstance(results, Variable): results = [results] else: msg = '{} not available'.format(type(results)) raise NotImplementedError(msg) if not isinstance(index, Tuple): index = [index] else: index = list([i for i in index]) lhs = [] for r in results: m = r.rank - depth_out ind = index + [Slice(None, None)] * m if len(ind) == 1: ind = ind[0] lhs.append(IndexedBase(r.name)[ind]) lhs = Tuple(*lhs) if len(lhs) == 1: lhs = lhs[0] # ... # ... create core statement stmts += [Assign(lhs, rhs)] # ... # TODO USE THIS # expr = self.get_expr_from_type() # return the associated for loops return GeneratorBlock(generator, stmts, accelerator=self.accelerator, nowait=self.nowait, schedule=self.schedule, chunk=self.chunk)
def _body_array(self, variable, collect_var, check_type=False): """ Responsible for collecting value and managing error and create the body of arguments with rank greater than 0 in format if (rank check == False){ print TypeError Wrong rank return Null }else if(Type Check == False){ Print TypeError Wrong type return Null }else if (order check == False){ #check for order for rank > 1 Print NotImplementedError Wrong Order return Null } collect the value from PyArrayObject Parameters: ---------- Variable : Variable The optional variable collect_var : variable the pyobject type variable holder of value check_type : Boolean True if the type is needed Returns ------- body : list A list of statements """ body = [] #TODO create and extern rank and order check function #check optional : if variable.is_optional: check = PyccelNot(VariableAddress(collect_var)) body += [(check, [Assign(VariableAddress(variable), Nil())])] #rank check : check = PyccelNe(FunctionCall(numpy_get_ndims, [collect_var]), LiteralInteger(collect_var.rank)) error = PyErr_SetString( 'PyExc_TypeError', '"{} must have rank {}"'.format(collect_var, str(collect_var.rank))) body += [(check, [error, Return([Nil()])])] if check_type: #Type check numpy_dtype = self.find_in_numpy_dtype_registry(variable) arg_dtype = self.find_in_dtype_registry( self._print(variable.dtype), variable.precision) check = PyccelNe(FunctionCall(numpy_get_type, [collect_var]), numpy_dtype) info_dump = PythonPrint( [FunctionCall(numpy_get_type, [collect_var]), numpy_dtype]) error = PyErr_SetString( 'PyExc_TypeError', '"{} must be {}"'.format(variable, arg_dtype)) body += [(check, [info_dump, error, Return([Nil()])])] if collect_var.rank > 1 and self._target_language == 'fortran': #Order check if collect_var.order == 'F': check = FunctionCall(numpy_check_flag, [collect_var, numpy_flag_f_contig]) else: check = FunctionCall(numpy_check_flag, [collect_var, numpy_flag_c_contig]) error = PyErr_SetString( 'PyExc_NotImplementedError', '"Argument does not have the expected ordering ({})"'. format(collect_var.order)) body += [(PyccelNot(check), [error, Return([Nil()])])] body += [(LiteralTrue(), [ Assign(VariableAddress(variable), self.get_collect_function_call(variable, collect_var)) ])] body = [If(*body)] return body