B
    [-J                 @   s  d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZmZ ddlmZ dd	lmZmZmZmZmZmZmZmZmZmZmZ dd
lmZmZ ddlm Z  edZ!edZ"edZ#edZ$edZ%edZ&G dd deZ'G dd deZ(dd Z)G dd deZ*G dd deZ+G dd deZ,G dd deZ-G d d! d!eZ.G d"d# d#eZ/G d$d% d%eZ0G d&d' d'eZ1e1 Z2d(d) Z3e3d*Z4dZd,d-Z5d.d/ Z6d0d1 Z7d[d2d3Z8d\d4d5Z9d]d6d7Z:d^d8d9Z;d_d:d;Z<d`d<d=Z=G d>d? d?eZ>G d@dA dAeZ?G dBdC dCe
Z@G dDdE dEe@ZAG dFdG dGe@ZBG dHdI dIe@ZCG dJdK dKe@ZDG dLdM dMe@ZEG dNdO dOeAZFG dPdQ dQeZGG dRdS dSeGZHG dTdU dUeGZIG dVdW dWeeZJG dXdY dYeeZKd+S )az
AST nodes specific to Fortran.

The functions defined in this module allows the user to express functions such as ``dsign``
as a SymPy function for symbolic manipulation.
    )Basic)Expr)string_types)Tuple)Function)FloatInteger)sympify)	Attribute	CodeBlockDeclarationFunctionCallNodenoneStringTokenType	_mk_TupleVariable)truefalse)iterablepure	elemental	intent_in
intent_outintent_inoutallocatablec               @   s(   e Zd ZdZddgZeZedd ZdS )Programam   Represents a 'program' block in Fortran

    Examples
    ========

    >>> from sympy.codegen.ast import Print
    >>> from sympy.codegen.fnodes import Program
    >>> prog = Program('myprogram', [Print([42])])
    >>> from sympy.printing import fcode
    >>> print(fcode(prog, source_format='free'))
    program myprogram
        print *, 42
    end program
    namebodyc             C   s   t |  S )N)r   )r     r!   3lib/python3.7/site-packages/sympy/codegen/fnodes.py<lambda>2   s    zProgram.<lambda>N)	__name__
__module____qualname____doc__	__slots__r   _construct_namestaticmethod_construct_bodyr!   r!   r!   r"   r   !   s   r   c               @   s    e Zd ZdZddgZeZeZdS )
use_renamea   Represents a renaming in a use statement in Fortran

    Examples
    ========

    >>> from sympy.codegen.fnodes import use_rename, use
    >>> from sympy.printing import fcode
    >>> ren = use_rename("thingy", "convolution2d")
    >>> print(fcode(ren, source_format='free'))
    thingy => convolution2d
    >>> full = use('signallib', only=['snr', ren])
    >>> print(fcode(full, source_format='free'))
    use signallib, only: snr, thingy => convolution2d
    ZlocalZoriginalN)r$   r%   r&   r'   r(   r   Z_construct_localZ_construct_originalr!   r!   r!   r"   r,   5   s   r,   c             C   s   t | dr| jS t| S d S )Nr   )hasattrr   r   )argr!   r!   r"   _nameH   s    
r/   c               @   sD   e Zd ZdZdddgZeedZeeZ	edd Z
edd Zd	S )
usea   Represents a use statement in Fortran

    Examples
    ========

    >>> from sympy.codegen.fnodes import use
    >>> from sympy.printing import fcode
    >>> fcode(use('signallib'), source_format='free')
    'use signallib'
    >>> fcode(use('signallib', [('metric', 'snr')]), source_format='free')
    'use signallib, metric => snr'
    >>> fcode(use('signallib', only=['snr', 'convolution2d']), source_format='free')
    'use signallib, only: snr, convolution2d'
    	namespacerenameonly)r2   r3   c             C   s   t dd | D  S )Nc             S   s"   g | ]}t |tr|nt| qS r!   )
isinstancer,   ).0r.   r!   r!   r"   
<listcomp>`   s    z use.<lambda>.<locals>.<listcomp>)r   )argsr!   r!   r"   r#   `   s    zuse.<lambda>c             C   s   t dd | D  S )Nc             S   s"   g | ]}t |tr|nt|qS r!   )r4   r,   r/   )r5   r.   r!   r!   r"   r6   a   s    z use.<lambda>.<locals>.<listcomp>)r   )r7   r!   r!   r"   r#   a   s    N)r$   r%   r&   r'   r(   r   defaultsr*   r/   Z_construct_namespaceZ_construct_renameZ_construct_onlyr!   r!   r!   r"   r0   N   s   

r0   c               @   s@   e Zd ZdZdddgZde iZeZe	dd Z
e	dd ZdS )	Modulead   Represents a module in Fortran

    Examples
    ========

    >>> from sympy.codegen.fnodes import Module
    >>> from sympy.printing import fcode
    >>> print(fcode(Module('signallib', ['implicit none'], []), source_format='free'))
    module signallib
    implicit none
    <BLANKLINE>
    contains
    <BLANKLINE>
    <BLANKLINE>
    end module

    r   ZdeclarationsZdefinitionsc             C   s   t |  S )N)r   )r.   r!   r!   r"   r#   y   s    zModule.<lambda>c             C   s   t |  S )N)r   )r.   r!   r!   r"   r#   z   s    N)r$   r%   r&   r'   r(   r   r8   r   r)   r*   Z_construct_declarationsZ_construct_definitionsr!   r!   r!   r"   r9   d   s   

r9   c               @   s8   e Zd ZdZddddgZeZedd Ze	dd	 Z
d
S )
Subroutinea
   Represents a subroutine in Fortran

    Examples
    ========

    >>> from sympy import symbols
    >>> from sympy.codegen.ast import Print
    >>> from sympy.codegen.fnodes import Subroutine
    >>> from sympy.printing import fcode
    >>> x, y = symbols('x y', real=True)
    >>> sub = Subroutine('mysub', [x, y], [Print([x**2 + y**2, x*y])])
    >>> print(fcode(sub, source_format='free', standard=2003))
    subroutine mysub(x, y)
    real*8 :: x
    real*8 :: y
    print *, x**2 + y**2, x*y
    end subroutine
    r   
parametersr    attrsc             C   s   t ttj|  S )N)r   mapr   deduced)Zparamsr!   r!   r"   r#      s    zSubroutine.<lambda>c             C   s   t |tr|S t| S d S )N)r4   r   )clsZitrr!   r!   r"   r+      s    
zSubroutine._construct_bodyN)r$   r%   r&   r'   r(   r   r)   r*   Z_construct_parametersclassmethodr+   r!   r!   r!   r"   r:   }   s
   r:   c               @   s(   e Zd ZdZddgZeeZeeZ	dS )SubroutineCalla   Represents a call to a subroutine in Fortran

    Examples
    ========

    >>> from sympy.codegen.fnodes import SubroutineCall
    >>> from sympy.printing import fcode
    >>> fcode(SubroutineCall('mysub', 'x y'.split()))
    '       call mysub(x, y)'
    r   Zsubroutine_argsN)
r$   r%   r&   r'   r(   r*   r/   r)   r   Z_construct_subroutine_argsr!   r!   r!   r"   rA      s   
rA   c               @   sf   e Zd ZdZddddddgZeded	Zed
d Z	ee
Zee
Zee
Zee
Zedd ZdS )Doa   Represents a Do loop in in Fortran

    Examples
    ========

    >>> from sympy import symbols
    >>> from sympy.codegen.ast import aug_assign, Print
    >>> from sympy.codegen.fnodes import Do
    >>> from sympy.printing import fcode
    >>> i, n = symbols('i n', integer=True)
    >>> r = symbols('r', real=True)
    >>> body = [aug_assign(r, '+', 1/i), Print([i, r])]
    >>> do1 = Do(body, i, 1, n)
    >>> print(fcode(do1, source_format='free'))
    do i = 1, n
        r = r + 1d0/i
        print *, i, r
    end do
    >>> do2 = Do(body, i, 1, n, 2)
    >>> print(fcode(do2, source_format='free'))
    do i = 1, n, 2
        r = r + 1d0/i
        print *, i, r
    end do
    r    counterfirstlaststep
concurrent   )rF   rG   c             C   s   t |  S )N)r   )r    r!   r!   r"   r#      s    zDo.<lambda>c             C   s   | rt S tS )N)r   r   )r.   r!   r!   r"   r#      s    N)r$   r%   r&   r'   r(   r   r   r8   r*   r+   r	   _construct_counter_construct_first_construct_last_construct_stepZ_construct_concurrentr!   r!   r!   r"   rB      s   rB   c               @   s   e Zd ZdZdgZeeZdS )ArrayConstructora\   Represents an array constructor

    Examples
    ========

    >>> from sympy.printing import fcode
    >>> from sympy.codegen.fnodes import ArrayConstructor
    >>> ac = ArrayConstructor([1, 2, 3])
    >>> fcode(ac, standard=95, source_format='free')
    '(/1, 2, 3/)'
    >>> fcode(ac, standard=2003, source_format='free')
    '[1, 2, 3]'

    elementsN)r$   r%   r&   r'   r(   r*   r   Z_construct_elementsr!   r!   r!   r"   rM      s   rM   c               @   sR   e Zd ZdZdddddgZdediZeeZ	eeZ
eeZeeZeeZdS )	ImpliedDoLoopa   Represents an implied do loop in Fortran

    Examples
    ========

    >>> from sympy import Symbol, fcode
    >>> from sympy.codegen.fnodes import ImpliedDoLoop, ArrayConstructor
    >>> i = Symbol('i', integer=True)
    >>> idl = ImpliedDoLoop(i**3, i, -3, 3, 2)  # -27, -1, 1, 27
    >>> ac = ArrayConstructor([-28, idl, 28]) # -28, -27, -1, 1, 27, 28
    >>> fcode(ac, standard=2003, source_format='free')
    '[-28, (i**3, i = -3, 3, 2), 28]'

    exprrC   rD   rE   rF   rH   N)r$   r%   r&   r'   r(   r   r8   r*   r	   _construct_exprrI   rJ   rK   rL   r!   r!   r!   r"   rO      s   rO   c               @   s    e Zd ZdZdd Zdd ZdS )ExtentaL   Represents a dimension extent.

    Examples
    ========

    >>> from sympy.codegen.fnodes import Extent
    >>> e = Extent(-3, 3)  # -3, -2, -1, 0, 1, 2, 3
    >>> from sympy.printing import fcode
    >>> fcode(e, source_format='free')
    '-3:3'
    >>> from sympy.codegen.ast import Variable, real
    >>> from sympy.codegen.fnodes import dimension, intent_out
    >>> dim = dimension(e, e)
    >>> arr = Variable('x', real, attrs=[dim, intent_out])
    >>> fcode(arr.as_Declaration(), source_format='free', standard=2003)
    'real*8, dimension(-3:3, -3:3), intent(out) :: x'

    c             G   sd   t |dkr*|\}}t| t|t|S t |dksNt |dkrX|d dkrXt| S tdd S )N   r   rH   ):Nz5Expected 0 or 2 args (or one argument == None or ':'))lenr   __new__r	   
ValueError)r?   r7   ZlowZhighr!   r!   r"   rV     s    $
zExtent.__new__c             C   s   t | jdkrdS d| j S )Nr   rT   z%d:%d)rU   r7   )selfprinterr!   r!   r"   	_sympystr  s    zExtent._sympystrN)r$   r%   r&   r'   rV   rZ   r!   r!   r!   r"   rR      s   	rR   c              G   s   t | dkrtdg }xx| D ]p}t|tr8|| qt|trh|dkrX|t  q|t| qt|r|t|  q|t| qW t | dkrtdt	d|S )a   Creates a 'dimension' Attribute with (up to 7) extents.

    Examples
    ========

    >>> from sympy.printing import fcode
    >>> from sympy.codegen.fnodes import dimension, intent_in
    >>> dim = dimension('2', ':')  # 2 rows, runtime determined number of columns
    >>> from sympy.codegen.ast import Variable, integer
    >>> arr = Variable('a', integer, attrs=[dim, intent_in])
    >>> fcode(arr.as_Declaration(), source_format='free', standard=2003)
    'integer*4, dimension(2, :), intent(in) :: a'

       z0Fortran only supports up to 7 dimensional arraysrT   r   zNeed at least one dimension	dimension)
rU   rW   r4   rR   appendr   r   r   r	   r
   )r7   r;   r.   r!   r!   r"   r\     s     


r\   *Nc             K   s   t |tr*t|jdkr2tdt| nt| }t|dg |g }|dk	rx|tt	t
fkrntt	t
d| }|| |dd}|dd}|dkrtj| ||dS t| |||dS dS )	a   Convenience function for creating a Variable instance for a Fortran array

    Parameters
    ==========

    symbol : symbol
    dim : Attribute or iterable
        If dim is an ``Attribute`` it need to have the name 'dimension'. If it is
        not an ``Attribute``, then it is passsed to :func:`dimension` as ``*dim``
    intent : str
        One of: 'in', 'out', 'inout' or None
    \*\*kwargs:
        Keyword arguments for ``Variable`` ('type' & 'value')

    Examples
    ========

    >>> from sympy.printing import fcode
    >>> from sympy.codegen.ast import integer, real
    >>> from sympy.codegen.fnodes import array
    >>> arr = array('a', '*', 'in', type=integer)
    >>> print(fcode(arr.as_Declaration(), source_format='free', standard=2003))
    integer*4, dimension(*), intent(in) :: a
    >>> x = array('x', [3, ':', ':'], intent='out', type=real)
    >>> print(fcode(x.as_Declaration(value=1), source_format='free', standard=2003))
    real*8, dimension(3, :, :), intent(out) :: x = 1
    r\   z/Got an unexpected Attribute argument as dim: %sr<   N)inoutZinoutvaluetype)ra   r<   )r4   r
   strr   rW   r\   listpopr   r   r   r]   r   r>   )ZsymboldimZintentkwargsr<   ra   Ztype_r!   r!   r"   arrayD  s    

rh   c             C   s   t | trt| S t| S )N)r4   r   r   r	   )r.   r!   r!   r"   
_printabler  s    ri   c             C   s   t dt| gS )a    Creates an AST node for a function call to Fortran's "allocated(...)"

    Examples
    ========

    >>> from sympy.printing import fcode
    >>> from sympy.codegen.fnodes import allocated
    >>> alloc = allocated('x')
    >>> fcode(alloc, source_format='free')
    'allocated(x)'
    	allocated)r   ri   )rh   r!   r!   r"   rj   v  s    rj   c             C   s4   t dt| g|rt|gng  |r,t|gng  S )ax   Creates an AST node for a function call to Fortran's "lbound(...)"

    Parameters
    ==========

    array : Symbol or String
    dim : expr
    kind : expr

    Examples
    ========

    >>> from sympy.printing import fcode
    >>> from sympy.codegen.fnodes import lbound
    >>> lb = lbound('arr', dim=2)
    >>> fcode(lb, source_format='free')
    'lbound(arr, 2)'
    lbound)r   ri   )rh   rf   kindr!   r!   r"   rk     s    rk   c             C   s4   t dt| g|rt|gng  |r,t|gng  S )Nubound)r   ri   )rh   rf   rl   r!   r!   r"   rm     s    rm   c             C   s"   t dt| g|rt|gng  S )aZ   Creates an AST node for a function call to Fortran's "shape(...)"

    Parameters
    ==========

    source : Symbol or String
    kind : expr

    Examples
    ========

    >>> from sympy.printing import fcode
    >>> from sympy.codegen.fnodes import shape
    >>> shp = shape('x')
    >>> fcode(shp, source_format='free')
    'shape(x)'
    shape)r   ri   )sourcerl   r!   r!   r"   rn     s    rn   c             C   s4   t dt| g|rt|gng  |r,t|gng  S )a   Creates an AST node for a function call to Fortran's "size(...)"

    Examples
    ========

    >>> from sympy import Symbol
    >>> from sympy.printing import fcode
    >>> from sympy.codegen.ast import FunctionDefinition, real, Return, Variable
    >>> from sympy.codegen.fnodes import array, sum_, size
    >>> a = Symbol('a', real=True)
    >>> body = [Return((sum_(a**2)/size(a))**.5)]
    >>> arr = array(a, dim=[':'], intent='in')
    >>> fd = FunctionDefinition(real, 'rms', [arr], body)
    >>> print(fcode(fd, source_format='free', standard=2003))
    real*8 function rms(a)
    real*8, dimension(:), intent(in) :: a
    rms = sqrt(sum(a**2)*1d0/size(a))
    end function

    size)r   ri   )rh   rf   rl   r!   r!   r"   rp     s    rp   c             C   s:   t dt| t|g|r t|gng  |r2t|gng  S )z Creates an AST node for a function call to Fortran's "reshape(...)"

    Parameters
    ==========

    source : Symbol or String
    shape : ArrayExpr
    reshape)r   ri   )ro   rn   Zpadorderr!   r!   r"   rq     s    	 rq   c             C   s   t d| rt| gng S )a*   Creates an Attribute ``bind_C`` with a name

    Parameters
    ==========

    name : str

    Examples
    ========

    >>> from sympy import Symbol
    >>> from sympy.printing import fcode
    >>> from sympy.codegen.ast import FunctionDefinition, real, Return, Variable
    >>> from sympy.codegen.fnodes import array, sum_, size, bind_C
    >>> a = Symbol('a', real=True)
    >>> s = Symbol('s', integer=True)
    >>> arr = array(a, dim=[s], intent='in')
    >>> body = [Return((sum_(a**2)/s)**.5)]
    >>> fd = FunctionDefinition(real, 'rms', [arr, s], body, attrs=[bind_C('rms')])
    >>> print(fcode(fd, source_format='free', standard=2003))
    real*8 function rms(a, s) bind(C, name="rms")
    real*8, dimension(s), intent(in) :: a
    integer*4 :: s
    rms = sqrt(sum(a**2)/s)
    end function
    bind_C)r
   r   )r   r!   r!   r"   rs     s    rs   c               @   s0   e Zd ZdZddgZdeiZeeZ	ee
ZdS )GoToa   Represents a goto statement in Fortran

    Examples
    ========

    >>> from sympy.codegen.fnodes import GoTo
    >>> go = GoTo([10, 20, 30], 'i')
    >>> from sympy.printing import fcode
    >>> fcode(go, source_format='free')
    'go to (10, 20, 30), i'
    labelsrP   N)r$   r%   r&   r'   r(   r   r8   r*   r   Z_construct_labelsr	   rQ   r!   r!   r!   r"   rt     s
   rt   c               @   s&   e Zd ZdZdgZdeiZeeZ	dS )FortranReturna2   AST node explicitly mapped to a fortran "return".

    Because a return statement in fortran is different from C, and
    in order to aid reuse of our codegen ASTs the ordinary
    ``.codegen.ast.Return`` is interpreted as assignment to
    the result variable of the function. If one for some reason needs
    to generate a fortran RETURN statement, this node should be used.

    Examples
    ========

    >>> from sympy.codegen.fnodes import FortranReturn
    >>> from sympy.printing import fcode
    >>> fcode(FortranReturn('x'))
    '       return x'
    Zreturn_valueN)
r$   r%   r&   r'   r(   r   r8   r*   r	   Z_construct_return_valuer!   r!   r!   r"   rv     s   rv   c               @   s   e Zd ZdZdd ZdS )	FFunctionM   c             C   sF   | j j}|jd | jk r*td|| jf d|dt|j| j	S )NZstandardz%s requires Fortran %d or newerz{0}({1})z, )
	__class__r$   Z	_settings_required_standardNotImplementedErrorformatjoinr=   Z_printr7   )rX   rY   r   r!   r!   r"   _fcode8  s
    zFFunction._fcodeN)r$   r%   r&   rz   r~   r!   r!   r!   r"   rw   5  s   rw   c               @   s   e Zd ZdZdS )F95Function_   N)r$   r%   r&   rz   r!   r!   r!   r"   r   @  s   r   c               @   s   e Zd ZdZdZdS )isignz/ Fortran sign intrinsic for integer arguments. rS   N)r$   r%   r&   r'   nargsr!   r!   r!   r"   r   D  s   r   c               @   s   e Zd ZdZdZdS )dsignz8 Fortran sign intrinsic for double precision arguments. rS   N)r$   r%   r&   r'   r   r!   r!   r!   r"   r   I  s   r   c               @   s   e Zd ZdZdZdS )cmplxz& Fortran complex conversion function. rS   N)r$   r%   r&   r'   r   r!   r!   r!   r"   r   N  s   r   c               @   s   e Zd ZdZdZdS )rl   z Fortran kind function. rH   N)r$   r%   r&   r'   r   r!   r!   r!   r"   rl   S  s   rl   c               @   s   e Zd ZdZdZdS )mergez Fortran merge function    N)r$   r%   r&   r'   r   r!   r!   r!   r"   r   X  s   r   c               @   s   e Zd ZdZdZdd ZdS )_literalNc             O   sp   d | j|  d\}}|dd}|d |dd  d }}|dkrRdn|}|p\d| j | |pld S )	Nz%.{0}ee0.r   rH   + )r|   	_decimalssplitstriprstriplstrip_token)rX   rY   r7   rg   ZmantissaZsgnd_exZex_sgnZex_numr!   r!   r"   r~   a  s
    z_literal._fcode)r$   r%   r&   r   r   r~   r!   r!   r!   r"   r   ]  s   r   c               @   s   e Zd ZdZdZdZdS )
literal_spz' Fortran single precision real literal r   	   N)r$   r%   r&   r'   r   r   r!   r!   r!   r"   r   i  s   r   c               @   s   e Zd ZdZdZdZdS )
literal_dpz' Fortran double precision real literal d   N)r$   r%   r&   r'   r   r   r!   r!   r!   r"   r   o  s   r   c               @   s0   e Zd ZdddgZeedZeeZeeZ	dS )sum_rh   rf   mask)rf   r   N)
r$   r%   r&   r(   r   r8   r*   r	   _construct_array_construct_dimr!   r!   r!   r"   r   u  s   

r   c               @   s0   e Zd ZdddgZeedZeeZeeZ	dS )product_rh   rf   r   )rf   r   N)
r$   r%   r&   r(   r   r8   r*   r	   r   r   r!   r!   r!   r"   r   |  s   

r   )N)NN)NN)N)NN)NN)N)Lr'   Zsympy.core.basicr   Zsympy.core.exprr   Zsympy.core.compatibilityr   Zsympy.core.containersr   Zsympy.core.functionr   Zsympy.core.numbersr   r   Zsympy.core.sympifyr	   Zsympy.codegen.astr
   r   r   r   r   r   r   r   r   r   r   Zsympy.logicr   r   Zsympy.utilities.iterablesr   r   r   r   r   r   r   r   r,   r/   r0   r9   r:   rA   rB   rM   rO   rR   Zassumed_extentr\   Zassumed_sizerh   ri   rj   rk   rm   rn   rp   rq   rs   rt   rv   rw   r   r   r   r   rl   r   r   r   r   r   r   r!   r!   r!   r"   <module>   sj   4%!#
.

	



