diff --git a/lampy/__init__.py b/lampy/__init__.py index 288a11e..a8e6676 100644 --- a/lampy/__init__.py +++ b/lampy/__init__.py @@ -1,13 +1,13 @@ # -*- coding: UTF-8 -*- -from .lexeme import * -from .ast import * -from .datatypes import * -from .syntax import * -from .compatibility import * -from .semantic import * -from .codegen import * -from .lambdify import * -from .utilities import * -from .printing import * -from .interface import * +from lampy.lexeme import * +from lampy.ast import * +from lampy.datatypes import * +from lampy.syntax import * +from lampy.compatibility import * +from lampy.semantic import * +from lampy.codegen import * +from lampy.lambdify import * +from lampy.utilities import * +from lampy.printing import * +from lampy.interface import * diff --git a/lampy/ast.py b/lampy/ast.py index 129e26e..075b054 100644 --- a/lampy/ast.py +++ b/lampy/ast.py @@ -1,12 +1,17 @@ # coding: utf-8 - +import random +import string from sympy import Symbol, Tuple, Dict, Lambda from pyccel.ast.basic import Basic -from pyccel.ast.core import FunctionCall, FunctionDef -from pyccel.codegen.utilities import random_string +from pyccel.ast.core import FunctionCall, FunctionDef + #========================================================================= +def random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) + class BasicMap(Basic): """.""" _name = 'BasicMap' diff --git a/lampy/codegen.py b/lampy/codegen.py index 93ab78f..e8345ff 100644 --- a/lampy/codegen.py +++ b/lampy/codegen.py @@ -2,7 +2,8 @@ import os from os.path import join, dirname - +import string +import random from sympy import Symbol, Lambda, Function, Dummy from sympy import Tuple, IndexedBase, Indexed from sympy.core.function import AppliedUndef @@ -12,12 +13,13 @@ from sympy import FunctionClass -from pyccel.codegen.utilities import random_string +#from pyccel.codegen.utilities import random_string from pyccel.ast.utilities import build_types_decorator from pyccel.ast.core import Slice +from pyccel.ast.core import Block from pyccel.ast.core import Variable, FunctionDef, Assign, AugAssign from pyccel.ast.core import Return, Pass, Import, String -from pyccel.ast.core import For, Range, Len, Print +from pyccel.ast.core import For, Range, Len, SymbolicPrint from pyccel.ast.datatypes import get_default_value from pyccel.ast.datatypes import NativeInteger, NativeReal, NativeComplex, NativeBool from pyccel.ast.basic import Basic @@ -27,15 +29,19 @@ from pyccel.ast.parallel.openmp import OMP_NumThread from pyccel.ast.parallel.openmp import OMP_Reduction -from .datatypes import TypeVariable, TypeTuple, TypeList -from .semantic import Parser as SemanticParser -from .lexeme import _internal_applications -from .lexeme import _math_functions -from .lexeme import _internal_map_functors -from .ast import Call -from .ast import BasicMap +from lampy.datatypes import TypeVariable, TypeTuple, TypeList +from lampy.semantic import Parser as SemanticParser +from lampy.lexeme import _internal_applications +from lampy.lexeme import _math_functions +from lampy.lexeme import _internal_map_functors +from lampy.ast import Call +from lampy.ast import BasicMap #======================================================================== +def random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) + # TODO improve or copy from pyccel.parser def _get_name(i): if isinstance(i, Symbol): @@ -150,19 +156,29 @@ def _get_default_value(var, op=None): raise NotImplementedError('TODO') #========================================================================= + +class Types (Function): + def __new__(cls, *args): + return Basic.__new__(cls, *args) +#========================================================================= class LambdaFunctionDef(FunctionDef): """.""" def __new__( cls, name, arguments, results, body, **kwargs ): generators = kwargs.pop('generators', {}) m_results = kwargs.pop('m_results', []) - obj = FunctionDef.__new__(cls, name, arguments, results, body, **kwargs) - obj._generators = generators - obj._m_results = m_results + return obj + def __init__(self, name, arguments, results, body, **kwargs): + generators = kwargs.pop('generators', {}) + m_results = kwargs.pop('m_results', []) + super().__init__(name, arguments, results, body, **kwargs) + self._generators = generators + self._m_results = m_results + @property def generators(self): return self._generators @@ -422,7 +438,11 @@ def __new__( cls, block, **kwargs ): # ... # ... - body = [OMP_Parallel( clauses, variables, body )] + + body = [Block( 'function' , variables, body )] + + + # ... # TODO this is a hack to handle the last comment after a loop, so that @@ -769,6 +789,7 @@ def __init__(self, parser, **kwargs): self._typed_functions = parser.typed_functions self._default_type = parser.default_type self._generators = {} + # ... # ... @@ -1386,9 +1407,7 @@ def _visit_LampyLambda(self, stmt): # decorators = {'types': build_types_decorator(args), # 'external_call': []} - decorators = {'types': build_types_decorator(args), - 'external': []} - + decorators = {'types': Types(*build_types_decorator(args))} tag = random_string( 6 ) name = 'lambda_{}'.format( tag ) # ... @@ -1399,6 +1418,7 @@ def _visit_LampyLambda(self, stmt): generators = self.generators, m_results = m_results ) + def _visit_Integer(self, stmt): return stmt diff --git a/lampy/datatypes.py b/lampy/datatypes.py index cab5121..697f898 100644 --- a/lampy/datatypes.py +++ b/lampy/datatypes.py @@ -1,14 +1,18 @@ #!/usr/bin/python # -*- coding: utf-8 -*- - +import random, string from sympy import Tuple, IndexedBase from pyccel.ast.basic import Basic from pyccel.ast.core import Variable, For, Range, Assign, Len -from pyccel.codegen.utilities import random_string +#from pyccel.codegen.utilities import random_string #========================================================================= +def random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) + class BasicTypeVariable(Basic): _tag = None diff --git a/lampy/interface.py b/lampy/interface.py index 2843927..5ccfcdb 100644 --- a/lampy/interface.py +++ b/lampy/interface.py @@ -2,7 +2,8 @@ import os from os.path import join, dirname - +import random +import string from sympy import Symbol, Lambda, Function, Dummy from sympy import Tuple, IndexedBase from sympy.core.function import AppliedUndef @@ -12,7 +13,7 @@ from sympy import FunctionClass -from pyccel.codegen.utilities import random_string +#from pyccel.codegen.utilities import random_string from pyccel.ast.utilities import build_types_decorator from pyccel.ast.core import Slice from pyccel.ast.core import Variable, FunctionDef, Assign, AugAssign @@ -23,14 +24,18 @@ from pyccel.ast.numpyext import Zeros from pyccel.ast.basic import Basic -from .datatypes import TypeVariable, TypeTuple, TypeList -from .semantic import Parser as SemanticParser -from .lexeme import _internal_applications -from .lexeme import _math_functions -from .lexeme import _internal_map_functors -from .codegen import BasicGenerator, Shaping, LambdaFunctionDef +from lampy.datatypes import TypeVariable, TypeTuple, TypeList +from lampy.semantic import Parser as SemanticParser +from lampy.lexeme import _internal_applications +from lampy.lexeme import _math_functions +from lampy.lexeme import _internal_map_functors +from lampy.codegen import BasicGenerator, Shaping, LambdaFunctionDef #======================================================================================= +def random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) + def compute_shape( arg, generators ): if not( arg in generators.keys() ): raise ValueError('Could not find {}'.format( arg )) diff --git a/lampy/lambdify.py b/lampy/lambdify.py index 8767927..ded4207 100644 --- a/lampy/lambdify.py +++ b/lampy/lambdify.py @@ -5,62 +5,230 @@ import os import sys +import inspect import importlib import numpy as np from types import FunctionType -from sympy import Indexed, IndexedBase, Tuple, Lambda -from sympy.core.function import AppliedUndef -from sympy.core.function import UndefinedFunction -from sympy import sympify -from sympy import Dummy - -from pyccel.codegen.utilities import construct_flags as construct_flags_pyccel -from pyccel.codegen.utilities import execute_pyccel -from pyccel.codegen.utilities import get_source_function -from pyccel.codegen.utilities import random_string -from pyccel.codegen.utilities import write_code -from pyccel.codegen.utilities import mkdir_p -from pyccel.ast.datatypes import dtype_and_precsision_registry as dtype_registry -from pyccel.ast import Variable, Len, Assign, AugAssign -from pyccel.ast import For, Range, FunctionDef -from pyccel.ast import FunctionCall -from pyccel.ast import Comment, AnnotatedComment -from pyccel.ast import Print, Pass, Return, Import -from pyccel.ast.core import Slice, String -from pyccel.ast import Zeros -from pyccel.ast.datatypes import NativeInteger, NativeReal, NativeComplex, NativeBool +#from sympy import Indexed, IndexedBase, Tuple, Lambda +#from sympy.core.function import AppliedUndef +#from sympy.core.function import UndefinedFunction +#from sympy import sympify +#from sympy import Dummy + +#from pyccel.codegen.utilities import construct_flags as construct_flags_pyccel +#from pyccel.codegen.utilities import execute_pyccel +#from pyccel.codegen.utilities import get_source_function +#from pyccel.codegen.utilities import random_string +#from pyccel.codegen.utilities import write_code +#from pyccel.codegen.utilities import mkdir_p +#from pyccel.ast.datatypes import dtype_and_precsision_registry as dtype_registry +#from pyccel.ast import Variable, Len, Assign, AugAssign +#from pyccel.ast import For, Range, FunctionDef +#from pyccel.ast import FunctionCall +#from pyccel.ast import Comment, AnnotatedComment +#from pyccel.ast import Import +#from pyccel.ast.core import Slice, String +#from pyccel.ast import Zeros +#from pyccel.ast.datatypes import NativeInteger, NativeReal, NativeComplex, NativeBool from pyccel.codegen.printing.pycode import pycode -from pyccel.codegen.printing.fcode import fcode -from pyccel.ast.utilities import build_types_decorator -from pyccel.ast.datatypes import get_default_value -from pyccel.parser import Parser as PyccelParser - -from .syntax import parse as parse_lambda -from .semantic import Parser as SemanticParser -from .codegen import AST -from .utilities import get_decorators -from .utilities import get_pyccel_imports_code -from .utilities import get_dependencies_code -from .utilities import math_atoms_as_str -from .printing import pycode -from .interface import LambdaInterface +#from pyccel.codegen.printing.fcode import fcode +#from pyccel.ast.utilities import build_types_decorator +#from pyccel.ast.datatypes import get_default_value +from pyccel.parser.parser import Parser as PyccelParser + +from lampy.syntax import parse as parse_lambda +from lampy.semantic import Parser as SemanticParser +from lampy.codegen import AST +from lampy.utilities import get_decorators +from lampy.utilities import get_pyccel_imports_code +from lampy.utilities import get_dependencies_code +from lampy.utilities import math_atoms_as_str +from lampy.printing import pycode +from lampy.interface import LambdaInterface +from os import path +from pyccel.ast.basic import Basic +from sympy import Integral, Symbol, Tuple +from sympy.utilities.iterables import iterable +import random +import string +#============================================================================== +class AsName(Basic): + def __new__(cls, name, target): + + # TODO check + + return Basic.__new__(cls, name, target) + + @property + def name(self): + return self._args[0] + + @property + def target(self): + return self._args[1] + + def _sympystr(self, printer): + sstr = printer.doprint + return '{0} as {1}'.format(sstr(self.name), sstr(self.target)) + +#============================================================================== +class DottedName(Basic): + def __new__(cls, *args): + return Basic.__new__(cls, *args) + + @property + def name(self): + return self._args + + def __str__(self): + return """.""".join(str(n) for n in self.name) + + def _sympystr(self, printer): + sstr = printer.doprint + return """.""".join(sstr(n) for n in self.name) + + + +#============================================================================== +class Import(Basic): + + def __new__(cls, target, source=None): + + def _format(i): + if isinstance(i, str): + if '.' in i: + return DottedName(*i.split('.')) + else: + return Symbol(i) + if isinstance(i, (DottedName, AsName)): + return i + elif isinstance(i, Symbol): + return i + else: + raise TypeError('Expecting a string, Symbol DottedName, given {}'.format(type(i))) + + _target = [] + if isinstance(target, (str, Symbol, DottedName, AsName)): + _target = [_format(target)] + elif iterable(target): + for i in target: + _target.append(_format(i)) + target = Tuple(*_target, sympify=False) + + if not source is None: + source = _format(source) + + return Basic.__new__(cls, target, source) + + @property + def target(self): + return self._args[0] + + @property + def source(self): + return self._args[1] + + def _sympystr(self, printer): + sstr = printer.doprint + target = ', '.join([sstr(i) for i in self.target]) + if self.source is None: + return 'import {target}'.format(target=target) + else: + source = sstr(self.source) + return 'from {source} import {target}'.format(source=source, + target=target) +#============================================================================== + +def get_source_function(func): + if not callable(func): + raise TypeError('Expecting a callable function') + + lines = inspect.getsourcelines(func) + lines = lines[0] + # remove indentation if the first line is indented + a = lines[0] + leading_spaces = len(a) - len(a.lstrip()) + code = '' + for a in lines: + if leading_spaces > 0: + line = a[leading_spaces:] + else: + line = a + code = '{code}{line}'.format(code=code, line=line) + return code #============================================================================== +def write_code(filename, code, folder=None): + if not folder: + folder = os.getcwd() + folder = os.path.abspath(folder) + if not os.path.isdir(folder): + raise ValueError('{} folder does not exist'.format(folder)) + filename = os.path.basename( filename ) + filename = os.path.join(folder, filename) + # TODO check if init exists + # add __init__.py for imports + cmd = 'touch {}/__init__.py'.format(folder) + os.system(cmd) + f = open(filename, 'w') + for line in code: + f.write(line) + f.close() + return filename +#============================================================================== +def mkdir_p(dir): + # type: (unicode) -> None + if path.isdir(dir): + return + os.makedirs(dir) +#============================================================================== _accelerator_registery = {'openmp': 'omp', 'openacc': 'acc', None: None} +def random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) +#============================================================================== +def create_lampy_folder (code ): + + tag = random_string(8) + module_name = 'mod_{}'.format(tag) + pymod_filename = '{}.py'.format(module_name) + pymod_filepath = os.path.abspath(pymod_filename) + + # Store current directory + base_dirpath = os.getcwd() + + # Define working directory 'folder' + folder = os.path.dirname(pymod_filepath) + + # Define directory name and path for epyccel files + lampy_dirname = '__lampy__' + lampy_dirpath = os.path.join(folder, lampy_dirname) + + # Create new directories if not existing + os.makedirs(folder, exist_ok=True) + os.makedirs(lampy_dirpath, exist_ok=True) + + # Change working directory to '__epyccel__' + os.chdir(lampy_dirpath) + + # Store python file in '__epyccel__' folder, so that execute_pyccel can run + with open(pymod_filename, 'w') as f: + f.writelines(code) + + return pymod_filename #============================================================================== def _parse_typed_functions(user_functions): """generate ast for dependencies.""" code = get_pyccel_imports_code() code += get_dependencies_code(user_functions) - - pyccel = PyccelParser(code) + filename= create_lampy_folder(code) + pyccel = PyccelParser(filename) ast = pyccel.parse() - settings = {} ast = pyccel.annotate(**settings) return ast.namespace.functions @@ -104,6 +272,7 @@ def _lambdify(func, namespace={}, **kwargs): raise NotImplementedError('') typed_functions = _parse_typed_functions(list(user_functions.values())) + # ... # ... semantic analysis diff --git a/lampy/printing.py b/lampy/printing.py index 13d0299..21bfbec 100644 --- a/lampy/printing.py +++ b/lampy/printing.py @@ -3,7 +3,7 @@ from pyccel.codegen.printing.pycode import PythonCodePrinter as PyccelPythonCodePrinter -from .ast import BasicMap, PartialFunction +from lampy.ast import BasicMap, PartialFunction class PythonCodePrinter(PyccelPythonCodePrinter): @@ -50,6 +50,7 @@ def _print_BasicBlock(self, expr): # ... if expr.body: + body = '\n'.join(self._print(i) for i in expr.body) code = '{code}\n{new}'.format( code = code, @@ -58,6 +59,27 @@ def _print_BasicBlock(self, expr): return code + # ..................................................... + def _print_Block(self, expr): + code = '' + + # ... + if expr.declarations: + declarations = '\n'.join(self._print(i) for i in expr.declarations) + + code = '{code}\n{new}'.format(code=code, + new=declarations) + # ... + + # ... + if expr.body: + body =self._print(expr.body) + code = '{code}\n{new}'.format(code=code, + new=body) + # ... + + return code + # ..................................................... # OpenMP statements # ..................................................... diff --git a/lampy/semantic.py b/lampy/semantic.py index 3075f00..6308c70 100644 --- a/lampy/semantic.py +++ b/lampy/semantic.py @@ -2,7 +2,8 @@ import os from os.path import join, dirname - +import random +import string from sympy import Symbol, Lambda, Function, Dummy from sympy import Tuple, IndexedBase from sympy.core.function import AppliedUndef @@ -12,34 +13,39 @@ from sympy import FunctionClass -from pyccel.codegen.utilities import random_string +#from pyccel.codegen.utilities import random_string from pyccel.ast.utilities import build_types_decorator -from pyccel.ast.datatypes import Int, Real, Complex, Bool +from pyccel.ast.datatypes import Int, Real, Cmplx, Bool from pyccel.ast.core import Slice from pyccel.ast.core import Variable, FunctionDef, Assign, AugAssign from pyccel.ast.core import Return from pyccel.ast.basic import Basic -from .datatypes import assign_type, BasicTypeVariable -from .datatypes import TypeVariable, TypeTuple, TypeList, TypeFunction -from .lexeme import _internal_map_functors -from .lexeme import _internal_functors -from .lexeme import _internal_zip_functions -from .lexeme import _internal_product_functions -from .lexeme import _internal_applications -from .lexeme import _elemental_math_functions -from .lexeme import _math_vector_functions -from .lexeme import _math_matrix_functions -from .lexeme import _math_functions -from .ast import Map, ProductMap, TensorMap, Zip, Product -from .ast import BasicReduce, AddReduce, MulReduce -from .ast import BasicMap -from .ast import PartialFunction -from .ast import LampyLambda -from .ast import FunctionSymbol +from lampy.datatypes import assign_type, BasicTypeVariable +from lampy.datatypes import TypeVariable, TypeTuple, TypeList, TypeFunction +from lampy.lexeme import _internal_map_functors +from lampy.lexeme import _internal_functors +from lampy.lexeme import _internal_zip_functions +from lampy.lexeme import _internal_product_functions +from lampy.lexeme import _internal_applications +from lampy.lexeme import _elemental_math_functions +from lampy.lexeme import _math_vector_functions +from lampy.lexeme import _math_matrix_functions +from lampy.lexeme import _math_functions +from lampy.ast import Map, ProductMap, TensorMap, Zip, Product +from lampy.ast import BasicReduce, AddReduce, MulReduce +from lampy.ast import BasicMap +from lampy.ast import PartialFunction +from lampy.ast import LampyLambda +from lampy.ast import FunctionSymbol + #========================================================================= +def random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) + def sanitize(expr): if isinstance(expr, Lambda): args = expr.variables @@ -122,11 +128,11 @@ def __init__(self, expr, **kwargs): precision = 8 elif prefix == 'c': - dtype = Complex + dtype = Cmplx precision = 8 elif prefix == 'z': - dtype = Complex + dtype = Cmplx precision = 16 else: @@ -289,20 +295,14 @@ def _insert_function(self, f, type_domain, type_codomain): def doit(self, verbose=False): # ... compute type - i_count = 0 - max_count = 2 - while(i_count < max_count and not isinstance(self.main, BasicTypeVariable)): - if verbose: - print('----> BEFORE ', self.main) - self.main = self._visit(self.main) + if verbose: + print('----> BEFORE ', self.main) - if verbose: - print('<---- AFTER', self.main) - - i_count += 1 - # ... + self.main = self._visit(self.main) + if verbose: + print('<---- AFTER', self.main) return self.main def _visit(self, stmt, value=None): diff --git a/lampy/syntax.py b/lampy/syntax.py index 4974833..4c53a52 100644 --- a/lampy/syntax.py +++ b/lampy/syntax.py @@ -1,6 +1,8 @@ # coding: utf-8 import os +import random +import string from os.path import join, dirname from sympy import Symbol, Lambda, Function, Dummy @@ -8,16 +10,20 @@ from textx.metamodel import metamodel_from_str -from pyccel.codegen.utilities import random_string +#from pyccel.codegen.utilities import random_string -from .ast import AddReduce, MulReduce, FunctionSymbol, BasicMap -from .ast import _map_registery -from .ast import _, AnyArgument -from .ast import PartialFunction -from .lexeme import _internal_map_functors -from .lexeme import _internal_reduction_operators +from lampy.ast import AddReduce, MulReduce, FunctionSymbol, BasicMap +from lampy.ast import _map_registery +from lampy.ast import _, AnyArgument +from lampy.ast import PartialFunction +from lampy.lexeme import _internal_map_functors +from lampy.lexeme import _internal_reduction_operators #========================================================================== +def random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(length)) + class NamedAbstraction(object): def __init__(self, **kwargs): self.name = kwargs.pop('name') diff --git a/lampy/tests/test_math.py b/lampy/tests/test_math.py index ee92884..184f351 100644 --- a/lampy/tests/test_math.py +++ b/lampy/tests/test_math.py @@ -14,12 +14,11 @@ def test_annotate_map_list(**settings): sin = np.sin l = lambda xs: map(sin, xs) - L = _lambdify( l, **settings ) - xs = np.linspace(0., np.pi, 100) out = L(xs) expected = list(l(xs)) + assert(np.allclose( out, expected )) print('DONE.') diff --git a/lampy/tests/test_partial.py b/lampy/tests/test_partial.py index c5b9fb3..893a8ff 100644 --- a/lampy/tests/test_partial.py +++ b/lampy/tests/test_partial.py @@ -7,7 +7,7 @@ from pyccel.decorators import types, pure from pyccel.ast.datatypes import NativeInteger, NativeReal, NativeComplex, NativeBool - +from lampy.ast import PartialFunction from lampy.lambdify import _lambdify from lampy import TypeVariable, TypeTuple, TypeList from lampy import add, mul diff --git a/lampy/utilities.py b/lampy/utilities.py index c527f2d..b6a78ce 100644 --- a/lampy/utilities.py +++ b/lampy/utilities.py @@ -22,14 +22,14 @@ from sympy.printing.pycode import _known_functions_math from sympy.printing.pycode import _known_constants_math -from pyccel.codegen.utilities import get_source_function -from pyccel.ast.datatypes import dtype_and_precsision_registry as dtype_registry +from pyccel.epyccel import get_source_function +#from pyccel.ast.datatypes import dtype_and_precsision_registry as dtype_registry from pyccel.ast.core import Slice, String from pyccel.ast.datatypes import NativeInteger, NativeReal, NativeComplex, NativeBool from pyccel.ast.datatypes import get_default_value -from pyccel.parser import Parser +from pyccel.parser.parser import Parser -from .ast import FunctionSymbol +from lampy.ast import FunctionSymbol #========================================================================== def math_atoms_as_str(expr): @@ -70,7 +70,7 @@ def get_pyccel_imports_code(): code = '' code += '\nfrom pyccel.decorators import types' code += '\nfrom pyccel.decorators import pure' - code += '\nfrom pyccel.decorators import external, external_call' +# code += '\nfrom pyccel.decorators import external, external_call' # code += '\nfrom pyccel.decorators import shapes' # code += '\nfrom pyccel.decorators import workplace' # code += '\nfrom pyccel.decorators import stack_array'