a
    <b-                     @   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
mZ ddlmZmZ ddlmZmZmZ dd	lmZmZ dd
lmZmZmZ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' ddl(m)Z) ddl*m+Z+ G dd dZ,G dd de,Z-dd Z.e-dd dd Z/eddd gdZ0edd d gdZ1ed!Z2ed"Z3ed#d$d gdZ4e-ee3e3 ee3Z5e-ee4e3 e3 e4ee4e3  Z6e5e6fZ7e-e2ee3 ed% e2ee3 d&d d'Z8e-ed%ee3 ee3Z9e-d(d d)d Z:G d*d+ d+e-Z;e;e
eZ<e;ee%Z=e-d,d d-d Z>d.d d/d0d1Z?d2d3 Z@d4d5 ZAe-e@eAZBe-ee
e2e
e3 e"e2e3ZCe-ee d%e2e d%e3 e#e2e3ed% ZDe<e>e/e8e9fZEeEeCeDf e7 ZFe=fZGd6S )7a  
Classes and functions useful for rewriting expressions for optimized code
generation. Some languages (or standards thereof), e.g. C99, offer specialized
math functions for better performance and/or precision.

Using the ``optimize`` function in this module, together with a collection of
rules (represented as instances of ``Optimization``), one can rewrite the
expressions for this purpose::

    >>> from sympy import Symbol, exp, log
    >>> from sympy.codegen.rewriting import optimize, optims_c99
    >>> x = Symbol('x')
    >>> optimize(3*exp(2*x) - 3, optims_c99)
    3*expm1(2*x)
    >>> optimize(exp(2*x) - 1 - exp(-33), optims_c99)
    expm1(2*x) - exp(-33)
    >>> optimize(log(3*x + 3), optims_c99)
    log1p(x) + log(3)
    >>> optimize(log(2*x + 3), optims_c99)
    log(2*x + 3)

The ``optims_c99`` imported above is tuple containing the following instances
(which may be imported from ``sympy.codegen.rewriting``):

- ``expm1_opt``
- ``log1p_opt``
- ``exp2_opt``
- ``log2_opt``
- ``log2const_opt``


    )
expand_log)S)Wild)sign)explog)MaxMin)cossinsinc)Qask)log1plog2exp2expm1)MatrixSolve)UnevaluatedExpr)Pow)	logaddexp
logaddexp2)cosm1)Mul)MatrixSymbol)siftc                   @   s"   e Zd ZdZdddZdd ZdS )	Optimizationz Abstract base class for rewriting optimization.

    Subclasses should implement ``__call__`` taking an expression
    as argument.

    Parameters
    ==========
    cost_function : callable returning number
    priority : number

    N   c                 C   s   || _ || _d S N)cost_functionpriority)selfr   r     r"   g/Users/vegardjervell/Documents/master/model/venv/lib/python3.9/site-packages/sympy/codegen/rewriting.py__init__@   s    zOptimization.__init__c                 G   s   t || jdd S )N)keyr   )sortedr   )r!   argsr"   r"   r#   cheapestD   s    zOptimization.cheapest)Nr   )__name__
__module____qualname____doc__r$   r(   r"   r"   r"   r#   r   4   s   
r   c                       s(   e Zd ZdZ fddZdd Z  ZS )ReplaceOptima   Rewriting optimization calling replace on expressions.

    Explanation
    ===========

    The instance can be used as a function on expressions for which
    it will apply the ``replace`` method (see
    :meth:`sympy.core.basic.Basic.replace`).

    Parameters
    ==========

    query :
        First argument passed to replace.
    value :
        Second argument passed to replace.

    Examples
    ========

    >>> from sympy import Symbol
    >>> from sympy.codegen.rewriting import ReplaceOptim
    >>> from sympy.codegen.cfunctions import exp2
    >>> x = Symbol('x')
    >>> exp2_opt = ReplaceOptim(lambda p: p.is_Pow and p.base == 2,
    ...     lambda p: exp2(p.exp))
    >>> exp2_opt(2**x)
    exp2(x)

    c                    s"   t  jf i | || _|| _d S r   )superr$   queryvalue)r!   r/   r0   kwargs	__class__r"   r#   r$   h   s    zReplaceOptim.__init__c                 C   s   | | j| jS r   )replacer/   r0   )r!   exprr"   r"   r#   __call__m   s    zReplaceOptim.__call__)r)   r*   r+   r,   r$   r6   __classcell__r"   r"   r2   r#   r-   H   s   r-   c                 C   s@   t |dd ddD ](}|| }|jdu r.|} q|| |} q| S )a   Apply optimizations to an expression.

    Parameters
    ==========

    expr : expression
    optimizations : iterable of ``Optimization`` instances
        The optimizations will be sorted with respect to ``priority`` (highest first).

    Examples
    ========

    >>> from sympy import log, Symbol
    >>> from sympy.codegen.rewriting import optims_c99, optimize
    >>> x = Symbol('x')
    >>> optimize(log(x+3)/log(2) + log(x**2 + 1), optims_c99)
    log1p(x**2) + log2(x + 3)

    c                 S   s   | j S r   )r    )optr"   r"   r#   <lambda>       zoptimize.<locals>.<lambda>T)r%   reverseN)r&   r   r(   )r5   ZoptimizationsZoptimZnew_exprr"   r"   r#   optimizeq   s    
r<   c                 C   s   | j o| jdkS )N   )is_Powbasepr"   r"   r#   r9      r:   r9   c                 C   s
   t | jS r   )r   r   r@   r"   r"   r#   r9      r:   dc                 C   s   | j S r   )Zis_Dummyxr"   r"   r#   r9      r:   )Z
propertiesuc                 C   s   | j  o| j S r   )	is_numberis_AddrC   r"   r"   r#   r9      r:   vwnc                 C   s   | j S r   rF   rC   r"   r"   r#   r9      r:   r=   c                 C   s   |  dd S )Nc                 S   s*   | j r| jjp(t| ttfo(| jd j S )Nr   )r>   r   Zis_negative
isinstancer   r   r'   rF   er"   r"   r#   r9      s    <lambda>.<locals>.<lambda>)countr5   r"   r"   r#   r9      s   r   c                 C   sD   t | toB| jd joBt| jd jdkoBtdd | jd jD S )Nr   r=   c                 s   s   | ]}t |tV  qd S r   )rL   r   ).0tr"   r"   r#   	<genexpr>   r:   z<lambda>.<locals>.<genexpr>)rL   r   r'   rG   lenalllr"   r"   r#   r9      s
   

c                 C   s<   t dd | jd jD  tttdd | jd jD   S )Nc                 S   s   g | ]}|j d  qS r   r'   rS   rN   r"   r"   r#   
<listcomp>   r:   z<lambda>.<locals>.<listcomp>r   c                 S   s   g | ]}|j d  qS rZ   r[   r\   r"   r"   r#   r]      r:   )r   r'   r   r   r	   rX   r"   r"   r#   r9      s     c                       s>   e Zd ZdZd fdd	Zdd Zdd Z fd	d
Z  ZS )FuncMinusOneOptima  Specialization of ReplaceOptim for functions evaluating "f(x) - 1".

    Explanation
    ===========

    Numerical functions which go toward one as x go toward zero is often best
    implemented by a dedicated function in order to avoid catastrophic
    cancellation. One such example is ``expm1(x)`` in the C standard library
    which evaluates ``exp(x) - 1``. Such functions preserves many more
    significant digits when its argument is much smaller than one, compared
    to subtracting one afterwards.

    Parameters
    ==========

    func :
        The function which is subtracted by one.
    func_m_1 :
        The specialized function evaluating ``func(x) - 1``.
    opportunistic : bool
        When ``True``, apply the transformation as long as the magnitude of the
        remaining number terms decreases. When ``False``, only apply the
        transformation if it completely eliminates the number term.

    Examples
    ========

    >>> from sympy import symbols, exp
    >>> from sympy.codegen.rewriting import FuncMinusOneOptim
    >>> from sympy.codegen.cfunctions import expm1
    >>> x, y = symbols('x y')
    >>> expm1_opt = FuncMinusOneOptim(exp, expm1)
    >>> expm1_opt(exp(x) + 2*exp(5*y) - 3)
    expm1(x) + 2*expm1(5*y)


    Tc                    s<   dt  jdd | j fddd || _ | _|| _d S )N
   c                 S   s   | j S r   )rG   rM   r"   r"   r#   r9      r:   z,FuncMinusOneOptim.__init__.<locals>.<lambda>c                    s   |   |    S r   )Z	count_opsrP   rQ   func_m_1Zweightr"   r#   r9      r:   rR   )r.   r$   replace_in_Addfuncra   opportunistic)r!   rc   ra   rd   r2   r`   r#   r$      s    zFuncMinusOneOptim.__init__c                    sD   t |jdd dd\}}t|}t | fdddd\}}|||fS )Nc                 S   s   | j S r   rK   argr"   r"   r#   r9      r:   z4FuncMinusOneOptim._group_Add_terms.<locals>.<lambda>Tbinaryc                    s   |   jS r   )Zhasrc   re   r!   r"   r#   r9      r:   )r   r'   sum)r!   addZnumbersZnon_numnumsumterms_with_funcotherr"   ri   r#   _group_Add_terms   s    z"FuncMinusOneOptim._group_Add_termsc                    s:    |\}}}|dkr|S g g  }}|D ]}|jrt|j fdddd\}}	t|dkr|t|	dkr||d |	d  }}	qd}	n|j jkr|tj }}	nd}	|	dur|	jrt	|	t	| kr j
rt|	| t|k }
n|	| dk}
|
r||	7 }||	 j|j   q*|| q*|j|g|||R  S )z1 passed as second argument to Basic.replace(...) r   c                    s   | j  j kS r   )rc   re   ri   r"   r#   r9      r:   z2FuncMinusOneOptim.replace_in_Add.<locals>.<lambda>Trg   r   N)ro   Zis_Mulr   r'   rV   rc   r   ZOnerF   r   rd   absappendra   )r!   rN   rl   rm   Zother_non_num_termsZsubstitutedZ	untouchedZ	with_funcrc   ZcoeffZdo_substituter"   ri   r#   rb      s.    
&z FuncMinusOneOptim.replace_in_Addc                    s(   t  |}t  | }| ||S r   )r.   r6   factorr(   )r!   r5   Zalt1Zalt2r2   r"   r#   r6     s    zFuncMinusOneOptim.__call__)T)	r)   r*   r+   r,   r$   ro   rb   r6   r7   r"   r"   r2   r#   r^      s
   & r^   c                 C   s
   t | tS r   )rL   r   rM   r"   r"   r#   r9     r:   c                 C   s(   t | tdd ttd ttS )Nc                 S   s   t |  S r   )r   rr   re   r"   r"   r#   r9     r:   rO   r   )r   r4   r   _ur   rX   r"   r"   r#   r9     s   c                 C   s   | j S r   )Z	is_symbol)br"   r"   r#   r9     r:   )base_reqc                   s   t  fdddd S )a   Creates an instance of :class:`ReplaceOptim` for expanding ``Pow``.

    Explanation
    ===========

    The requirements for expansions are that the base needs to be a symbol
    and the exponent needs to be an Integer (and be less than or equal to
    ``limit``).

    Parameters
    ==========

    limit : int
         The highest power which is expanded into multiplication.
    base_req : function returning bool
         Requirement on base for expansion to happen, default is to return
         the ``is_symbol`` attribute of the base.

    Examples
    ========

    >>> from sympy import Symbol, sin
    >>> from sympy.codegen.rewriting import create_expand_pow_optimization
    >>> x = Symbol('x')
    >>> expand_opt = create_expand_pow_optimization(3)
    >>> expand_opt(x**5 + x**3)
    x**5 + x*x*x
    >>> expand_opt(x**5 + x**3 + sin(x)**3)
    x**5 + sin(x)**3 + x*x*x
    >>> opt2 = create_expand_pow_optimization(3, base_req=lambda b: not b.is_Function)
    >>> opt2((x+1)**2 + sin(x)**2)
    sin(x)**2 + (x + 1)*(x + 1)

    c                    s&   | j o$ | jo$| jjo$t| jkS r   )r>   r?   r   Z
is_Integerrp   rM   ru   limitr"   r#   r9   A  r:   z0create_expand_pow_optimization.<locals>.<lambda>c                 S   sJ   | j dkr(tt| jg| j 
  ddiS dtt| jg| j   ddi S )Nr   evaluateFr   )r   r   r   r?   r@   r"   r"   r#   r9   B  s    ()r-   )rw   ru   r"   rv   r#   create_expand_pow_optimization  s    #ry   c                 C   sZ   | j rVt| jdkrV| j\}}|jrV|jd dkrV|j}t|trVtt	t
|jS dS )Nr=   r   F)Z	is_MatMulrV   r'   Z
is_Inverseshaperf   rL   r   boolr   r   Zfullrankr5   leftrightZinv_argr"   r"   r#   _matinv_predicateH  s    

r   c                 C   s   | j \}}|j}t||S r   )r'   rf   r   r|   r"   r"   r#   _matinv_transformS  s    
r   N)Hr,   Zsympy.core.functionr   Zsympy.core.singletonr   Zsympy.core.symbolr   Z$sympy.functions.elementary.complexesr   Z&sympy.functions.elementary.exponentialr   r   Z(sympy.functions.elementary.miscellaneousr   r	   Z(sympy.functions.elementary.trigonometricr
   r   r   Zsympy.assumptionsr   r   Zsympy.codegen.cfunctionsr   r   r   r   Zsympy.codegen.matrix_nodesr   Zsympy.core.exprr   Zsympy.core.powerr   Zsympy.codegen.numpy_nodesr   r   Zsympy.codegen.scipy_nodesr   Zsympy.core.mulr   Z"sympy.matrices.expressions.matexprr   Zsympy.utilities.iterablesr   r   r-   r<   Zexp2_optZ_drs   Z_v_wZ_nZ	sinc_opt1Z	sinc_opt2Z	sinc_optsZlog2_optZlog2const_optZlogsumexp_2terms_optr^   Z	expm1_optZ	cosm1_optZ	log1p_optry   r   r   Z
matinv_optZlogaddexp_optZlogaddexp2_optZ
optims_c99Zoptims_numpyZoptims_scipyr"   r"   r"   r#   <module>   st    )*[

+
 ,