Source code for pyccel.ast.numpyext

#!/usr/bin/python
# -*- coding: utf-8 -*-

# TODO remove sympify, Symbol

import numpy
from sympy.core.function import Function
from sympy.core import Symbol, Tuple
from sympy import sympify
from sympy.core.basic import Basic
from sympy import Integer as sp_Integer, Add, Mul, Pow as sp_Pow, Float as sp_Float
from sympy.utilities.iterables import iterable
from sympy.logic.boolalg import Boolean, BooleanTrue, BooleanFalse
from sympy.core.assumptions import StdFactKB
from sympy import sqrt, asin, acsc, acos, asec, atan, acot, sinh, cosh, tanh, log
from sympy import Rational as sp_Rational
from sympy import IndexedBase


from .core import (Variable, IndexedElement, IndexedVariable, 
                   List, String, ValuedArgument, Constant, Pow, int2float)
from .datatypes import dtype_and_precsision_registry as dtype_registry
from .datatypes import default_precision
from .datatypes import DataType, datatype
from .datatypes import (NativeInteger, NativeReal, NativeComplex,
                        NativeBool)

from .core import local_sympify ,float2int

numpy_constants = {
    'pi': Constant('real', 'pi', value=numpy.pi),
                  }

[docs]class Array(Function): """Represents a call to numpy.array for code generation. arg : list ,tuple ,Tuple,List """ def __new__(cls, arg, dtype=None, order='C'): if not isinstance(arg, (list, tuple, Tuple, List)): raise TypeError('Uknown type of %s.' % type(arg)) prec = 0 if not dtype is None: if isinstance(dtype, ValuedArgument): dtype = dtype.value dtype = str(dtype).replace('\'', '') arg = float2int(arg) if 'int' in dtype else arg dtype,prec = dtype_registry[dtype] dtype = datatype('ndarray' + dtype) if not prec and dtype: prec = default_precision[dtype] return Basic.__new__(cls, arg, dtype, order, prec) def _sympystr(self, printer): sstr = printer.doprint return self.arg @property def arg(self): return self._args[0] @property def dtype(self): return self._args[1] @property def order(self): return self._args[2] @property def precision(self): return self._args[3] @property def shape(self): return Tuple(*numpy.shape(self.arg)) @property def rank(self): return len(self.shape)
[docs] def fprint(self, printer, lhs): """Fortran print.""" if isinstance(self.shape, (Tuple, tuple)): # this is a correction. problem on LRZ shape_code = ', '.join('0:' + printer(i - 1) for i in self.shape) else: shape_code = '0:' + printer(self.shape - 1) lhs_code = printer(lhs) code_alloc = 'allocate({0}({1}))'.format(lhs_code, shape_code) arg = self.arg if self.rank > 1: import functools import operator arg = functools.reduce(operator.concat, arg) init_value = 'reshape(' + printer(arg) + ',' \ + printer(self.shape) + ')' else: init_value = printer(arg) code_init = '{0} = {1}'.format(lhs_code, init_value) code = '{0}\n{1}'.format(code_alloc, code_init) return code
[docs]class Sum(Function): """Represents a call to numpy.sum for code generation. arg : list , tuple , Tuple, List, Variable """ def __new__(cls, arg): if not isinstance(arg, (list, tuple, Tuple, List, Variable)): raise TypeError('Uknown type of %s.' % type(arg)) return Basic.__new__(cls, arg) @property def arg(self): return self._args[0] @property def dtype(self): return self._args[0].dtype @property def rank(self): return 0
[docs] def fprint(self, printer, lhs=None): """Fortran print.""" rhs_code = printer(self.arg) if lhs: lhs_code = printer(lhs) return '{0} = sum({1})'.format(lhs_code, rhs_code) return 'sum({0})'.format(rhs_code)
[docs]class Shape(Array): """Represents a call to numpy.shape for code generation. arg : list ,tuple ,Tuple,List, Variable """ def __new__(cls, arg, index=None): if not isinstance(arg, (list, tuple, Tuple, List, Array, Variable, IndexedElement, IndexedBase)): raise TypeError('Uknown type of %s.' % type(arg)) # TODO add check on index: must be Integer or Variable with dtype=int # TODO [YG, 09.10.2018]: Verify why index should be passed at all (not in Numpy!) return Basic.__new__(cls, arg, index) @property def arg(self): return self._args[0] @property def index(self): return self._args[1] @property def dtype(self): return 'ndarrayint' @property def shape(self): return Tuple(self.arg.rank) @property def rank(self): return 1
[docs] def fprint(self, printer, lhs = None): """Fortran print.""" lhs_code = printer(lhs) if isinstance(self.arg, Array): init_value = printer(self.arg.arg) else: init_value = printer(self.arg) init_value = ['size({0},{1})'.format(init_value, ind) for ind in range(1, self.arg.rank+1, 1)] if self.arg.order == 'C': init_value.reverse() init_value = ', '.join(i for i in init_value) if lhs: if self.index is None: code_init = '{0} = (/ {1} /)'.format(lhs_code, init_value) else: index = printer(self.index) code_init = '{0} = size({1}, {2})'.format(lhs_code, init_value, index) else: if self.index is None: code_init = '(/ {0} /)'.format(init_value) else: index = printer(self.index) code_init = 'size({0}, {1})'.format(init_value, index) return code_init
[docs]class Int(Function): """Represents a call to numpy.int for code generation. arg : Variable, Real, Integer, Complex """ def __new__(cls, arg): if not isinstance(arg, (Variable, sp_Float, sp_Integer, Mul, Add, sp_Pow, sp_Rational)): raise TypeError('Uknown type of %s.' % type(arg)) obj = Basic.__new__(cls, arg) assumptions = {'integer':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj @property def arg(self): return self._args[0] @property def dtype(self): return 'int' @property def shape(self): return None @property def rank(self): return 0 @property def precision(self): return 4
[docs] def fprint(self, printer): """Fortran print.""" value = printer(self.arg) code = 'Int({0})'.format(value) return code
[docs]class Real(Function): """Represents a call to numpy.Real for code generation. arg : Variable, Float, Integer, Complex """ def __new__(cls, arg): if not isinstance(arg, (Variable, sp_Integer, sp_Float, Mul, Add, sp_Pow, sp_Rational)): raise TypeError('Uknown type of %s.' % type(arg)) obj = Basic.__new__(cls, arg) assumptions = {'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj @property def arg(self): return self._args[0] @property def dtype(self): return 'int' @property def shape(self): return None @property def rank(self): return 0 @property def precision(self): return 8
[docs] def fprint(self, printer): """Fortran print.""" value = printer(self.arg) code = 'Real({0})'.format(value) return code
def __str__(self): return 'Float({0})'.format(str(self.arg)) def _sympystr(self, printer): return self.__str__()
[docs]class Complex(Function): """Represents a call to numpy.complex for code generation. arg : Variable, Float, Integer """ def __new__(cls, arg0, arg1=sp_Float(0)): for arg in [arg0, arg1]: if not isinstance(arg, (Variable, sp_Integer, sp_Float, Mul, Add, sp_Pow, sp_Rational)): raise TypeError('Uknown type of %s.' % type(arg)) obj = Basic.__new__(cls, arg0, arg1) assumptions = {'complex':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj @property def real_part(self): return self._args[0] @property def imag_part(self): return self._args[1] @property def dtype(self): return 'complex' @property def shape(self): return None @property def rank(self): return 0 @property def precision(self): return 8
[docs] def fprint(self, printer): """Fortran print.""" value0 = printer(self.real_part) value1 = printer(self.imag_part) code = 'complex({0},{1})'.format(value0,value1) return code
def __str__(self): return self.fprint(str) def _sympystr(self, printer): return self.fprint(str)
[docs]class Rand(Real): """Represents a call to numpy.random.random or numpy.random.rand for code generation. arg : list ,tuple ,Tuple,List """ @property def arg(self): return self._args[0] @property def rank(self): return 0
[docs] def fprint(self, printer): """Fortran print.""" rhs_code = printer(self.arg) if len(self.arg) == 0: rhs_code = '' return 'rand({0})'.format(rhs_code)
[docs]class Zeros(Function): """Represents a call to numpy.zeros for code generation. shape : int, list, tuple int or list of integers dtype: str, DataType datatype for the constructed array Examples """ # TODO improve def __new__(cls, shape,*args): args = list(args) args_= {'dtype':'real','order':'C'} prec = 0 val_args = [] for i in range(len(args)): if isinstance(args[i], ValuedArgument): val_args = args[i:] args[i:] = [] break if len(args)==1: args_['dtype'] = str(args[0]) elif len(args)==2: args_['dtype'] = str(args[0]) args_['order'] = str(args[1]) for i in val_args: val = str(i.value).replace('\'', '') args_[str(i.argument.name)] = val dtype = args_['dtype'] order = args_['order'] if isinstance(shape,Tuple): shape = list(shape) if isinstance(shape, list): if order == 'C': shape.reverse() # this is a correction. otherwise it is not working on LRZ if isinstance(shape[0], list): shape = Tuple(*(sympify(i, locals = local_sympify) for i in shape[0])) else: shape = Tuple(*(sympify(i, locals = local_sympify) for i in shape)) elif isinstance(shape, (int, sp_Integer, Symbol)): shape = Tuple(sympify(shape, locals = local_sympify)) else: shape = shape if isinstance(dtype, str): dtype = dtype.replace('\'', '') dtype, prec = dtype_registry[dtype] dtype = datatype('ndarray' + dtype) elif not isinstance(dtype, DataType): raise TypeError('datatype must be an instance of DataType.') if not prec: prec = default_precision[str(dtype)] return Basic.__new__(cls, shape, dtype, order, prec) @property def shape(self): return self._args[0] @property def rank(self): if iterable(self.shape): return len(self.shape) else: return 1 @property def dtype(self): return self._args[1] @property def order(self): return self._args[2] @property def precision(self): return self._args[3] @property def init_value(self): dtype = self.dtype if isinstance(dtype, NativeInteger): value = 0 elif isinstance(dtype, NativeReal): value = 0.0 elif isinstance(dtype, NativeComplex): value = 0.0 elif isinstance(dtype, NativeBool): value = BooleanFalse() else: raise TypeError('Unknown type') return value
[docs] def fprint(self, printer, lhs): """Fortran print.""" if isinstance(self.shape, (Tuple,tuple)): # this is a correction. problem on LRZ shape_code = ', '.join('0:' + printer(i - 1) for i in self.shape) else: shape_code = '0:' + printer(self.shape - 1) init_value = printer(self.init_value) lhs_code = printer(lhs) code_alloc = 'allocate({0}({1}))'.format(lhs_code, shape_code) code_init = '{0} = {1}'.format(lhs_code, init_value) code = '{0}\n{1}'.format(code_alloc, code_init) return code
[docs]class Ones(Zeros): """Represents a call to numpy.ones for code generation. shape : int or list of integers """ @property def init_value(self): dtype = self.dtype if isinstance(dtype, NativeInteger): value = 1 elif isinstance(dtype, NativeReal): value = 1.0 elif isinstance(dtype, NativeComplex): value = 1.0 elif isinstance(dtype, NativeBool): value = BooleanTrue() else: raise TypeError('Unknown type') return value
[docs]class Empty(Zeros): """Represents a call to numpy.empty for code generation. shape : int or list of integers """
[docs] def fprint(self, printer, lhs): """Fortran print.""" if isinstance(self.shape, Tuple): # this is a correction. problem on LRZ shape_code = ', '.join('0:' + printer(i - 1) for i in self.shape) else: shape_code = '0:' + printer(self.shape - 1) lhs_code = printer(lhs) code = 'allocate({0}({1}))'.format(lhs_code, shape_code) return code
[docs]class Sqrt(Pow): def __new__(cls, base): return Pow(base, 0.5, evaluate=False)
[docs]class Asin(Function): def __new__(cls,arg): obj = asin(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Acos(Function): def __new__(cls,arg): obj = acos(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Asec(Function): def __new__(cls,arg): obj = asec(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Atan(Function): def __new__(cls,arg): obj = atan(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Acot(Function): def __new__(cls,arg): obj = acot(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Acsc(Function): def __new__(cls,arg): obj = acsc(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Sinh(Function): def __new__(cls,arg): obj = sinh(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Cosh(Function): def __new__(cls,arg): obj = cosh(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Tanh(Function): def __new__(cls,arg): obj = tanh(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Log(Function): def __new__(cls,arg): obj = log(arg) if arg.is_real: assumptions={'real':True} ass_copy = assumptions.copy() obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = ass_copy return obj
[docs]class Abs(Function): def _eval_is_integer(self): return all(i.is_integer for i in self.args) def _eval_is_real(self): return True
[docs]class Min(Function): def _eval_is_integer(self): return all(i.is_integer for i in self.args) def _eval_is_real(self): return True
[docs]class Max(Function): def _eval_is_integer(self): return all(i.is_integer for i in self.args) def _eval_is_real(self): return True
[docs]class Complex64(Complex): @property def precision(self): return 4
[docs]class Complex128(Complex): pass
[docs]class Float32(Real): @property def precision(self): return 4
[docs]class Float64(Real): pass
[docs]class Int32(Int): pass
[docs]class Int64(Int): @property def precision(self): return 8