o
    *ήc2#                     @   sx   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 d dlmZmZmZmZmZ G dd	 d	eZd
S )    )permutedims)Number)S)Symbol)sympify)MutableDenseNDimArray)TensorTensExprTensAddTensMulTensorIndexc                   @   s   e Zd ZdZdd Zedd Zedd Zedd	 Z	d
d Z
dd Zdd Zdd Zdd Zdd Zedd Zedd Zdd ZdS )PartialDerivativea
  
    Partial derivative for tensor expressions.

    Examples
    ========

    >>> from sympy.tensor.tensor import TensorIndexType, TensorHead
    >>> from sympy.tensor.toperators import PartialDerivative
    >>> from sympy import symbols
    >>> L = TensorIndexType("L")
    >>> A = TensorHead("A", [L])
    >>> B = TensorHead("B", [L])
    >>> i, j, k = symbols("i j k")

    >>> expr = PartialDerivative(A(i), A(j))
    >>> expr
    PartialDerivative(A(i), A(j))

    The ``PartialDerivative`` object behaves like a tensorial expression:

    >>> expr.get_indices()
    [i, -j]

    Notice that the deriving variables have opposite valence than the
    printed one: ``A(j)`` is printed as covariant, but the index of the
    derivative is actually contravariant, i.e. ``-j``.

    Indices can be contracted:

    >>> expr = PartialDerivative(A(i), A(i))
    >>> expr
    PartialDerivative(A(L_0), A(L_0))
    >>> expr.get_indices()
    [L_0, -L_0]

    The method ``.get_indices()`` always returns all indices (even the
    contracted ones). If only uncontracted indices are needed, call
    ``.get_free_indices()``:

    >>> expr.get_free_indices()
    []

    Nested partial derivatives are flattened:

    >>> expr = PartialDerivative(PartialDerivative(A(i), A(j)), A(k))
    >>> expr
    PartialDerivative(A(i), A(j), A(k))
    >>> expr.get_indices()
    [i, -j, -k]

    Replace a derivative with array values:

    >>> from sympy.abc import x, y
    >>> from sympy import sin, log
    >>> compA = [sin(x), log(x)*y**3]
    >>> compB = [x, y]
    >>> expr = PartialDerivative(A(i), B(j))
    >>> expr.replace_with_arrays({A(i): compA, B(i): compB})
    [[cos(x), 0], [y**3/x, 3*y**2*log(x)]]

    The returned array is indexed by `(i, -j)`.

    Be careful that other SymPy modules put the indices of the deriving
    variables before the indices of the derivand in the derivative result.
    For example:

    >>> expr.get_free_indices()
    [i, -j]

    >>> from sympy import Matrix, Array
    >>> Matrix(compA).diff(Matrix(compB)).reshape(2, 2)
    [[cos(x), y**3/x], [0, 3*y**2*log(x)]]
    >>> Array(compA).diff(Array(compB))
    [[cos(x), y**3/x], [0, 3*y**2*log(x)]]

    These are the transpose of the result of ``PartialDerivative``,
    as the matrix and the array modules put the index `-j` before `i` in the
    derivative result. An array read with index order `(-j, i)` is indeed the
    transpose of the same array read with index order `(i, -j)`. By specifying
    the index order to ``.replace_with_arrays`` one can get a compatible
    expression:

    >>> expr.replace_with_arrays({A(i): compA, B(i): compB}, [-j, i])
    [[cos(x), y**3/x], [0, 3*y**2*log(x)]]
    c                 G   sZ   t |tr|j| }|j}| t||\}}}}tj| g|R  }||_||_	||_
|S N)
isinstancer   	variablesexpr _contract_indices_for_derivativer   r	   __new___indices_free_dum)clsr   r   argsindicesfreedumobj r   >/tmp/pip-target-vg8gfxp4/lib/python/sympy/tensor/toperators.pyr   b   s   

zPartialDerivative.__new__c                 C   s   t jS r   )r   Oneselfr   r   r   coeffs   s   zPartialDerivative.coeffc                 C   s   | S r   r   r    r   r   r   nocoeffw   s   zPartialDerivative.nocoeffc                 C   s   g }|D ]#}t |tr| }||dd |D  qt |tr'|| qtj|g| dd\}}}}	tdt	|D ]}|| }
t |
tr\||  }|| dd |D ||< q=||||	fS )Nc                 S      i | ]}|| qS r   r   .0kr   r   r   
<dictcomp>       zFPartialDerivative._contract_indices_for_derivative.<locals>.<dictcomp>T)replace_indices   c                 S   r$   r   r   r%   r   r   r   r(      r)   )
r   r   get_free_indicesappendxreplacer   r   _tensMul_contract_indicesrangelen)r   r   r   variables_opposite_valenceii_free_indicesr   r   r   r   args_i	i_indicesr   r   r   r   {   s(   




z2PartialDerivative._contract_indices_for_derivativec                 K   s8   |  | j| j\}}}}| j| }||_||_||_|S r   )r   r   r   funcr   r   r   )r!   hintsr   r   r   r   r   r   r   r   doit   s   
zPartialDerivative.doitc                    sB   jj\}}}}j|  | _| _| _ }|d js$tj	S t
 jtr< jj fdd|jjD  }|S t
 jtrt jdkrg }t jj}tt|D ]/}t
t|| tsj|| g jR   }	|t|d | |	g ||d d     qWt|}|S  j} jD ]
}
||
 }q|S )Nr   c                    s$   g | ]}j |g jR   qS r   )r7   r   _expand_partial_derivative)r&   ar   r!   r   r   
<listcomp>   s    z@PartialDerivative._expand_partial_derivative.<locals>.<listcomp>r+   )r   r   r   r7   r   r   r   free_symbolsr   Zeror   r
   r   r   r1   listr0   r   r   r:   r-   fromiter)r!   r   r   r   r   resulttermsmulargsinddvr   r<   r   r:      s@   



z,PartialDerivative._expand_partial_derivativec                 C   sD   | j }| jD ]}t|tr||}q|jr||}qtj}q|S r   )	r   r   r   r	   _eval_partial_derivative	_diff_wrt_eval_derivativer   r?   )r!   rB   rG   r   r   r   _perform_derivative   s   

z%PartialDerivative._perform_derivativec                 C   s   | j S r   )r   r    r   r   r   get_indices   s   zPartialDerivative.get_indicesc                 C   s    t | jdd d}dd |D S )Nc                 S   s   | d S Nr+   r   )xr   r   r   <lambda>   s    z4PartialDerivative.get_free_indices.<locals>.<lambda>)keyc                 S   s   g | ]}|d  qS )r   r   r&   r3   r   r   r   r=      r)   z6PartialDerivative.get_free_indices.<locals>.<listcomp>)sortedr   )r!   r   r   r   r   r,      s   z"PartialDerivative.get_free_indicesc                    sD   | j |}dd | D   fdd| jD }| j|g|R  S )Nc                 S   s   i | ]	\}}| | qS r   r   )r&   r'   rG   r   r   r   r(      s    z6PartialDerivative._replace_indices.<locals>.<dictcomp>c                    s   g | ]}|  qS r   )r.   rQ   mirroredr   r   r=      s    z6PartialDerivative._replace_indices.<locals>.<listcomp>)r   r.   itemsr   r7   )r!   replr   r   r   rS   r   _replace_indices   s   z"PartialDerivative._replace_indicesc                 C   s
   | j d S )Nr   r   r    r   r   r   r      s   
zPartialDerivative.exprc                 C   s   | j dd  S rM   rX   r    r   r   r   r      s   zPartialDerivative.variablesc                    sL  ddl m}m} | j|\}}| jD ]}||\}}dd |D }tdd |D  \}	}t|j}
|||}t|j}||
  t	| fddt
|
D tt
  }| }|d }dgdd t
t|D  }t|	D ]\}}||d< |t|  |  < qo| |v r|| }||d|d f}|| q|| q||fS )	Nr+   )derive_by_arraytensorcontractionc                 S   s   g | ]}| qS r   r   rQ   r   r   r   r=      s    z3PartialDerivative._extract_data.<locals>.<listcomp>c                 S   s   g | ]}|  qS r   )as_coeff_MulrQ   r   r   r   r=      r)   c                    s   g | ]}|  qS r   r   rQ   dim_increaser   r   r=      r)   r   c                 S   s   g | ]}t d qS r   )slicerQ   r   r   r   r=      r)   )arrayrY   rZ   r   _extract_datar   zipr1   shaper   r0   r@   
as_mutable	enumeratetupleindexpopr-   )r!   replacement_dictrY   rZ   r   r_   variablevar_indices	var_arraycoeff_array
dim_before	dim_aftervarindexcoeff_indexr3   r"   posr   r\   r   r`      s.   



(
zPartialDerivative._extract_dataN)__name__
__module____qualname____doc__r   propertyr"   r#   classmethodr   r9   r:   rK   rL   r,   rW   r   r   r`   r   r   r   r   r      s(    V



,

r   N)sympyr   sympy.core.numbersr   sympy.core.singletonr   sympy.core.symbolr   sympy.core.sympifyr   #sympy.tensor.array.dense_ndim_arrayr   sympy.tensor.tensorr   r	   r
   r   r   r   r   r   r   r   <module>   s    